1、事务认识
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
2、事务的传播特性
支持当前事务的情况
- PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。
不支持当前事务的情况
- PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况
- PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。
3、事务的隔离级别
- ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。
- ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
- ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
4、Spring事务实现方式
Spring关于事务的配置总是由数据源、事务管理器、代理机制三个部分组成
Spring事务的核心jar包:spring-tx-3.2.13.RELEASE.jar
4.1.spring数据源配置
PreferencsPlaceholderConfigurer类加载数据库配置文件
BasicDataSource类配置数据源
<!--加载database.properties配置文件-->
<bean id="database"class="org.springframework.beans.factory.config.PreferencsPlaceholderConfigurer">
<property name="location"value="classpath:database.properties" />
</bean>
<!-- 创建数据源bean -->
<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
4.2.事务管理器配置
DataSourceTranactionManager类定义事务管理器
<!-- 定义数据源的声明事务管理器 -->
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTranactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
4.3.代理机制
方式一:使用tx标签配置的拦截器
<!--使用tx标签配置事务的拦截器 transaction-manager属性引用事务管理器-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--对哪个方法进行事务管理 propagation指定传播特性-->
<!--匹配以update开头的方法-->
<tx:method name="update*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* cn.siwen.service.impl.*.*(..))" id="pointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
方式二:使用事务注解@Transaction
<!--开启事务注解 transaction-manager属性引用事务管理器-->
<tx:annotation-driven transaction-manager="transactionManager"/>
在需要使用注解定义事务的类及方法上添加 @Transaction注解
@Transactional
public class TestServiceBean implements TestService {}
当类中某些方法不需要事物时
在方法上定义事务传播特性为not_supported
@Transactional
public class TestServiceBean implements TestService {
private TestDao dao;
public void setDao(TestDao dao) {
this.dao = dao;
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public List<Object> getAll() {
return null;
}
}
5、Spring事务回滚方式
方式一:需要实现事务的方法主动抛出异常,并在调用此方法时捕捉异常,数据出错将自动回滚
方法二:如果在方法内手动捕获了异常,可以使用如下方式手动回滚数据
//得到当前事务
TransactionStatus t=TransactionAspectSupport.currentTransactionStatus();
//若当前存在事务则回滚
if(t!=null) t.setRollbackOnly();