[[408136]]
上期我们讲到了jpa的事识点常用操作,查询、须知更新、关于个知删除等,事识点但是须知如果在操作数据库事务时发生异常 ,数据会回滚吗?下面我们来看个例子
- @GetMapping("save1")
- public String save1(){
- User user = new User();
- user.setDptId(1L);
- user.setName("a");
- user.setAge(18L);
- user.setEmail("a@a.com");
- user.setHeadImg("headImg1");
- this.userJpa.save(user);
- //模拟发生了异常
- System.out.println(1/0);
- return "ok";
- }
使用postman请求
- localhost:8080/user/save1
执行之后可以看到java后台报错了,关于个知postman前台也报出来错误,事识点但是须知数据却保存进去了,数据新增了一条记录
说明即使发生了异常,数据还是会保存进去数据库,那应该怎么办呢?试试在save1方法上加一个@Transactional的注解。
我们再执行一次。发现错误也报出来了,但是数据库并没有将新数据插入进去,最新的还是上一次的id为7的记录,那么 Transactional注解是干嘛的呢?
@Transactional是声明式事务管理编程中使用的注解
如下是该注解的属性,我们需要关注重点关注的是rollback-for和propagation两个属性。
属性名 | 说明 |
---|---|
name | 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。 |
propagation | 事务的传播行为,默认值为 REQUIRED。 |
isolation | 事务的隔离度,默认值采用 DEFAULT。 |
timeout | 事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。 |
read-only | 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。 |
rollback-for | 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。 |
no-rollback- for | 抛出 no-rollback-for 指定的异常类型,不回滚事务。 |
rollback-for:只有执行的异常才回滚。但是我们刚刚的程序并没有指定异常,那是默认的是遇到什么样的异常会回滚呢?
throw new Exception("test")
,再执行下postman,发现事务提交了,并没有回滚。@Transactional(rollbackFor = Exception.class)
,再执行postman,事务却回滚了,并没有提交,什么原因?@Transactional
注解可以很方便的开启事务,但是默认只在遇到 运行时异常
和 Error
时才会回滚,非运行时异常不回滚,即 Exception
的子类中,除了 RuntimeException
及其子类,其他的类默认不回滚。rollbackFor = Exception.class
表示 Exception
及其子类的异常都会触发回滚,同时不影响 Error
的回滚。propagation:这个用得最广的需求就是业务出错了,但是日志必须提交到数据库。怎么处理?来看下面的代码。
- @Service
- public class LogService {
- @Resource
- private UserJpa userJpa;
- @Transactional(propagation = Propagation.REQUIRES_NEW)
- public void saveLog(){
- User user = new User();
- user.setDptId(1L);
- user.setName("log");
- user.setAge(18L);
- user.setEmail("log@log.com");
- user.setHeadImg("log");
- this.userJpa.save(user);
- System.out.println("log");
- }
- }
- @Service
- public class UserService {
- @Resource
- private UserJpa userJpa;
- @Resource
- private LogService logService;
- @Transactional(rollbackFor = Exception.class)
- public void saveBiz() throws Exception {
- System.out.println("save2");
- User user = new User();
- user.setDptId(1L);
- user.setName("biz");
- user.setAge(18L);
- user.setEmail("biz@biz.com");
- user.setHeadImg("biz");
- this.userJpa.save(user);
- //模拟保存日志
- this.logService.saveLog();
- //模拟发生了异常
- throw new Exception("test1");
- }
- }
- @GetMapping("save2")
- public String save2() throws Exception {
- //模拟业务操作
- this.userService.saveBiz();
- return "ok";
- }
postman执行下,是不是只有log的那条记录插入进去了?biz的没有插入进去。
注意:同一个业务类里面 , 即使声明为 Propagation.REQUIRES_NEW
也不会新启一个事务。必须调用另一个类的 Propagation.REQUIRES_NEW
方法才行。所以样例中是使用 UserService
里面调用另一个类 LogService
中的 saveLog
的方法。
责任编辑:张燕妮 来源: 博客园 MYSQL开发数据库
(责任编辑:休闲)
中国经济占全球经济比重将持续增加 新的全球经济力量布局正在形成