事务并发时可能出现的问题及解决方法

1.脏读(读到了另一个事务在处理中还未提交的数据)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

 

查询账户余额为1000元

T4

 

汇入100元把余额改为1100元

T5

查询账户余额为1100元(读取脏数据)

 

T6

 

回滚

T7

取款1100

 

T8

提交事务失败

 

 2.不可重复读(在同一个事务中对同一个数据前后读两次的值是不一样的)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元

 

T5

 

汇入100元把余额改为1100元

T5

 

提交事务

T6

查询帐户余额为1100元

 

T8

提交事务

 

 3.幻读(说的是插入和更新的问题,在你读的过程中,另外一个事务可能往里面插入了一条新数据,影响了读取的结果)

时间

查询学生事务A

插入新学生事务B

T1

开始事务

 

T2

 

开始事务

T3

查询学生为10人

 

T4

 

插入1个学生

T5

查询学生为11人

 

T6

 

提交事务

T7

提交事务

 

 解决方法:

 数据库的事务隔离机制

  i. 查看 java.sql.Connection 文档

  ii. 1:read-uncommitted  2:read-committed  4:repeatable read  8:serializable(数字代表对应值)

  为什么取值要使用 1 2 4 8 而不是 1 2 3 4

  1=0000  2=0010 4=0100 8=1000(位移计算效率高)

  1. 只要数据库支持事务,就不可能出现第一类丢失更新
  2. read-uncommitted(允许读取未提交的数据) 会出现dirty read, phantom-read,non-repeatable read 问题
  3. read-commited(读取已提交的数据 项目中一般都使用这个)不会出现dirty read,因为只有另一个事务提交才会读出来结果,但仍然会出现 non-repeatable read 和 phantom-read。使用read-commited机制可用悲观锁 乐观锁来解决non-repeatable read 和 phantom-read问题
  4. repeatable read(事务执行中其他事务无法执行修改或插入操作     较安全)
  5. serializable解决一切问题(顺序执行事务 不并发,实际中很少用)

设定hibernate的事务隔离级别(使用hibernate.connection.isolation配置 取值1、2、4、8)

i.hibernate.connection.isolation = 2(如果不设 默认依赖数据库本身的级别)

ii.用悲观锁解决repeatable read的问题(依赖于数据库的锁

  1. select ... for update
  2. 使用另一种load方法--load(xx.class , i , LockMode.Upgrade)

  a)     LockMode.None无锁的机制,Transaction结束时,切换到此模式

  b)     LockMode.read在査询的时候hibernate会自动获取锁

  c)     LockMode.write insert  update hibernate 会自动获取锁

  d)     以上3种锁的模式,是hibernate内部使用的(不需要设)

  e)     LockMode.UPGRADE_NOWAIT是 ORACLE 支持的锁的方式

Hibernate(JPA)乐观锁定(ReadCommitted)

实体类中增加version属性(数据库也会对应生成该字段,初始值为0),并在其get方法前加

@Version注解,则在操作过程中没更新一次该行数据则version值加1,即可在事务提交前判断该数据是否被其他事务修改过.

posted on 2013-09-13 20:36  凯特的宝贝世界  阅读(2573)  评论(0编辑  收藏  举报