Spring事务的处理和配置
spring对于事务的处理,有两种 一种是编程式事务(将事务管理代码嵌到业务方法中来控制事务的提交和回滚),还有一种是声明式事务(利用Spring的AOP进行事务管理)。编程试事务会有大量的冗余代码出现,按照spring的说法会污染你的业务层。
spring的出现就简化了大量的需要你配置的东西(约定大于配置),面向注解试开发。
Spring + Mybatis 中就衍生出了@Transactional的注解,只需要进行简单的配置,在需要进行事务绑定的方法上添加这个@Transactional的注解就可以进行原子性操作。但是Spring简化了事务的配置,就必须要你按照他的一套逻辑规范来真确的使用这个注解式事务的使用。下面是事务使用的实例化操作,业务背景(Spring + Mybatis + Oracle)而且jdbc操作为多数据源。
一,第一步 定义事务的bean
<!-- 定义事务 -->
<bean id = "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "multipleDataSource" />
</bean>
<!-- 使用注解定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
注意事项:ref = "xxxx"参数指向dataSource(数据源)
二,使用@Transactional的注解进行方法绑定
注意事项:@Transactional中的参数可以不加(指定能够触发事务回滚的异常类,可以指定多个用{}进行指示),但是个人习惯还是得加上,默认情况下,Spring会对unchecked异常进行事务回滚;如果是checked异常则不回滚。
辣么什么是checked异常,什么是unchecked异常
java里面将派生于Error或者RuntimeException(比如空指针,1/0)的异常称为unchecked异常,其他继承自java.lang.Exception得异常统称为Checked Exception,如IOException、TimeoutException等。
然后你就可以进行测试了。
三,测试
简单的两个插入语句进行测试,正常不加事务第一个insert语句的数据会进入到数据库,但是第二个不会,如果是添加了事务的话,就会回滚,第一条insert语句都不会进入倒数据库的层面去。
这是正常的使用场景。现在我们需要进行异常捕获然后返回状态值(不管后台怎么样,添加成功与否,或者是出了异常,我都要进行返回状态值给前端,好告诉用户我后台出错了。。。叫他联系管理员),
import com.alibaba.fastjson.JSONObject;
import com.example.demo.test.dao.Studentsdao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
/**
* @author yuqin
* @date 2019/8/27
* @description:
*/
@Service
public class StudentsService {
@Autowired(required = false)
Studentsdao studentsdao;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Transactional(rollbackFor = Exception.class)
public JSONObject getStudents() {
try {
studentsdao.addStudents();
int i = 1 / 0;
studentsdao.addStudents2();
//成功返回的状态值
return null;
} catch (Exception e) {
e.printStackTrace(); //在控制台打印报错信息i
logger.error("xxx方法异常,异常信息为:" + e.toString());
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动回滚事务
//异常返回的状态值
return null;
}
}
}
还有一种情况就是不用手动回滚事务
throw new RuntimeException();返回一个运行时异常也会触发到事务的回滚机制
现在总结遇到的坑,或者说是导致事务失效的问题总结
1.(我遇到的也是最惨的)项目中关于数据源的配置,我们公司项目使用的是多数据源,原先事务的配置直接配置的dataSoure
单个Oracle链接。但是我看到Spring关于事务配置明确指出:Mybatis + Spring 的事务配置必须
sqlSessionFactory中的数据源和配置事务的transactionManager中的数据源一致,否则会导致事务失效。
2.方法 只能是public 否则失效
3.指定回滚的异常
4mysql 引擎是否支持事务
5.在@Transactional注解的方法中,再调用本类中的其他方法B时,那么B方法上的@Transactional注解是不!会!生!效!的!
假设我现在有个A方法你加了@Transactional的注解 ,代码比较冗余 因为查询和遍历数据很多,业务场景摆在这里,一个方法里面套个n多个try{}catch(){},我想把关于数据库操作的删除,修改,新增拿出来单独抽出来一个方法B进行处理,现在你在B上加了一个@Transactional的注解,我告诉你,这尼玛事务不好使。它特么不好使你知道吧。
正确的处理是方法B把异常正常抛出给A,让A的@Transacional来捕获到这个异常进行处理和回滚。
最后总结:如果你的事务失效了,先看配置,先看配置,先看配置。。。。。