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

保定设计网站网站建设报表明细

保定设计网站,网站建设报表明细,给传销做网站什么罪,建设微信商城网站制作最近在工作中遇到了两个关于事务操作的问题,顺便就着这两个问题又回顾了一遍Spring的事务相关的操作,想着一次性把这个问题研究明白了,后续使用事务的时候也能踏实点,让事务发挥真实的作用 什么是事务?什么是事务管理…

最近在工作中遇到了两个关于事务操作的问题,顺便就着这两个问题又回顾了一遍Spring的事务相关的操作,想着一次性把这个问题研究明白了,后续使用事务的时候也能踏实点,让事务发挥真实的作用

什么是事务?什么是事务管理?什么是Spring事务

什么是事务?事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用,关乎数据准确性的地方我们一定要用到事务,防止业务逻辑出错。

什么是事务管理,事务管理对于企业应用而言至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失

关于事务的基本概念和定义可以参照我的另一篇Blog:【Spring学习笔记 九】Spring声明式事务管理实现机制。Sping事务简而言之就是一种JTA事务,这里不再详细展开。

一个用来演示的例子

我们还是沿用:【Spring学习笔记 九】Spring声明式事务管理实现机制这篇文章中的例子,只不过为了更贴近工作实战,这里我重构了一下代码实现。

单元测试入口

package com.example.springboot;import com.example.springboot.model.Person;
import com.example.springboot.service.PersonAggService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;@SpringBootTest
class SpringbootApplicationTests {@Resourceprivate PersonAggService personAggService;@Testpublic void springTransTest() {Person person = new Person();person.setUsername("wcong");person.setAge(30);person.setEmail("111111@qq.com");person.setPassword("111111");person.setPhone(11111111);person.setHobby("跳远");personAggService.addPerson(person, 100086L);}
}

聚合的Service方法

package com.example.springboot.service;import com.example.springboot.model.Person;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** @author tianmaolin004* @date 2023/8/6*/
@Service
public class PersonAggService {@Resourceprivate PersonService personService;@Resourceprivate PersonMaintainService personMaintainService;public void addPerson(Person person, Long creatorId) {//本地新增人员personService.insert(person);//保存人员创建者personMaintainService.savePersonCreator(creatorId);}
}

数据服务方法

package com.example.springboot.service;import com.example.springboot.dao.PersonDao;
import com.example.springboot.model.Person;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.List;@Service
public class PersonService {@ResourcePersonDao personDao;public List<Person> getPersonList() {return personDao.getPersonList();}public Person getPersonById(Integer id) {return personDao.getPersonById(id);}public void insert(Person person) {personDao.insert(person);}}

人员维护人添加方法

package com.example.springboot.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** @author tianmaolin004* @date 2023/8/6*/
@Service
public class PersonMaintainService {@Transactional(rollbackFor = Exception.class)public void savePersonCreator(Long userId) {System.out.println("保存人员创建者失败" + userId);throw new RuntimeException();}
}

数据表落库

在这里插入图片描述

不使用事务的情况

不使用事务的情况虽然单元测试报错了
在这里插入图片描述

但是数据库落库还是成功了:
在这里插入图片描述

遇到的两个事务问题

依据以上的基本case示例,模拟我遇到的两个问题和解决方案

Transaction rolled back because it has been marked as rollback-only

为了保证整体数据与预期一致可以回滚,我使用了事务,首先在外层加事务:

