关于MySQL事务,你必须知道的几个知识点!

运维 数据库运维
上期我们讲到了jpa的常用操作,查询、更新、删除等,但是如果在操作数据库事务时发生异常 ,数据会回滚吗?

 [[408136]]

Transaction事务

上期我们讲到了jpa的常用操作,查询、更新、删除等,但是如果在操作数据库事务时发生异常 ,数据会回滚吗?下面我们来看个例子

UserController新增如下代码:

  1. @GetMapping("save1"
  2.  
  3. public String save1(){ 
  4.     User user = new User(); 
  5.     user.setDptId(1L); 
  6.     user.setName("a"); 
  7.     user.setAge(18L); 
  8.     user.setEmail("a@a.com"); 
  9.     user.setHeadImg("headImg1"); 
  10.  
  11.     this.userJpa.save(user); 
  12.     //模拟发生了异常 
  13.     System.out.println(1/0); 
  14.     return "ok"

使用postman请求

  1. localhost:8080/user/save1 

执行之后可以看到java后台报错了,postman前台也报出来错误,但是数据却保存进去了,数据新增了一条记录

说明即使发生了异常,数据还是会保存进去数据库,那应该怎么办呢?试试在save1方法上加一个@Transactional的注解。

我们再执行一次。发现错误也报出来了,但是数据库并没有将新数据插入进去,最新的还是上一次的id为7的记录,那么 Transactional注解是干嘛的呢?

@Transactional是声明式事务管理编程中使用的注解

  1. 该注解是添加在实现类或者 接口 实现方法上,而不能放在 接口 中
  2. 需要注意的是这个注解只对public方法生效

如下是该注解的属性,我们需要关注重点关注的是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:只有执行的异常才回滚。但是我们刚刚的程序并没有指定异常,那是默认的是遇到什么样的异常会回滚呢?

  1. 将UserController中的代码稍作修改,手动 throw new Exception("test") ,再执行下postman,发现事务提交了,并没有回滚。
  2. 接着我们将注解修改为 @Transactional(rollbackFor = Exception.class) ,再执行postman,事务却回滚了,并没有提交,什么原因?
  3. spring的 @Transactional 注解可以很方便的开启事务,但是默认只在遇到 运行时异常 和 Error 时才会回滚,非运行时异常不回滚,即 Exception 的子类中,除了 RuntimeException 及其子类,其他的类默认不回滚。
  4. 而rollbackFor属性可以解决这个问题, rollbackFor = Exception.class 表示 Exception 及其子类的异常都会触发回滚,同时不影响 Error 的回滚。

propagation:这个用得最广的需求就是业务出错了,但是日志必须提交到数据库。怎么处理?来看下面的代码。

新增LogService类

  1. @Service 
  2.  
  3. public class LogService { 
  4.     @Resource 
  5.     private UserJpa userJpa; 
  6.  
  7.     @Transactional(propagation = Propagation.REQUIRES_NEW) 
  8.     public void saveLog(){ 
  9.         User user = new User(); 
  10.         user.setDptId(1L); 
  11.         user.setName("log"); 
  12.         user.setAge(18L); 
  13.         user.setEmail("log@log.com"); 
  14.         user.setHeadImg("log"); 
  15.  
  16.         this.userJpa.save(user); 
  17.         System.out.println("log"); 
  18.     } 

新增UserService类:

  1. @Service 
  2.  
  3. public class UserService { 
  4.     @Resource 
  5.     private UserJpa userJpa; 
  6.     @Resource 
  7.     private LogService logService; 
  8.  
  9.     @Transactional(rollbackFor = Exception.class
  10.     public void saveBiz() throws Exception { 
  11.         System.out.println("save2"); 
  12.         User user = new User(); 
  13.         user.setDptId(1L); 
  14.         user.setName("biz"); 
  15.         user.setAge(18L); 
  16.         user.setEmail("biz@biz.com"); 
  17.         user.setHeadImg("biz"); 
  18.  
  19.         this.userJpa.save(user); 
  20.  
  21.         //模拟保存日志 
  22.         this.logService.saveLog(); 
  23.         //模拟发生了异常 
  24.         throw new Exception("test1"); 
  25.     } 

UserController新增代码

  1. @GetMapping("save2"
  2.  
  3. public String save2() throws Exception { 
  4.     //模拟业务操作 
  5.     this.userService.saveBiz(); 
  6.     return "ok"

postman执行下,是不是只有log的那条记录插入进去了?biz的没有插入进去。

注意:同一个业务类里面 , 即使声明为 Propagation.REQUIRES_NEW 也不会新启一个事务。必须调用另一个类的 Propagation.REQUIRES_NEW 方法才行。所以样例中是使用 UserService 里面调用另一个类 LogService 中的 saveLog 的方法。

 

责任编辑:张燕妮 来源: 博客园
相关推荐

2017-12-07 15:47:25

2020-02-28 14:05:00

Linuxshell命令

2017-12-07 15:28:36

2017-10-11 15:50:18

光纤通信传输

2021-03-01 07:34:42

Java泛型ArrayList

2012-11-05 09:19:37

2019-05-30 08:25:50

5G4G网络

2011-12-16 17:05:58

2010-06-25 09:18:43

MySQLOracle

2011-05-13 11:41:55

2012-02-08 09:44:05

ChromeAndroid

2017-10-17 15:18:58

综合布线网络

2009-06-04 10:20:34

Hibernate持久化Java

2019-06-05 15:43:46

固态硬盘PC

2009-04-01 11:39:39

视图DB2

2012-09-29 10:29:56

.Net内存分配继承

2012-09-29 09:22:24

.NETGC内存分配

2015-01-20 11:24:52

Win 10

2015-05-29 09:45:42

Google IOA

2016-06-29 13:50:12

云计算
点赞
收藏

51CTO技术栈公众号