事务概念
事务的四个特性(ACID)
一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该造成其丢失。
Spring中的事务管理
Spring的事务管理方式有两种:编程式的事务管理和声明式的事务管理。事实上,不论你采用哪一种方式来进行事务管理,都需要先声明事务管理器(TransactionManager)。
Spring集成了很多内置的事务管理器,最常用两种便是DataSourceTransactionManager和HibernateTransactionManager:
DataSourceTransactionManager:用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理;
HibernateTransactionManager:用于集成Hibernate框架时的事务管理.
编程式事务
1.配置事务管理器(以JdbcDataSource为例)
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2.配置事务管理模板
<bean id = "transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- service层注入transactionTemplate -->
<bean id = "accountService" class="com.cfx.service.impl.AccountServiceImpl">
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
3.在Service中注入模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public void transfer(String out, String in, Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult(){
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.outMoney(out, money);
int i = 1/0;//若不进行事务管理,出现错误,outMoney()将会执行。
accountDao.inMoney(in, money);
}
});
}
声明式事务
1.基于AspectJ的方式
配置事务管理器..
<tx:advice id="accountAdvice" transaction-manager="transactionManager">
<!--配置事务传播性,隔离级别以及超时回滚等问题 -->
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--配置切点 与切面-->
<aop:pointcut id="services" expression="execution(* com.cfx.service.*.*(..))" />
<aop:advisor pointcut-ref="services" advice-ref="accountAdvice" />
</aop:config>
因为采用切面的方式,所以其他位置将不需要改变。2.基于注解式配置
这种配置方式最为简洁。
<tx:annotation-driven transaction-manager="transactionManager"/>
之后在需要事务管理的类或者方法上加上@Transactional注解即可,可以相应的传播行为,隔离级别等等。(注意方法的事务管理一定要是public访问修饰符作用才行)
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT)
ok,下面将分享关于配置事务属性的知识(参考于https://www.cnblogs.com/longshiyVip/p/5061637.html):
声明式事务通过传播行为,隔离级别,只读提示,事务超时及回滚规则来进行定义。Spring事务的传播行为:
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务的传播行为可以由传播属性指定。Spring定义了7种传播行为:
传播行为 | 含义 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务 |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 |
其中PROPAGATION_REQUIRED为默认的传播属性
Spring事务的隔离级别
隔离级别定义了一个事务可能受其他并发事务影响的程度。在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发,虽然是必须的,可是会导致下面的问题。
并发事务所导致的问题可以分为以下三类:
① 脏读(Dirty reads):脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
② 不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间更新了数据
③ 幻读(Phantom read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录
Spring事务的隔离级别
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
Spring事务的只读
“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可。
Spring事务的事务超时
为了使应用程序更好的运行,事务不能运行太长的时间。因此,声明式事务的第四个特性就是超时。
Spring事务的回滚规则
默认情况下,事务只有在遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚,但是也可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。