Java实战之02Hibernate-06处理并发

十三、处理并发

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>
posted @ 2016-06-23 16:00  铭昊Coder  阅读(405)  评论(0编辑  收藏  举报