详述Spring 框架事务以及@Transactional常用属性说明
事务管理
企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性。
事务:Spring中的事务是指多个java操作同时失败或成功。MYsql中的事务是指SQL语句同时失败或成功
它分为编程式事务管理与声明式事务管理。
主要应用的为声明式事务管理:它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理,Spring声明式事务管理建立在AOP基础之上,是一个典型的横切关注点,通过环绕增强来实现,其原理是对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完毕之后根据执行情况提交或回滚事务。
实现声明式事务
- 引入spring-aspects-4.3.10.RELEASE.jar包
- Spring配置文件(application.xml)中添加如下配置
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"></bean>
<!-- 开启@Transactional注解 -->
<tx:annotation-driven proxy-target-class="true"/>
3.在Service层public方法上添加事务注解——@Transactional
@Transactional
- 当一个类含有@Transactional注解修饰的方法,则Spring框架自动为该类创建代理对象,默认使用JDK创建代理对象(可手动添加配置改为CGLib代理)
- 不能在protected、默认或者private的方法上使用@Transactional注解
- 其有四个常用属性1. timeout 2.readOnly 3.rollbackFor 4.propagation
1.timeout
当目标方法添加这个属性时,就限制了执行时间,若超出规定时间,则自动回滚事务且出现org.springframework.transaction.TransactionTimedOutException异常。
@Transactional(timeout=3)
public boolean insert(String userId,String bookId, int count){
//代码略
Thread.sleep(4000);
//代码略
}
如上例,程序内因强制延缓4秒而注定超时,则一定发生回滚。
2.readOnly
当目标方法添加这个属性时,对事务性资源进行只读操作。
@Transactional(readOnly=true)
public boolean insert(String userId,String bookId, int count){
//代码略
xxx.update();
//代码略
}
因方法内出现了更新操作,则一定发生回滚。
3.rollbackFor
@Transactional(rollbackFor= {MoneyException.class}/*里面写的一般是检查时异常*/)
public boolean insert(String userId,String bookId, int count)throws MoneyException{
//代码略
}
因为@Transactional一般只对运行时异常(RuntimeException)起作用,如果想要对某类检查时异常起作用,就需要手动添加配置。
public boolean insert(String userId,String bookId, int count) throws MoneyException{
if(bookDao.enough(bookId, count)) {//书籍足够
//书籍表库存递减
bookDao.update(bookId, count);
}
if(moneyDao.enough(userId, total)) {
//余额足够,代码略
moneyDao.update(userId, total);
}
return true;
}
如上例,代码内进行了两次update操作,如果不配置rollbackFor= {MoneyException.class},则在库存够而钱不够的情况下,数据库内的书籍数量会减少,而钱的数量不减少,发生错误。
但配置后,会发生回滚,保证数据库内的数据正确。
4.propagation
指定事务传播行为,一个事务方法被另一个事务方法调用时,必须指定事务应该如何传播,例如:方法可能继承在现有事务中运行,也可能开启一个新事物,并在自己的事务中运行。
当调用一个事务方法时,若其方法内调用的方法也同为事务方法,一般情况下会将两个事务合并为一个事务。
但使用propagation,可以将两个事务分开。
@Transactional(propagation=Propagation.REQUIRES_NEW)/*当前方法必须启动新事务,
并在它自己的事务内运行,如果有事务在运行,
则把当前事务挂起,直到新的事务提交或者回滚才恢复执行*/
public boolean insert(String userId,String bookId, int count) {
//代码略
}