凡科网站代理登录入口,建设厅网站上保存键看不见,html写手机网站吗,手机网站推广法目录
一. Spring 中事务的实现
1. 编程式事务
2. 声明式事务 3. Transaction 参数的设置
4. Transaction 的隔离级别
5. Transaction 的工作原理
二. Spring 事务传播机制
七种事务传播机制 支持当前事务 不支持当前事务 嵌套事务 一. Spring 中事务的实现
1. 编程式事…目录
一. Spring 中事务的实现
1. 编程式事务
2. 声明式事务 3. Transaction 参数的设置
4. Transaction 的隔离级别
5. Transaction 的工作原理
二. Spring 事务传播机制
七种事务传播机制 支持当前事务 不支持当前事务 嵌套事务 一. Spring 中事务的实现
1. 编程式事务 编程式事务主要就是三个步骤 1. 开启事务 2. 提交事务 3. 回滚事务 在 SpringBoot 中内置了两个对象DataSourceTransactionManager 用来开启事务提交事务和回滚事务TransactionDefinition 是事务的属性在开启事务的时候就需要传入此对象从而获得一个事务 TransactionStatus RestController
RequestMapping(/user)
public class UserController {Autowiredprivate UserService userService;// 编程式事务 要引入两个内置的对象
// 整个事务的操作是需要到这个事务管理器对象的DataSourceTransactionManagerAutowiredprivate DataSourceTransactionManager transactionManager;Autowired
// 事务定义器通过这个来设置事务的一些东西要得到一个事务就必须传递此参数private TransactionDefinition transactionDefinition;RequestMapping(/del)public int del(Integer id) {if (id null || id 0) {return 0;}
// 开启事务TransactionStatus transactionStatus null;int result 0;try {
// 开启事务transactionStatus transactionManager.getTransaction(transactionDefinition);// 业务操作删除用户result userService.del(id);System.out.println(删除 result);
// 正常情况下提交事务transactionManager.commit(transactionStatus);} catch (Exception e) {
// 如果出现异常了回滚事务, 或者事务还没创建就不用回滚if (transactionStatus ! null) {transactionManager.rollback(transactionStatus);}}return result;}
}2. 声明式事务 相比于编程式事务声明式事务就方便得多了只需要在方法或类上添加注解 Transaction 不需要手动开启和提交事务进入方法就自动开启事务方法执行完就自动提交事务如果中途发生没有处理的异常就会自动回滚事务 需要注意的是 Transactional 修饰方法的时候只能修饰在 public 方法上 修饰类的时候表示该注解对类中的所有 public 方法生效 RestController
RequestMapping(/user2)
public class UserController2 {Autowiredprivate UserService userService;RequestMapping(/del)Transactional // 在方法开始之前开启事务方法正常执行结束之后提交事务如果执行途中发生异常则回滚事务public int del(Integer id){if (id null || id 0){return 0;}int result userService.del(id);System.out.println(删除result);int num 10 / 0; // 制造算数异常 return result;}}此时因为在运行过程中出现了算数异常所以事务会进行回滚页面会以 500 的形式返回 但如果对于异常进行 try/catch 处理的时候情况就不一样了如果是我们自己去抓取了异常没有让异常抛出此时就相当于是我们自己把异常消化了外部监测不到就不会回滚事务了而是正常提交事务 对此就有两种解决方法 1. 将异常抛出让框架感知到异常当框架感知到异常之后就会自动进行回滚 2. 手动进行回滚事务 try {int num 10 / 0;}catch (Exception e){
// e.printStackTrace(); // 不回滚
// throw e; // 回滚
// 手动回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();} 3. Transaction 参数的设置 4. Transaction 的隔离级别 在前面的文章中有说到事务的四大特性原子性一致性持久性隔离性。在隔离性中也有五种隔离级别 1. Isolation.DEFAULT以连接的数据库的事务隔离级别为主 2. Isolation.READ_UNCOMMITTED读未提交 3. Isolation.READ_COMMITTED读已提交 4. Isolation.REPEATABLE_READ可重复读 5. Isolation.SERIALIZABLE串行化 此处的细节内容可以见前面的文章。 5. Transaction 的工作原理 Transaction 是基于 AOP 来实现的AOP 又是使用动态代理来实现的如果目标对象实现了接口 默认情况下会采用 JDK 的动态代理如果目标对象没有实现接口会采用 CGLIB 动态代理 Transaction 在开始执行业务之前通过代理先开启事务在执行成功之后再提交事务如果中途遇到异常则回滚事务 二. Spring 事务传播机制 Spring 事务传播机制定义了多个包含了事务的方法相互调用的时候事务是如何在这些方法间进行传递的。 事务的隔离级别是保证多个事务并发执行的稳定性事务的传播机制是保证一个事务在多个调用方法间的稳定性 事务传播机制解决 七种事务传播机制 1. Propagation.REQUIRED默认的事务传播级别它表示如果当前存在事务则加入该事务如果当前没有事务则创建⼀个新的事务。 2. Propagation.SUPPORTS如果当前存在事务则加⼊该事务如果当前没有事务则以非事务的方式继续运⾏。 3. Propagation.MANDATORYmandatory强制性如果当前存在事务则加⼊该事务如果当前没有事务则抛出异常。 4. Propagation.REQUIRES_NEW表示创建⼀个新的事务如果当前存在事务则把当前事务挂起。也就是说不管外部方法是否开启事务Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务且开启的事务相互独立互不⼲扰。 5. Propagation.NOT_SUPPORTED以非事务方式运行如果当前存在事务则把当前事务挂起。 6. Propagation.NEVER以非事务方式运行如果当前存在事务则抛出异常。 7. Propagation.NESTED如果当前存在事务则创建⼀个事务作为当前事务的嵌套事务来运行如果当前没有事务则该取值等价于 PROPAGATION_REQUIRED。 也可以进行整体划分 此处写一个 添加用户和添加日志 的案例进行演示 首先在 Controller 层中的 add 方法进行 Transaction 注解添加然后调用 Service 层的 add 方法Service 层的 add 方法也添加了 Transaction 注解然后调用 logService.add() 方法进行日志打印logService.add() 方法也添加了 Transaction 注解 ( 此处为了方便分析用 Controller 调用了 Service后 Service 再次调用 Service 层的方法) 支持当前事务
RestController
RequestMapping(/user3)
public class UserController3 {Autowiredprivate UserService userService;RequestMapping(/add)Transactional(propagation Propagation.REQUIRED)public int add(String username,String password){if (null username || null password ||username.equals() || password.equals()) return 0;UserInfo user new UserInfo();user.setUsername(username);user.setPassword(password);int result userService.add(user);
// 外部事务的回滚不会报错误
// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return result;}
}Service
public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate LogService logService;Transactional(propagation Propagation.REQUIRED)public int add(UserInfo userInfo){
// 给用户表添加用户信息int addUserResult userMapper.add(userInfo);System.out.println(添加用户结果addUserResult);// 添加日志信息LogInfo logInfo new LogInfo();logInfo.setMessage(添加用户信息);logService.add(logInfo);return addUserResult;}
}Service
public class LogService {Autowiredprivate LogMapper logMapper;Transactional(propagation Propagation.REQUIRED)public int add(LogInfo log){int result logMapper.add(log);System.out.println(添加日志 result);
// 设置回滚操作 内部事务的回滚会报错误TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return result;}
}此时的事务传播机制属于 支持当前事务 也就是可以将三个事务看为是一个事务同时提交同时回滚在程序中前两个事务都正常运行然后最后一个事务进行回滚此时整个事务都会进行回滚也就是既没有添加用户也没有添加日志。 此处需要注意内部事务的回滚会以报错误的形式出现显示 500 页面外部事务的回滚则不会上述是内部事务的回滚所以显示的页面是 不支持当前事务 将 LogService 中的 add 方法也就是日志添加的方法隔离级别设为 REQUIRES_NEW 。 此时该事务就与前面两个事务没有任何联系不在一个调用链上的事务各自执行相互不干扰。独自进行提交事务回滚事务。 Service
public class LogService {Autowiredprivate LogMapper logMapper;Transactional(propagation Propagation.REQUIRES_NEW)public int add(LogInfo log){int result logMapper.add(log);System.out.println(添加日志 result);TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return result;}
}
此时在该方法中进行回滚操作外部事务都不回滚看一下执行结果日志记录没有添加而用户信息添加了 需要补充的是在 不支持当前事务 的机制中虽然两个事务不在一个调用链上但如果内层事务出现了异常而没有及时处理让外层的 Controller 和 Service 都感知到了会导致整个程序报错整个调用链都是500虽然都是独自的业务但是感知到异常的时候都是会进行回滚的 按照上述代码如果在 LogService 中 (或者 UserService )的 add 方法加入 int num 100/0 语句形成算数异常此时内层事务对异常的未处理会导致外层也受影响页面显示 500日志 和 用户信息 都无法添加成功 但如果是外层事务的异常未处理也会造成 500 页面显示但不会影响到内层事务的业务执行 按照上述代码如果在 UserController3 中的 add 方法加入 int num 100/0 语句形成算数异常此时日志可以正常添加而用户信息无法添加因为异常的出现而回滚事务了页面显示为 500 嵌套事务 嵌套事务在进行回滚的时候就只会影响到自己的内层事务外层事务是影响不到的也就是不会回滚嵌套之前的事务 在上述代码中LogService 中的事务就算是 UserService 的内层事务所以 UserService 中的事务设置为 嵌套事务 的时候进行回滚就只会影响到 LogService 中的事务会一起回滚而最外层的 UserController 事务不会被影响到。 得到的结果也就是用户信息添加失败日志信息添加失败 如果是对最里层事务 LogService 设置为 嵌套事务回滚发生在 LogService 中那么此时用户信息是可以添加成功的但日志信息添加失败 Service
public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate LogService logService;Transactional(propagation Propagation.NESTED)public int add(UserInfo userInfo){
// 给用户表添加用户信息int addUserResult userMapper.add(userInfo);System.out.println(添加用户结果addUserResult);TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();// 添加日志信息LogInfo logInfo new LogInfo();logInfo.setMessage(添加用户信息);logService.add(logInfo);return addUserResult;}
} 嵌套事务之所以能实现部分事务的回滚是因为事务中有一个保存点的概念嵌套事务进入之后就相当于新建了一个保存点而回滚的时候只会回滚到保存点因此之前的事务是不受影响的。 嵌套事务和加入事务的区别 1. 如果事务全部执行成功二者的结果是一样的 2. 如果事务执行到一半失败了加入事务整个事务都会回滚而嵌套事务会局部回滚不会影响到上一个方法中执行的结果