当前位置: 首页 > news >正文

网站收录查询平台网站备案 登陆

网站收录查询平台,网站备案 登陆,网站备案号如何获得,wordpress 插件 摘要文章目录 一. Spring事务简介二. Spring事务使用1. 编程式事务2. 声明式事务 三. Transactional的使用1. 参数作用2. 事务失效的场景3. Transactional工作原理 四. Spring 事务的隔离级别五. Spring事务传播机制 一. Spring事务简介 在之前的博客已经介绍了在 Spring 环境中整… 文章目录 一. Spring事务简介二. Spring事务使用1. 编程式事务2. 声明式事务 三. Transactional的使用1. 参数作用2. 事务失效的场景3. Transactional工作原理 四. Spring 事务的隔离级别五. Spring事务传播机制 一. Spring事务简介 在之前的博客已经介绍了在 Spring 环境中整合 mybatis 完成数据库的增删查改操作在正常情况下操作数据库是没有问题的但是当一个业务需要并发式的操作数据库并且需要涉及到修改插入删除操作就可能会有问题如转账业务其实是有两个步骤第一步从 A 账户扣钱第二步在 B 账户中加钱。 如果第一步顺利执行的在执行完成第二步前程序发生了异常 此时第二个操作就不能够正常执行了这就会是很严重的事故了致使 A 的钱少了但 B 的钱没有增多无论是用户还是我们都是不能容忍这样的 bug 的。 为了解决这个问题Spring 引入了事务管理的机制事务的作用是保证执行一组数据库操作的时候要么全部失败要不全部成功即同成功或同失败。 那也就是在程序发生异常的时候回滚所有已经成功数据库操作这样就算这一次转账失败了也不会给客户和商家带来损失。 Spring 中事务的作用是保证在数据层或业务层执行的一系列数据库操作同成功或同失败。 二. Spring事务使用 Spring 中的事务分为两类 编程式事务手动操作。声明式事务自动提交事务。 1. 编程式事务 SpringBoot 内置了两个对象DataSourceTransactionManager用来获取事务开启事务、提交事务、回滚事务ransactionDefinition是事务的属性在获取事务时需要将TransactionDefinition传递进去获取一个TransactionStatus。 ControllerServiceMapper 各层演示代码如下 package com.example.demo.controller;import com.example.demo.model.UserInfo; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController RequestMapping(/user) public class UserController {Autowiredprivate UserService userService;// JDBC 事务管理器Autowiredprivate DataSourceTransactionManager transactionManager;// 定义事务属性Autowiredprivate TransactionDefinition transactionDefinition;RequestMapping(/add)public int del(Integer id) {UserInfo userinfo new UserInfo();userinfo.setUsername(zhaoliu);userinfo.setPassword(123);if(userinfo ! null) {//开启事务TransactionStatus transactionStatus transactionManager.getTransaction(transactionDefinition);//删除用户业务操作int result userService.add(userinfo);System.out.println(受影响行数: result);// 提交事务/回滚事务// transactionManager.commit(transactionStatus); //提交事务transactionManager.rollback(transactionStatus); //回滚事务}return 0;} }数据库 userinfo 表中现有数据如下 启动程序在浏览器地址栏中进行 url 的访问结果如下 控制台显示的结果是插入成功的此时再看数据库数据是否有变化。 我们可以发现数据库中数据是没有变化的说明在插入数据后事务成功的进行了回滚操作但是这样的方式是比较繁琐的下面介绍更简单的声明式事务。 2. 声明式事务 声明式事务我们只需要在方法上加上Transactional注解就可以实现此时无需我们手动进行开启事务和提交事务进入方法就会自动开启事务执行完毕自动提交发生异常后会自动回滚事务。 package com.example.demo.controller;import com.example.demo.model.UserInfo; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RequestMapping(/user) RestController public class UserController2 {Autowiredprivate UserService userService;TransactionalRequestMapping(/add)public int add() {UserInfo userinfo new UserInfo();userinfo.setUsername(zhaoliu);userinfo.setPassword(123);// 非空判断if (userinfo null) {return 0;}// 调用 service 执行添加int result userService.add(userinfo);System.out.println(受影响行数: result);// 将结果返回给前端return result;} }目前数据库数据 访问结果 此时数据库中就成功插入了一条数据这种情况是没有异常的情况下代码执行成功后自动进行了commit。 我们来在业务中加上一段异常代码 RestController RequestMapping(/user2) public class UserController2 {Autowiredprivate UserService userService;TransactionalRequestMapping(/del)public int del(Integer id) {if(id null || id 0) {return 0;}int result userService.del(id);int n 1 / 0; //异常业务return result;} }重新访问进行插入操作结果如下 可以看到的控制台中信息显示成功的进行了插入操作但同时报了一个算术异常再来看数据库 还是原来的那几条记录此时的情况就是发生异常自动进行了回滚操作了。 三. Transactional的使用 Transactional 的作用范围它既可以用来修饰方法也可以用来修饰类。 修饰方法更推荐使用只能应用到public方法上否则不生效。修饰类表明该注解对类中所有的public方法都生效。 1. 参数作用 我们可以通过设置 Transactional 的一些参数来决定事务的一些具体的功能。 参数作用value当配置了多个事务管理器时可以使用该属性指定选择哪个事务管理器。transactionManager当配置了多个事务管理器时可以使用该属性指定选择哪个事务管理器。propagation事务的传播行为默认值为 Propagation.REQUIREDisolation事务的隔离级别,默认值为 lsolation.DEFAULTtimeout事务的超时时间默认值为 -1如果超过该时间限制但事务还没有完成,则自动回滚事务。readOnly指定事务是否为只读事务默认值为 false为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only为true。rollbackFor用于指定能够触发事务回滚的异常类型可以指定多个异常类型。rollbackForClassName用于指定能够触发事务回滚的异常类型可以指定多个异常类型。noRollbackFor抛出指定的异常类型不回滚事务也可以指定多个异常类型。noRollbackForClassName抛出指定的异常类型不回滚事务也可以指定多个异常类型。 2. 事务失效的场景 要注意Transactional 在异常被捕获的情况下不会进行事务自动回滚。 我们将上面的代码手动创建的一个异常进行try catch处理。 再来进行访问结果如下 此时程序抛出了异常但数据库数据插入后并没有进行回滚操作出现这种情况的原因是事务AOP通知只有自己捕捉到了目标抛出的异常才能进行后续的回滚操作如果目标自己处理掉了异常事务是无法知悉的也就无法处理了。 解决方案 1️⃣方式一在 catch 块中将异常继续抛出此时代理对象就能感知到异常也就能自动的回滚事务了。 再次访问结果如下 此时数据库中数据是没有变化的即在成功插入后进行了回滚操作。 2️⃣方式二 手动回滚事务在方法中使用TransactionAspectSupport.currentTransactionStatus()可以得到当前的事务然后设置回滚方法setRollbackOnly就可以实现回滚了。 访问结果 此时数据插入后也是成功进行回滚而程序也不会报错。 3. Transactional工作原理 Transactional 是基于 AOP 实现的AOP 又是使用动态代理实现的。如果目标对象实现了接口默认情况下会采用 JDK 的动态代理如果目标对象没有实现了接口会使用 CGLIB 动态代理。 Transactional 在开始执行业务之前通过代理先开启事务在执行成功之后再提交事务。如果中途遇到异常会进行回滚业务。 Transactional 具体执行主要是以下逻辑 bean实例化Spring 容器创建了一个目标对象bean这个目标对象通常是一个普通的 Java 类其中包含了一些需要被事务管理的方法。看方法适配是否有切面Spring 框架会检查目标对象是否有被 Transactional 注解标记的方法如果有这样的方法那么这些方法需要被事务管理。如果目标对象中存在被 Transactional 注解标记的方法那么 Spring 将会创建一个代理对象。这个代理对象包含了与事务管理相关的逻辑代理对象会实现与目标对象相同的接口如果有或者继承目标对象的类如果没有接口从而能够替代目标对象的工作这意味着当其他部分的代码请求目标对象时实际上会得到代理对象而不是直接的目标对象。如果目标对象中不存在被 Transactional 注解标记的方法代理对象会被返回给 Spring 的容器从而成为容器中的实际 bean。当调用代理对象的方法时代理对象会在执行目标方法之前执行切面逻辑 before通常是事务管理的逻辑然后调用目标方法。如果切面逻辑中的 method 调用成功执行没有抛出异常代理对象会继续执行方法然后在方法执行后执行切面逻辑 after通常是事务提交。如果在目标方法的执行过程中抛出了异常代理对象会执行切面逻辑中的回滚操作以确保事务的一致性。 四. Spring 事务的隔离级别 我们可以使用以下 sql 查询 MySQL 中全局事务隔离级别和当前连接的事务隔离级别: select global.tx_isolation,tx_isolation;Spring 的事务隔离级别是有以下 5 种的 相比于 MySQL 中多了一种DEFAULT。 DEFAULT 以连接的数据库的 库的全局事务隔离级别为主 。READ_UNCOMMITTED读未提交允许读取还未提交的数据会出现脏读、不可重复读和幻读等问题。READ_COMMITTED读已提交只能读取已经提交的数据避免了脏读的问题但是可能出现不可重复读和幻读的问题。REPEATABLE_READ可重复读保证同一事务中多次读取同一记录结果是一致的避免了脏读和不可重复读的问题但是仍然可能出现幻读的问题。SERIALIZABLE串行化保证事务串行执行避免了脏读、不可重复读和幻读等问题但是影响系统性能。 默认情况下Spring 会使用底层数据库的默认隔离级别通常是 READ_COMMITTED 级别。可以通过事务管理器的 setDefaultTransactionIsolation() 方法或在Transactional注解中使用isolation属性来设置隔离级别 五. Spring事务传播机制 Spring 事务传播机制定义了多个包含事务的方法相互调用时的行为。 事务隔离级别是保证多个并发事务执行是可控的而事务传播机制是保证一个事务在多个调用方法间是可控的。 事务隔离级别是为了解决多个事务同时调用一个数据库的问题 事务传播机制是解决一个事务在多个方法中传递的问题 Spring 事务传播机制包含以下 7 种 Propagation.REQUIRED默认的事务传播级别它表示如果当前存在事务则加入该事务如果当前没有事务则创建⼀个新的事务。Propagation.SUPPORTS如果当前存在事务则加入该事务如果当前没有事务则以非事务的方式继续运行。Propagation.MANDATORYmandatory强制性如果当前存在事务则加入该事务如果当前没有事务则抛出异常。Propagation.REQUIRES_NEW表示创建一个新的事务如果当前存在事务则把当前事务挂起。也就是说不管外部方法是否开启事务Propagation.REQUIRES_NEW 修饰的内部会新方法开启自己的事务且开启的事务相互独立互不干扰。Propagation.NOT_SUPPORTED以非事务方式运行如果当前存在事务则把当前事务挂起。Propagation.NEVER以非事务方式运行如果当前存在事务则抛出异常。Propagation.NESTED如果当前存在事务则创建⼀个事务作为当前事务的嵌套事务来运行如果当前没有事务则该取值等价于 PROPAGATION_REQUIRED。 通过设置Transactional注解中的propagation属性就可以完成Spring事务传播机制的修改。 事务传播机制可以分为以下三类 上面的前 6 种事务机制是比较容易理解的下面主要来演示一下NESTED这种嵌套事务的效果为了便于观察我们清一下数据库中的数据 首先我们在UserService再声明一个insert方法方法中再调用一次UserMapper中的add接口执行插入逻辑在UserController2的add中再加入一个调用insert的逻辑。 把调用逻辑写好后构造嵌套事务将UserController2中的add的事务机制声明为REQUIREDUserService中的add和insert的事务机制都声明为NESTED整体代码如下 RequestMapping(/user2) RestController public class UserController2 {Autowiredprivate UserService userService;Transactional(propagation Propagation.REQUIRED)RequestMapping(/add)public int add() {UserInfo userinfo new UserInfo();userinfo.setUsername(zhaoliu);userinfo.setPassword(123);// 非空判断if (userinfo null) {return 0;}int result userService.add(userinfo);result userService.insert(userinfo);System.out.println(受影响行数: result);return result;} }Service public class UserService {Autowiredprivate UserMapper userMapper;Transactional(propagation Propagation.NESTED)public int add(UserInfo userinfo) {int result userMapper.add(userinfo);System.out.println(add result - result);return result;}Transactional(propagation Propagation.NESTED)public int insert(UserInfo userInfo) {int result userMapper.add(userInfo);System.out.println(insert result - result);try {int num 10 / 0;} catch (Exception e) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return result;} }访问结果 此时执行到Controller中的add会开启一个事务其中调用的add和insert开始的是嵌套事务嵌套事务如果发生了回滚只会影响它自己的局部逻辑而不影响全局。 控制台显示的是成功插入了两条记录的 查看数据库只是成功插入了一条记录这是因为insert逻辑中发生了回滚但它不会影响其他部分的逻辑。 要注意在嵌套事务中可能出现异常的部分要手动处理进行回滚不能让异常抛出否则会被全局代理感知到造成全局事务的整体回滚。 嵌套事务之所以能够实现部分事务的回滚是因为事务中有⼀个保存点savepoint的概念嵌套事务进入之后相当于新建了⼀个保存点而滚回时只回滚到当前保存点因此之前的事务是不受影响的这一点可以在 MySQL 的官方文档汇总找到相应的资料网页链接 。 嵌套事务NESTED和加入事务REQUIRED 的区别 整个事务如果全部执行成功二者的结果是⼀样的。如果事务执行到⼀半失败了那么加入事务整个事务会全部回滚而嵌套事务会局部回滚不会影响上⼀个方法中执行的结果。
http://www.zqtcl.cn/news/251892/

相关文章:

  • 网站建设好后 如何验收什么网站可以做护考题
  • 网站安全怎么做wordpress代币插件
  • 吉林网站建设电话龙华网站建设专业定制企业
  • 个人导航网站怎么备案js调用wordpress文章列表
  • 网站微信推广方案衡水外贸网站建设
  • 怎么打造自己的网站如何做自已网站
  • 美容美发网站模板wordpress适合优化吗
  • 网站开发的著作权和版权沧州市做网站价格
  • 优客逸家网站源码酒吧装修
  • 深圳网站制作的公司怎么样开工作室做网站怎样找资源
  • 大连城乡建设局网站seo编辑招聘
  • 网站建设意见怎么在中国移动做网站备案
  • 做内贸哪个网站找客户网络外包
  • 古玩网站建设意义钟山县住房和城乡建设局网站
  • 网站开发微信公众号自定义菜单规则网站建设
  • 营销网站建设工作教育培训wordpress主题
  • 温州地区做网站公司如何注册新公司
  • 做的网站怎样评估价值全国信息公示系统官网
  • 外国网站签到做任务每月挣钱1g内存vps 开电影网站
  • 营销型网站案例易网拓互联购物
  • 河南企业网站制作微信小程序如何做
  • 金坛住房和城乡建设局网站wordpress 需要授权吗
  • 个人理财的网站开发天津 公司网站建设
  • 做电脑游戏破解的网站大宗交易平台软件
  • 男女做暖暖视频免费网站网络营销策划案ppt
  • 普通网站 多大空间网站开发报告参考文献
  • 来宾住房和城乡建设网站pc网站建设哪
  • WordPress一键开启全站SSL东莞企业网站建设公司
  • 青海省公路建设管理局官方网站wordpress 加入地图
  • 建湖专业做网站的公司如何制作wordpress网站地图