1、@Transactional注解
@Transactional 实质是使用了 JDBC 的事务来进行事务控制的
@Transactional 基于 Spring 的动态代理的机制
@Transactional 实现原理:
1) 事务开始时,通过AOP机制,生成一个代理connection对象,
并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关的某处容器中。
在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库,
执行所有数据库命令。
[不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚]
(物理连接 connection 逻辑上新建一个会话session;
DataSource 与 TransactionManager 配置相同的数据源)
2) 事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令,
然后关闭该代理 connection 对象。
事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。
一般在项目上有多插入多表字段并且插入的表之间数据有关联时添加事务回滚就显得非常重要。例如插入的第一条数据与第二条数据字段数据大部分相同,但第一条数据插入成功后,第二条数据因为字段原因报错。此时第一条数据就成为脏数据,两条数据无法关联。
举例事务回滚
Service实现层代码
@Service
public class TPeopleServiceImpl implements TPeopleService {
@Autowired
TPeopleMapper tPeopleMapper;
@Autowired
TPeopleService tPeopleService;
@Override
@Transactional(rollbackFor = Exception.class)
public TPeople savePeople(TPeople params) throws Exception{
tPeopleMapper.insert(params);
System.out.println("数据库已插入");
return params;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int test(TPeople params) throws Exception{
tPeopleService.savePeople(params);
System.out.println("------------------------------------------");
if (params.getName().equals("张三君")){
throw new Exception("张三军不许入住");
}
return 0;
}
数据库当前就为一条数据
添加为张三君的数据
数据已插入到Mybatis缓存中,当跑完整个流程便插入进数据库
但是我们现在入参的名称为张三君
跑完后抛出异常,事务回滚,Mybatis缓存将要插入的数据没有插入进数据库当中。
数据库还是为一条数据。
(注意:若是在方法类中使用try、catch捕获异常则不会回滚该事务)
2、手动提交回滚
impl中通过这样获取:
@Resource(name="transactionManager")
private DataSourceTransactionManager transactionManager;
具体执行操作:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。
TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态
try {
//逻辑代码,可以写上你的逻辑处理代码
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}