欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > Spring事务以及事务的传播机制

Spring事务以及事务的传播机制

2024/10/25 14:23:46 来源:https://blog.csdn.net/m0_73700505/article/details/141858861  浏览:    关键词:Spring事务以及事务的传播机制

事务

在Sping中,事务有两种方式来实现,一种是通过手动编程的方式来实现,一种是通过注解的方式来进行实现.

手动编程实现事务

  @Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@AutowiredTransactionDefinition transactionDefinition;@Autowiredprivate UserService userService;@RequestMapping("/registry")public String registry(String name,String password){//开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);userService.registeryUser(name,password);//提交事务dataSourceTransactionManager.commit(transactionStatus);return "注册成功";}

首先需要对DataSourceTransactionManager事务管理器进行定义,并注入Autowired,

@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@AutowiredTransactionDefinition transactionDefinition;

对TransactionDefinition事务定义进行注入,在需要实现事务的方法里面开启事务

事务开启:

 //开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

事务提交

  //提交事务dataSourceTransactionManager.commit(transactionStatus);

控制台事务提交显示

接下来演示事务进行回滚时的操作

//        事务进行回滚log.info("事务进行回滚中");dataSourceTransactionManager.rollback(transactionStatus);

运行结果:

可以通过观察发现,回滚后的日志没有出现事务commit

发送增加数据请求之前数据库:

发送增加数据请求之后数据库:

可以观察到数据库并没有执行数据的插入操作,可见事务回滚成功,并未进行提交,

使用注解实现事务

使用注解的时候,加在方法之前即可

@Transactinoal可以对方法或者类进行修饰

对方法进行修饰的时候,只对public修饰的方法生效,对其他方法不生效,也不报错,但是不推荐

对类进行修饰的时候,则默认对该类所有的public修饰的方法生效

public class TransactionalController {@Autowiredprivate UserService userService;@RequestMapping("/registry")@Transactionalpublic String registry(String name,String password){userService.registeryUser(name,password);return "注册成功";}
}

 在程序正常进行无异常的时候,事务会进行正常提交,这一部分就不演示了,

接下来演示出现异常事务是否会进行回滚

代码:

   @Transactionalpublic String registry(String name,String password){userService.registeryUser(name,password);int a=10/0;return "注册成功";}

 可以看到事务进行回滚操作了,

可以看到数据库也是没有进行任何变化

  public String registry(String name,String password){userService.registeryUser(name,password);try{int a=10/0;}catch (Exception e){e.printStackTrace();}return "注册成功";}

 

可以看到虽然程序运行时出错了,但是事务提交了,是因为程序运行时抛出的异常被捕获到了,进行处理之后,@Transactional注解会自动进行提交,不会进行回滚,如果还想进行回滚需要手动进行设置,

  try{int a=10/0;}catch (Exception e){
//            e.printStackTrace();TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}

 可以通过这样设置,来手动进行事务的回滚

通过观察日志,我们可以发现事务并没有进行commit,而是进行了rollback.

  @RequestMapping("/r2")@Transactionalpublic String registry2(String name,String password) throws IOException {userService.registeryUser(name,password);if(true){throw new IOException();}return "注册成功";}

这次我们让程序主动抛出异常, 

可以发现,虽然主动抛出了异常,但是事务还是进行了提交

只有当异常为RuntimeException以及他的子类和error时才会进行回滚,其他异常则不会进行回滚

@Transactional(rollbackFor = Exception.class)

在将注解改成这样之后,将rollbackFor指定异常为Exception之后,该事务才会进行回滚.

事务的特性

rollbackFor:能指定事务回滚时的异常类型,可以指定多个异常类型

Isolation:事务的隔离级别,默认值为Isolation.DEFAULT

propagation:事务的传播机制,默认值为propagation.REQUIRED

1.Isolation.DEFAULT : 以连接的数据库的事务隔离级别为主.

2. Isolation.READ_UNCOMMITTED : 读未提交, 对应SQL标准中 READ UNCOMMITTED

3. Isolation.READ_COMMITTED : 读已提交,对应SQL标准中 READ COMMITTED

4. Isolation.REPEATABLE_READ : 可重复读, 对应SQL标准中 REPEATABLE READ

5. Isolation.SERIALIZABLE : 串⾏化, 对应SQL标准中 SERIALIZABLE

事务的传播机制

什么叫事务传播,当A方法和B方法同时被注解@Transactional进行修饰的时候,并且在A方法中调用B方法,那么A方法的事务和B方法的事务该如何开启呢,我们把这种现象称为事务的传播机制.

事务的传播机制分类

1.Propagation.REQUIRED    默认的事务传播机制,如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务

2.Propagation.MANDATORY 强制性.如果当前存在事务,则加入该事物,如果当前没有事务,则抛出异常

3.Propagation.SUPPORTS:如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式继续运行

4.Propagation.REQUIRES_NEW:创建一个新的事务.如果当前存在事务,则把当前事务挂起,也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW所修饰的内部方法都会开启一个新的事务

5.Propagation.NOT_SUPPORTED:以非事务的方式进行运行,如果当前存在事务,则把当前事务进行挂起,

6.Propagation.NEVER:以非事务的方式运行,如果有当前事务,则抛出异常

7.Propagation.NESTED:如果当前存在事务,则创建一个当前事务的嵌套事务,如果当前没有事务,则创建一个事务

conttroller类:

@RequestMapping("/test")
public class UserController2 {@Autowiredprivate UserService userService;@Autowiredprivate LogService logService;@RequestMapping("/u1")@Transactionalpublic String registry(String name,String password){userService.registeryUser(name,password);logService.inserLog(name,"注册成功");return "注册成功";}

 LogService类:

@Service
public class LogService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation =Propagation.REQUIRED)public void inserLog(String name,String op){logInfoMapper.insertLog(name,"用户注册");int a=10/0;}
}

Userservice类: 

@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public void registeryUser(String name,String password){userInfoMapper.insert(name,password);}
}

