• Java实战之02Hibernate06处理并发


    十三、处理并发

    1、事务的隔离级别

    不考虑隔离级别出现的问题:

    脏读:一个线程中的事务读到了另外一个线程中未提交的数据。

    不可重复读:一个线程中的事务读到了另外一个线程中提交的update(更新)的数据。

    虚读:一个线程中的事务读到了另外一个线程中提交的insert(插入)的数据。

    事务的隔离级别:

    1READ UNCOMMITTED:脏读、不可重复读、虚读(幻读)都可能发生。

    2READ COMMITTED:避免脏读;不可重复读、虚读(幻读)都可能发生。

    4REPEATABLE READ:避免脏读、不可重复读,虚读(幻读)可能发生。

    8SERIALIZABLE:避免脏读、不可重复读、虚读(幻读)。

    通过配置参数hibernate.connection.isolation=1|2|4|8进行设置。MySQL:默认4  Oracle:默认2

    2、第二类更新丢失

     1 //线程1
     2     @Test
     3     public void test1(){
     4         Session s = HibernateUtil.getSession();
     5         Transaction tx = s.beginTransaction();
     7         Customer c1 = s.get(Customer.class, 1);
     8         c1.setName("泰斯特");
     9         tx.commit();
    10         s.close();
    11     }
    12     
    13     //线程2
    14     @Test
    15     public void test2(){
    16         Session s = HibernateUtil.getSession();
    17         Transaction tx = s.beginTransaction();
    19         Customer c1 = s.get(Customer.class, 1);
    20         c1.setAge(20);
    21         tx.commit();
    22         s.close();
    23     }

    3、解决丢失更新的方案

    3.1、悲观锁(不是锁,是一种处理态度。是hibernate的)

    Hibernate认为丢失更新现象一定会发生。悲观锁用的是数据库的锁机制。(独占模式效率肯定不会高)

    数据库的锁机制:(是真正的锁)

    共享锁:可以有多把锁。

    MySQL客户端线程1

    MySQL客户端线程2

    开启事务 strat transaction;

    开启事务 strat transaction;

    执行查询:select * from customes where id = 1 lock in share mode; 加共享锁

    执行查询:select * from customes where id = 1 lock in share mode; 加共享锁

    执行更新:update customers set name='张三' where id = 1;

    此时会自动加排他锁。但是由于线程2没有释放共享锁,所以线程1处于等待状态。

    commit;

    当线程2释放共享锁,线程1就可以执行成功了。

    排他锁(独占模式,也称为独占锁):只能有一把锁,在锁之前,不能有任何的锁。执行写操作(insert,update,delete)的时候会自动加锁。

    MySQL客户端线程1

    MySQL客户端线程2

    开启事务 strat transaction;

    开启事务 strat transaction;

    执行查询:select * from customes where id = 1 for update; 加排他锁

    执行查询:select * from customes where id = 1 lock in share mode ; 由于有线程1的排他锁存在,线程2将处于等待状态

    执行更新:update customers set age = 50 where id = 1;

    此时还没有释放排他锁

    提交事务(释放排他锁) commit;

    线程2显示查询结果,已经是线程1改过之后的数据了。

    死锁:DEADLOCK

    MySQL客户端线程1

    MySQL客户端线程2

    开启事务 strat transaction;

    开启事务 strat transaction;

    执行查询:select * from customes where id = 1 lock in share mode; 加共享锁

    执行查询:select * from customes where id = 1 lock in share mode; 加共享锁

    执行更新:update customers set name='张三' where id = 1;

    此时会自动加排他锁。但是由于线程2没有释放共享锁,所以线程1处于等待状态。

    执行更新:update customers set age=18 where id = 1;

    此时会自动加排他锁。但是由于线程1没有释放共享锁,所以线程2处于等待状态。

    结果:线程1等着线程2释放共享锁,而线程2等着线程1释放排他锁。就造成了死锁。

     1 //线程1
     2     @Test
     3     public void test1(){
     4         Session s = HibernateUtil.getSession();
     5         Transaction tx = s.beginTransaction();
     6         Customer c1 = s.get(Customer.class, 1,LockMode.PESSIMISTIC_WRITE);//hibernate处理丢失更新的悲观锁解决方式
     7         //Customer c1 = s.get(Customer.class, 1);
     8         c1.setName("泰斯特");
     9         tx.commit();
    10         s.close();
    11     }
    12     
    13     //线程2
    14     @Test
    15     public void test2(){
    16         Session s = HibernateUtil.getSession();
    17         Transaction tx = s.beginTransaction();
    18         Customer c1 = s.get(Customer.class, 1,LockMode.PESSIMISTIC_WRITE);
    19         //Customer c1 = s.get(Customer.class, 1);
    20         c1.setAge(20);
    21         tx.commit();
    22         s.close();
    23     }

    3.2、乐观锁(不是锁,是一种处理态度)

    Hibernate认为丢失更新现象不一定会发生。乐观锁使用的是版本号机制。

     1     private Integer id;
     2     private String name;
     3     private Integer age;
     4     //================版本号==================
     5     private Integer version;
     6     //=======================================
     7     //一对多关系映射:一个客户可以有多个订单
     8     private Set<Order> orders = new HashSet<Order>(0);
     9     
    10     public Customer(){
    11         
    12     }
     1      <class name="Customer" table="T_CUSTOMERS">
     2         <id name="id" column="id">
     3             <generator class="native"></generator>
     4         </id>
     5         <!-- 版本字段,用于解决丢失更新 -->
     6         <version name="version"></version>
     7         
     8         <property name="name" column="NAME"></property>
     9         <property name="age" column="AGE"></property>
    10         <!-- 一对多关系映射: 
    11             set元素:
    12                 作用:映射集合元素
    13                 属性:
    14                     name:映射实体类中的集合属性
    15                     table:指定对应的表
    16             key元素:它是set的子元素
    17                 作用:就是用于指定外键的
    18                 属性:
    19                     column:指定外键字段的名称
    20             one-to-many元素:它是set的子元素
    21                 作用:描述当前实体映射文件和set中指定属性之间的关系。
    22                 属性:
    23                     class:指定是从表的实体类名称        
    24         -->
    25         <set name="orders" table="T_ORDERS" >
    26             <key column="CUSTOMER_ID"></key>
    27             <one-to-many class="Order"/>
    28         </set>
    29     </class>
  • 相关阅读:
    ansible for devops 读书笔记第二章Ad-Hoc Commands
    ansible for devops读书笔记第一章
    python3 获取天气
    简单cpu web flask mysql
    mysql mysqldump只导出表结构或只导出数据的实现方法
    nginx 限制solr
    [Selenium] 如何使 InternetExplorerDriver 每次启动的端口不会随机变化
    [Selenium] 如何绕过 IE 的安全模式
    [Selenium] close alert window
    [Selenium] waitUntilAllAjaxRequestCompletes
  • 原文地址:https://www.cnblogs.com/minihouseCoder/p/5611153.html
Copyright © 2020-2023  润新知