spring事务总结
一、Spring事务管理
1、事务的基本原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
1) 获取连接:
Connectioncon = DriverManager.getConnection();
2) 开启事务:con.setAutoCommit(true/false);
3) 执行CRUD
4) 提交事务/回滚事务con.commit() /con.rollback();
5) 关闭连接conn.close();
使用Spring的事务管理 功能后,可以不再写步骤 2 和 4 的代码,而是由Spirng自动完成。
2、核心接口
1)PlatformTransactionManager是spring事务抽象架构的核心接口,他的主要作用在于为应用程序提供事务界定的统一方式。它就好象我们的战略蓝图,而战略的具体实施则将由相应的PlatformTransactionManager实现类来执行。
public interface PlatformTransactionManager {
// 获得事务状态
TransactionStatus getTransaction(TransactionDefinition definition)throws TransactionException;
// 提交事务
void commit(TransactionStatus status)throws TransactionException;
// 回滚事务
void rollback(TransactionStatus status)throws TransactionException;
}
2) TransactionDefinition 结合PlatformTransactionManager实现类开启事务并获取事务的属性。
3) TransactionStatus:控制事务由开始到结束间的状态
AbstractPlatformTransactionManager实现了PlatformTransactionManager接口,提供基本的事务管理流程,在关键代码段则采用模板模式(事务管理器)由具体的子类实现操作逻辑。
protected Object doGetTransaction();
protected boolean isExistingTransaction(Object transaction);
protected void doBegin(Object transaction, TransactionDefinition definition); protected Object doSuspend(Object transaction);
protected void doResume(Object transaction, ObjectsuspendedResources);
protected void prepareForCommit(DefaultTransactionStatus status);
protected void doCommit(DefaultTransactionStatus status);
protected void doRollback(DefaultTransactionStatus status);
protected void doSetRollbackOnly(DefaultTransactionStatus status);
protected void doCleanupAfterCompletion(Object transaction);
3、事务的四个特性:ACID
· 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
· 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不会被破坏。
· 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,互不干扰,防止数据损坏。
· 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
4、事务的基本属性
5、隔离级别(ISOLATION)
隔离级别定义了一个事务可能受其他并发事务影响的程度
(1)并发事务引起的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致一下的问题:
· 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
· 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
· 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
(乐观锁和悲观锁)
Spring五大隔离级别(ISOLATION):
1)ISOLATION_DEFAULT
使用后端数据库默认的隔离级别。
2)ISOLATION_READ_UNCOMMITTED
最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
3)ISOLATION_READ_COMMITTED
允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
4)ISOLATION_REPEATABLE_READ
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
5)ISOLATION_SERIALIZABLE
最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的。
6、传播行为(PROPAGATION)
事务的第一个方面是传播行为(propagation behavior)。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
Spring七大传播行为(PROPAGATION):
1)PROPAGATION_REQUIRED
支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring默认的事务的传播。
2)PROPAGATION_REQUIRED_NEW
新建事务,如果当前存在事务,把当前事务挂起。
3)PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
4)PROPAGATION_MANDATORY
支持当前事务,如果当前没有事务,就抛出异常。
5)PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6)PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
7)PROPAGATION_NESTED
他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,
而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。
7、只读(readOnly)
read-only="true/false"
事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。
如果值为true就会告诉Spring我这个方法里面没有insert或者update,你只需要提供只读的数据库Connection就行了,这种执行效率会比read-write的Connection高,所以这是一个最优化提示。
8、事务超时(timeout)
为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
9、回滚规则(rollback)
rollback-for="Exception"
回滚规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚, 但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
二、编程式事务和声明式事务
1、编程式事务(代码侵入,不推荐):
编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager(太过‘底层’)。对于编程式事务管理,spring推荐使用TransactionTemplate(对PlatformTransactionManager的封装)。
PlatformTransactionManager示例:
JdbcTemplate template = new JdbcTemplate(datasource);
DataSourceTransactionManager tran = new DataSourceTransactionManager(datasource);
//事务定义类
DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//返回事务对象
TransactionStatus status = tran.getTransaction(def);
try {
template.update("Insert into user(name,password) values('abc','123')");
template.update("Insert into user(name,password) values('def','456')");
tran.commit(status);
} catch (Exception ex) {
tran.rollback(status);
}
TransactionTemplate示例:
final JdbcTemplate template = new JdbcTemplate(datasource);
DataSourceTransactionManager tran = new DataSourceTransactionManager(datasource);
TransactionTemplate trantemplate = new TransactionTemplate(tran);
trantemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
int i = 0;
try {
template.update("Insert into user(name,password) values('jjj','kkk')");
template.update("Insert into user(name,password) values('llll','mmm')");
i = 1;
} catch (Exception ex) {
ex.printStackTrace();
status.setRollbackOnly();
i = 0;
}
return new Integer(i);
}
2、声明式事务
声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
3、事务配置
不推荐
* TransactionInterceptor
* TransactionProxyFactoryBean
3.1:基于XML的事务管理(在配置文件中做相关的事务规则声明)
(Spring tx入口:TxAdviceBeanDefinitionParser)
<!-- 定义事务处理类,不同的数据访问方式,事务处理类不同,比如:Hibernate操作的
HibernateTransactionManager,JDBC操作的使用DataSourceTransactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 定义事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 定义方法的过滤规则 -->
<tx:attributes>
<!-- 所有方法都使用事务 -->
<tx:method name="*" propagation="REQUIRED"/>
<!-- 定义所有get开头的方法都是只读的 -->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 定义AOP配置 -->
<aop:config>
<!-- 定义一个切入点 -->
<aop:pointcut expression="execution (* com.iflysse.school.services.impl.*.*(..))" id="services"/>
<!-- 对切入点和事务的通知,进行适配 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="services"/> </aop:config>
3.2:基于@Transactional的事务管理(更简单易用,更清爽,但业务逻辑较多,较复杂......)
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 声明使用注解式事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>