可以发现两次操作是在同一个事务开启的,并且由于发生了异常进行回滚,进行的两次插入操作均失效,

 

  @Transactional(propagation =Propagation.REQUIRES_NEW)

将事务的传播机制改为Propagation.REQUIRES_NEW之后 

可以发现开启了两个事务,其中第二个事务由于发生异常进行了回滚操作,第一个事务成功提交了,说明这两个事务的隔离级别设置为Propagation.REQUIRES_NEW时,事务之间是相互不干扰的. 

    @Transactional(propagation =Propagation.NEVER)

在将事务的隔离级别改为NEVER的时候,程序直接抛出异常

 

@Transactional(propagation =Propagation.NESTED)

 

在将隔离级别改为NESTED的时候,可以发现,在其中的一个事务发生异常的时候,两个操作都会失效,都会进行回滚.

logInfoMapper.insertLog(name,"用户注册");try{ int a=10/0;}catch (Exception e){TransactionAspectSupport.
currentTransactionStatus().setRollbackOnly();}

 

http://127.0.0.1:8080/test/u1?name=123&password=1234

url请求访问之前数据库:

url请求访问之后数据库:

通过观察,我们可以发现只有log_info表的插入数据进行了回滚,然而user_info表中的插入数据并没有进行回滚,这是nested和required的区别.在于nested是一个嵌套事务,只要其中的一个事务把自己的异常处理好了并且即使rollback了也不会影响另外一个事务的正常提交.然而required由于是同一个事务,所以在一个事务中进行rollback了,另外一个也会自动进行rollback

mybatis运行日志

nested和required的区别

整个事务如果执行成功,那么两种级别是一样的.

如果其中的一个事务发生了异常,那么这个事务在nested中是可以进行局部回滚的,而required是做不到的.

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com