   @Transactional(rollbackFor = Exception.class)public void addPerson(Person person, Long creatorId) {//本地新增人员personService.insert(person);try {//发送人员同步到下游系统personMaintainService.savePersonCreator(creatorId);} catch (Exception e) {System.out.println("保存人员维护人异常但是被catch住了");}}

同时呢人员创建人这块我认为这里不需要报错阻塞整体操作,如果这里有问题只要有日志记录就行了,我通过巡检检查关注到即可,所以对这块代码加了try catch,但是呢因为内部代码不知道是谁写的也加了事务,

@Service
public class PersonMaintainService {@Transactional(rollbackFor = Exception.class)public void savePersonCreator(Long userId) {System.out.println("保存人员创建者失败" + userId);throw new RuntimeException();}
}

因为它们用的都是默认的传播机制,所以可以看做一个事务,使用REQUIRED传播模式,addAndSendPerson和savePersonCreator在同一个事务里面,savePersonCreator抛出异常要回滚,addAndSendPerson try Catch了异常正常执行commit,同一个事务一个要回滚,一个要提交,会报read-only异常,结果就是全部回滚,而外层所以这里就会出现rollback-only
在这里插入图片描述
解决方法有两种,一种是

干掉内层事务

内层的savePersonCreator事务干掉,这时数据也能落库成功了,事实上因为JTA的事务是有非常强的业务含义的,所以对于DAO层或简单的数据操作指令,不要加事务,否则对于较长的外部调用链路,会在传播过程中导致意外情况发生
在这里插入图片描述

内层声明为新事务

还有一种解决思路就是内层的事务声明为新事务

package com.example.springboot.service;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;/*** @author tianmaolin004* @date 2023/8/6*/
@Service
public class PersonMaintainService {@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)public void savePersonCreator(Long userId) {System.out.println("保存人员创建者失败" + userId);throw new RuntimeException();}
}

声明后再跑单测:
在这里插入图片描述
数据也落库成功了,因为是两个独立事务,所以内层事务遇到异常回滚,外层事务捕获到了异常catch住了,没有继续回滚

事务设置为什么不生效?

还有个例子是方法设置了事务但是不生效,我们再调整下以上的代码,模拟一种场景:savePerson要执行很多事项,但是不希望saveDate的执行异常回滚影响整体回滚,所以saveDate中的核心数据操作被try catch,并且声明内部的savePersonCreator方法为新事务,符合上边我们提到的那种场景,这种情况下理论上savePersonCreator抛出异常后会使 personDao.insert(person);回滚,数据不能写入

@SpringBootTest
class SpringbootApplicationTests {@Resourceprivate PersonAggService personAggService;@Testpublic void springTransTest() {Person person = new Person();person.setUsername("wcong");person.setAge(30);person.setEmail("111111@qq.com");person.setPassword("111111");person.setPhone(11111111);person.setHobby("跳远");personAggService.savePerson(person, 100086L);}}@Service
public class PersonAggService {@ResourcePersonDao personDao;@Transactional(rollbackFor = Exception.class)public void savePerson(Person person, Long creatorId) {System.out.println("执行其它事项");saveDate(person, creatorId);}@Transactional(rollbackFor = Exception.class)public void saveDate(Person person, Long creatorId) {//本地新增人员try {savePersonCreator(person, creatorId);} catch (Exception e) {System.out.println("捕获到创建人员异常");}}@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)public void savePersonCreator(Person person, Long userId) {personDao.insert(person);System.out.println("保存人员创建者失败" + userId);throw new RuntimeException();}
}

但事实上,数据库写入数据能成功:
在这里插入图片描述
数据库数据写入成功了
在这里插入图片描述
这是因为:Spring中事务的默认实现使用的是AOP,也就是代理的方式,如果大家在使用代码测试时,同一个Service类中的方法相互调用需要使用注入的对象来调用,不要直接使用this.方法名来调用,this.方法名调用是对象内部方法调用,不会通过Spring代理,也就是事务不会起作用,所以实际上saveDate和savePersonCreator的事务都没有生效

把需要成为事务的方法单独抽出来

上述代码我们把需要有事务机制的savePersonCreator单独抽到一个方法中

@SpringBootTest
class SpringbootApplicationTests {@Resourceprivate PersonAggService personAggService;@Testpublic void springTransTest() {Person person = new Person();person.setUsername("wcong");person.setAge(30);person.setEmail("111111@qq.com");person.setPassword("111111");person.setPhone(11111111);person.setHobby("跳远");personAggService.savePerson(person, 100086L);}}@Service
public class PersonAggService {@ResourcePersonService personService;@Transactional(rollbackFor = Exception.class)public void savePerson(Person person, Long creatorId) {System.out.println("执行其它事项");saveDate(person, creatorId);}@Transactional(rollbackFor = Exception.class)public void saveDate(Person person, Long creatorId) {//本地新增人员try {personService.savePersonCreator(person, creatorId);} catch (Exception e) {System.out.println("捕获到创建人员异常");}}
}@Service
public class PersonService {@ResourcePersonDao personDao;public List<Person> getPersonList() {return personDao.getPersonList();}public Person getPersonById(Integer id) {return personDao.getPersonById(id);}@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)public void savePersonCreator(Person person, Long userId) {personDao.insert(person);System.out.println("保存人员创建者失败" + userId);throw new RuntimeException();}
}

这样savePersonCreator的事务就生效了,数据没有插入成功

Spring事务的更多传播机制

以上两个示例是真实工作中遇到的,基于安全原则模拟了两个类似的case,其实spring还有更多的花式的事务使用机制,可以参照带你读懂Spring 事务——事务的传播机制

总结一下

照例总结一下,在单一的数据操作方法不要加事务,事务应该是一系列操作指令的聚合,添加了细粒度的事务可能会导致上层使用者在方法添加事务时产生了非预期的传播机制。当然如果内外层的方法调用都很复杂,则基于自己的预期进行考虑,如果不希望内层方法影响外层方法,可以使用外层方法异常捕获加内层事务的REQUIRES_NEW传播机制解决。需要注意的是Spring的事务是基于AOP实现的,所以对象内部方法调用,不会通过Spring代理,也就是事务不会起作用,这点非常重要。

http://www.yayakq.cn/news/892800/

相关文章:

  • 网站首页 seo深圳最新项目
  • 域名买好怎么开始做网站线上投票怎么做
  • 学习php网站建设桂林市区好玩的地方
  • 东莞百度搜索网站排名公司取名软件
  • 济南营销网站建设公司网站放自己服务器备案
  • 毕业设计做一个网站怎么做网站建设进度计划
  • 寿光网站建设价格微信指数是搜索量吗
  • 工行网站跟建设网站区别松原建设网站
  • 网站有风险提示怎么办小女孩做网站
  • 寿光网站优化中国建设银行信用卡网站
  • 长沙长沙网站建设wordpress阅读积分
  • 做网站的准备什么360收录提交入口
  • 永康网站建设制作自助网站建设公司电话
  • 四川建设厅电话网站seo优化的作用
  • 辽宁住房和建设厅网站首页马云谈2025的房价3500
  • 网站建设分哪几种做业精灵官方网站
  • 西安建设高端网站网站中图片加水印
  • 网站源代码怎么下载厦门网站建设培训机构
  • 做标书要不要做网站电商平台设计包括哪些内容
  • 关于个人工作室网站模板dede换网站
  • .net 网站开发项目结构手机怎样建立网站
  • 威海网站建设排名榜嘉兴市做网站优化
  • 网站建设中 什么意思襄阳网站建设首选公司哪家好
  • 在线动画手机网站模板下载安装苏州app开发
  • 天津网站建设推广服务网站定制化开发
  • 企业手机建站系统青岛销售系统app开发
  • 一起做单网站怎么样门户网站建设工作总结
  • 长春网站优化方案如何自己建公司网站
  • 站长 网站对比十大软件公司
  • 干网站建设销售怎么样互联网怎么打广告推广