用 Java 谈论事物--事务
首先说下什么是事物(数据库):
事物是数据库中一些列的连续的逻辑操作,事物具有ACID特性。(ACID:原子性、一致性、隔离性、持久性)
在处理日常数据时会出现的三类问题:脏读、不可重复读、幻读。
脏读 | 一个事物读取了另一个事物中未提交的数据。 |
---|---|
不可重复读 | 一个事物内读取表中某一行数据,多次读取结果不同。(更新操作) |
幻读 | 一个事物内读取到了别的事物插入的数据,导致前后不一致。(新增、删除操作) |
在数据库中可以设置不同的隔离级别解决上述问题,即:Read uncommitted 、Read committed 、Repeatable read 、Serializable(隔离级别低-->高)
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
- Read uncommitted 未提交读,会造成读取其它事物中未提交的事物(造成脏读)。
- Read committed 提交读,会造成不可重复读,事物提交但是存在update操作。
- Repeatable read 可重复读,可能会出现幻读。
- Serializable 序列化,可避免以上的所有问题(性能低)。
Oracle:默认系统事务隔离级别是READ-COMMITTED。
Mysql:默认的事务处理级别是REPEATABLE-READ。
SQL Server:默认系统事务隔离级别是READ-COMMITTED。
Spring 事务管理
Spring中的事物是通过TransactionDefiniton 接口定义的
该接口包含了与事物相关的属性和方法
public interface TransactionDefinition{
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int getIsolationLevel();
int getPropagationBehavior();
int getTimeout();
boolean isReadOnly();
}
TransactionDefinition接口中定义了五种表示隔离级别的常量
ISOLATION_DEFAULT(默认) | 底层数据库的默认隔离级别。
对大部分数据库而言, 常量值是 TransactionDefinition.ISOLATION_READ_COMMITTED |
---|---|
ISOLATION_READ_UNCOMMITTED | 该隔离级别表示一个事物可以读取另一个事物中修改但是还没有提交的数据。 该隔离级别不能防止脏读和不可重复读。(很少使用) |
ISOLATION_READ_COMMITTED | 该隔离表示一个事物可以读取另一个事物中已经提交的数据。 该隔离级别可以防止脏读。(推荐) |
ISOLATION_REPEATABLE_READ | 所有事物一次逐个执行,这样事物之间就完全不可能产生干扰。 该隔离级别可以防止脏读、不可重复读和幻读。(不推荐,影响性能) |
事物超时:一个事物所允许的最长时间。如果在超过此时间,事物还未完成,则自动回滚。
事物只读属性:对事物性资源进行只读操作或读写操作。如果是只读性质的事物,可标记为只读,以增强事物的处理能力。
事物的回滚规则:事物中抛出未检查的异常(RuntimeException),则默认将回滚事务。
事物管理主要分为两大类:
(一)、编程式事物管理。
基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务管理是 Spring 提供的最原始的方式。
基于 TransactionTemplate 的编程式事务管理是对上一种方式的封装,使得编码更简单、清晰。
例:Hibernate中,我们需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法。
(二)、声明式事物管理。
基于 TransactionInterceptor 的声明式事务是 Spring 声明式事务的基础。
基于 TransactionProxyFactoryBean 的声明式事务。( Spring 2.0 中已不推荐)
基于 和 命名空间的声明式事务管理(推荐),与 Spring AOP 结合紧密,使得管理事务更加灵活。
例:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="bulk*" propagation="REQUIRED" isolation="DEFAULT" />
<tx:method name="load*" propagation="REQUIRED" isolation="DEFAULT" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(**.services(..))" advice-ref="txAdvice" />
</aop:config>
或
<aop:config>
<aop:pointcut id="allServiceMethods"
expression="execution(**.services(..))"/>
<aop:advisor advice-ref="defaultTransactionAdvice"
pointcut-ref="allServiceMethods"/>
</aop:config>
<tx:advice id="defaultTransactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method
name="*"
isolation="DEFAULT"
propagation="REQUIRED"
rollback-for="java.lang.RuntimeException"
timeout="100"/>
<tx:method
name="get*"
read-only="true"/>
</tx:attributes>
</tx:advice>
基于 @Transactional 的方式将声明式事务管理
注:
作用于接口、接口方法、类、类中的方法。不推荐在接口中使用该注解,因为只有基于接口的代理时才会生效。
只可以用在public方法上,在protected、private使用时,会被忽略。
无法重用,只能作用于单个类或方法上,需逐个制定。
如个人理解有偏差:还请指正。
参考:https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/