JAVA中事务的并发机制

第一节:事务的并发处理ACID

Atomicity   原子性

Consistency 一致性

Isolation  隔离性

Durability 持久性

第二节:事务并发可能出现的问题

2.1第一类丢失更新(Lost Update)

说明:事务B的更新丢失。撤销一个事务影响到另外一个事务

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额1000元

 

T4

 

查询账户余额1000元

T5

 

汇入100元把余额改成1100元

T5

 

提交事务

T7

取出100把余额变成900

 

T8

撤销事务

 

T9

余额恢复1000(丢失更新)

 

 

2.2脏读(ditrty read)

说明:读到了别的事务还提交的事务,此时B事务还未提交,中间的事务可能回滚,所以读到数据可能不对。

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

 

 

T4

 

查询账户余额1000元

T5

 

汇入100元把余额改成1100元

T5

查询账户余额1100元

(读取的脏数据)

 

T7

 

回滚

T8

取款1100元

 

T9

提交事务失败

 

 

2.3不可重复读(non-repeatable read)

当前事务已经读取的数据记录,被其他事务修改或删除

说明:同一个事务中读取两遍的值不一致,此时无法确定按哪个值来处理。

时间

取款事务A

存款事务B

T1

开始事务

 

T2

查询账户余额1000元

 

T3

 

开始事务

T4

 

汇入100元账户余额改为1100元

T5

 

提交事务

T5

查询账户余额1100元

 

T7

 

 

T8

提交事务

 

 

 

2.4第二类丢失更新(second lost update)

说明:不可重复读的特殊情况,本来A事务在提交之前应该再次读一遍数据,读取的数据还是和第一次是不一致的。

时间

取款事务A

存款事务B

T1

 

开始事务

T2

开始事务

 

T3

 

查询账户余额1000元

T4

查询账户余额1000元

 

T5

 

取款100元把余额改成900元

T5

 

提交事务

T7

汇入100元

 

T8

提交事务

 

T9

余额改成1100元

 

 

 

2.5幻读(phantom read)

说明:此时两次机查询的数据不一致,同不可重复读,两次查询出来的数据不一致。幻读为插入和删除的操作,以上为更新的操作。

其他事务插入了新的数据,当前事务以相同的查询条件,在那个事务插入数据之前和之后查询数据,得到的数据记录的条数不一样。

时间

查询学生事务A

查询学生事务B

T1

开始事务

 

T2

 

开始事务

T3

查询学生为10人

 

T4

 

插入1个学校

T5

查询学生为11人

 

T5

 

提交事务

T7

提交事务

 

 

 

第三节:JDBC事务隔离级别

(1):TRNSACTION_NONE:不支持事务

(2):TRNSACTION_READ_COMMITTED:防止脏读和幻读,但是不能限制不可重复读,因为不可重复读是读取已经提交的事务,幻读类似

(3):TRNSACTION_READ_UNCOMMITTED:允许脏读,幻读,不可重复读

(4):TRNSACTION_REPEATABLE_READ(可重复读):MYSQL默认设置级别,即把这条数据读取出来以后加把锁,其他事务不能更新这条数据的值,等我这个事务处理完成后其他事务才能对该条数据做更新,select xxx rom xxxtable where xxx for update,数据库为其读取的这条记录加把锁,这条事务没提交之前,其他事务就不能更新这条记录

(5):TRNSACTION_SERIALIZABLE:无论多少事务来都不并发,一个一个执行

 

第四节:悲观锁和乐观锁

4.1悲观锁和乐观锁说明

利用悲观锁和乐观锁解决不可重复读(non-repeatable read)问题设成READ_COMMITTED通过hibernate实现。

悲观锁:通过数据库加锁(for update)

乐观锁:1:事务取出数据库中一条记录的时候为其设置一个version号

2:如果有事务更新了这条数据version版本号自动加一

3:事务把数据更改后检查版本号是否是刚取出来的那个version,如果不一样事务    回滚,否则会冲掉人家修改后的数据。

4.2 Hiernate悲观锁和乐观锁实例

Session session1 = sf.openSession();

Session session2 = sf.openSession();

session1.beginTransaction();

Account a1 = (Account )session1.load(Account .class,1); //把数据库记录load出来

 

session2.beginTransaction();

Account a2 = (Account )session2.load(Account .class,1);

a1.setBalance(100);

a2.setBalance(300);

 

session1.getTransaction.commit();

session2.getTransaction.commit();

posted on 2015-03-25 11:11  xiongqi_wentian  阅读(3028)  评论(0编辑  收藏  举报