最近在学习事务管理方面的知识,看了江南白衣推荐的一本书《Java Transaction Design Strategies》
http://www.infoq.com/minibooks/JTDS之后,写点自己对事务的认知。
(一)java事务管理策略如下:
1、本地事务。
2、编程式事务
3、声明式事务
1、本地事务:
用jdbc进行的connection事务管理。用书中作者的话就是管理的是connection,不是事务。事务交由dbms管理。
2、编程式事务:
编程式获取UserTransaction,然后UserTransaction.bigin(),UserTransaction.commit(),UserTransaction.roback()对事务进行管理。
3、声明式事务:
与2相比,就是不用硬编码,只需要告诉容器什么时候开启事务,开启什么样的事务,什么时候提交事务,什么时候回滚事务。(注意:在EJB中发生检查异常(checked exception)时,如果需要回滚事务,需要调用sessionCtx.setRollbackOnly();标识一下该事务需要回滚,容器则根据该标识进行事务的回滚,如果无该标识,则容器不进行回滚。)
(二)事务的容器管理级别
1、required
2、mandatory
3、requiresdNew
4、supports
5、Notsupports
6、never
在spring中对应如下:
1、required对应PROPAGATION_REQUIRED:告诉容器调用到指定方法时需要一个事务,如果事务存在,则使用已存在事务,如果事务不存在,则新建一个事务。
2、mandator对应PROPAGATION_MANDATOR:告诉容器调用到指定方法时需要一个事务,但不会新建事务。如果事务不存在,则抛出异常。
3、requiresdNew对应PROPAGATION_REQUIRES_NEW:告诉容器调用到指定方法时需要一个新事务,新事务创建时(称事务2),将旧事务挂起,直至新事务提交或回滚。此时之前已经存在的事务(称事务1)则继续执行,当事务1发生异常时,事务1回滚,事务2不受影响。(该级别对于无论操作是否成功,都已经记录某些动作(如操作记录),的行为很有效)。
4、supports对应PROPAGATION_SUPPORTS:告诉容器调用到指定方法时不需要一个事务。但如果事务已经存在,则加入该事务。(这对查询操作很有用,查询不需要事务,但如果存在事务,事务可能对查询的数据进行update,此时查询可取到事务控制中的最新查询数据)。
5、Notsupports对应PROPAGATION_NOT_SUPPORTED告诉容器调用到指定方法时不需要一个事务。如果事务已经存在,则挂起改事务,等方法执行完毕后再恢复挂起的事务。
6、never对应PROPAGATION_NEVER。告诉容器调用到指定方式时不需要一个事务。如果已经存在事务,则抛出不允许事务的异常。(没必要时建议不要用,很多时候可以用Notsupports代替)。
(三)ejb和spring都支持的事务隔离级别如下:
(说明:事务隔离级别是否有效需要数据库管理系统的支持)
1、TransactionReadUncommitted
2、TransactionReadCommitted
3、TransactionRepeatableRead
4、TransactionSerializable
1、TransactionReadUncommitted:脏读。最低级别的事务隔离级别,允许读取未提交的数据。假如存在事务A和事务B,同时对数据库中的某字段进行如下操作:
则事务A在t2对字段进行了修改,而事务则可在t3读取到修改后的字段值。这种事务隔离级别存在一个问题,即如果事务A在t4进行的是rollback而不是commit的话,则事务B读取到的数据则为脏数据。这种事务隔离级别很多数据库都不支持,包括oracle在内。
2、TransactionReadCommitted:不可重复读。该隔离级别只能读取到事务前或事务后的数据。以上面例子为例:
事务B读取到的是事务A之前和事务A之后的数据(在同一个事务中,会产生前后两次读取的数据不一致),该级别被认为是一个比较好的隔离级别。很多数据库都默认为该级别,如sql servier和oracle。
3、TransactionRepeatableRead:幻读。该隔离级别在一个事务中读取到的数据是一致的,不因为中间数据是否已经修改而重新读取新数据。如下图:
这时读取到的数据不是新数据。就好比事务A并没有对数据进行过修改一样,所以称之为幻读。Mysql默认为该级别。oracle不支持该事务隔离级别。
4、TransactionSerializable:序列执行事务,完全遵循ACID原则,属于最高事务隔离级别,但java对这个隔离级别的支持最低(This is the lowest level of isolatin supported by Java.),如下图:
事务B将被挂起,直至事务A结束。不能并发处理事务。
对于上诉4种隔离级别,需要数据库管理系统的支持才有效,如果数据库系统不支持,则设置的隔离级别是无效的,而采用的是数据库系统的默认隔离级别(但此时系统是不抛出异常的,所以你或许认为你的隔离级别是有效的,但事实上起效果的是默认隔离级别,因此,了解dbms支持的事务隔离级别是很有必要的。)。