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

极路由4 做网站无锡整站百度快照优化

极路由4 做网站,无锡整站百度快照优化,写文的免费软件,淘宝关键词排名是怎么做的最近在工作中遇到了三个关于事务操作的问题#xff0c;顺便就着这三个问题又回顾了一遍Spring的事务相关的操作#xff0c;想着一次性把这个问题研究明白了#xff0c;后续使用事务的时候也能踏实点#xff0c;让事务发挥真实的作用 什么是事务#xff1f;什么是事务管理…最近在工作中遇到了三个关于事务操作的问题顺便就着这三个问题又回顾了一遍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(111111qq.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 ListPerson 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(111111qq.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(执行其它事项);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(111111qq.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(执行其它事项);try {personService.savePersonCreator(person, creatorId);} catch (Exception e) {System.out.println(捕获到创建人员异常);}} } Service public class PersonService {ResourcePersonDao personDao;public ListPerson 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的事务就生效了数据没有插入成功 问题三为什么会发生org.springframework.dao.CannotAcquireLockException 经过上一步的调整事务总算生效了这里我们对上述代码再做一个调整让内层和外层的事务都对同一张表进行操作代码清单如下 SpringBootTest class SpringbootApplicationTests {Resourceprivate PersonAggService personAggService;Testpublic void springTransTest() {Person person new Person();person.setUsername(wcong);person.setAge(30);person.setEmail(111111qq.com);person.setPassword(111111);person.setPhone(11111111);person.setHobby(跳远);personAggService.savePerson(person, 100086L);}} Service public class PersonAggService {ResourcePersonService personService;ResourcePersonDao personDao;Transactional(rollbackFor Exception.class)public void savePerson(Person person, Long creatorId) {System.out.println(执行其它事项);Person personOut new Person();personOut.setUsername(outPerson);personOut.setAge(30);personOut.setEmail(111qq.com);personOut.setPassword(111111);personOut.setPhone(11111111);personOut.setHobby(跳远);personDao.insert(personOut);try {personService.savePersonCreator(person, creatorId);} catch (Exception e) {System.out.println(捕获到创建人员异常);}}}Service public class PersonService {ResourcePersonDao personDao;public ListPerson 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();} }我们发现外部事务的数据提交成功而内部事务的异常被捕获了 同时这句话也没有打印出来说明还没有执行到手动抛异常的位置 外部事务数据正确落库 为了更细致的看我们把异常捕获干掉 SpringBootTest class SpringbootApplicationTests {Resourceprivate PersonAggService personAggService;Testpublic void springTransTest() {Person person new Person();person.setUsername(wcong);person.setAge(30);person.setEmail(111111qq.com);person.setPassword(111111);person.setPhone(11111111);person.setHobby(跳远);personAggService.savePerson(person, 100086L);}}Service public class PersonAggService {ResourcePersonService personService;ResourcePersonDao personDao;Transactional(rollbackFor Exception.class)public void savePerson(Person person, Long creatorId) {System.out.println(执行其它事项);Person personOut new Person();personOut.setUsername(outPerson);personOut.setAge(30);personOut.setEmail(111111qq.com);personOut.setPassword(111111);personOut.setPhone(11111111);personOut.setHobby(跳远);personDao.insert(personOut);personService.savePersonCreator(person, creatorId);} }Service public class PersonService {ResourcePersonDao personDao;public ListPerson 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);} } 其原因就是两个不同的事务对同一张表进行操作 事务的传播行为 Spring 允许定义事务的传播行为即在一个事务方法中调用另一个事务方法时如何处理事务。其中一种传播行为是 Propagation.REQUIRES_NEW它表示每次方法被调用时都会启动一个新的事务而不管是否已经存在一个事务。如果在嵌套事务中使用 Propagation.REQUIRES_NEW可能会导致内层事务与外层事务并发执行从而产生并发问题。于是抛出了获取锁失败的异常。为了方便大家看是不是一个问题把这个异常详细粘贴出来 而多次调用实验也表明有时候数据是会落库成功的所以就看内外事务的并发执行时机了。 org.springframework.dao.CannotAcquireLockException: ### Error querying database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction ### The error may exist in file [F:\JavaWeb\springboot\target\classes\mapper\personMapper.xml] ### The error may involve com.example.springboot.dao.PersonDao.insert-Inline ### The error occurred while setting parameters ### SQL: insert into person (id,username,password,age,phone,email,hobby) values (?,?,?,?,?,?,?) ### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction ; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transactionat org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:267)at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70)at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91)at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)at com.sun.proxy.$Proxy107.selectOne(Unknown Source)at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160)at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87)at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)at com.sun.proxy.$Proxy108.insert(Unknown Source)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)at com.sun.proxy.$Proxy109.insert(Unknown Source)at com.example.springboot.service.PersonService.savePersonCreator(PersonService.java:27)at com.example.springboot.service.PersonService$$FastClassBySpringCGLIB$$2df9c1a9.invoke(generated)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)at com.example.springboot.service.PersonService$$EnhancerBySpringCGLIB$$7b8fd37c.savePersonCreator(generated)at com.example.springboot.service.PersonAggService.savePerson(PersonAggService.java:32)at com.example.springboot.service.PersonAggService$$FastClassBySpringCGLIB$$7eb0a300.invoke(generated)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)at com.example.springboot.service.PersonAggService$$EnhancerBySpringCGLIB$$ec6485e1.savePerson(generated)at com.example.springboot.SpringbootApplicationTests.springTransTest(SpringbootApplicationTests.java:24)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)at java.util.ArrayList.forEach(ArrayList.java:1257)at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)at java.util.ArrayList.forEach(ArrayList.java:1257)at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Caused by: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transactionat com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123)at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:370)at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3461)at com.alibaba.druid.wall.WallFilter.preparedStatement_execute(WallFilter.java:663)at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3459)at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(FilterEventAdapter.java:440)at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3459)at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.execute(PreparedStatementProxyImpl.java:167)at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:497)at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64)at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:89)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)内部不声明新事务 解决方案一就是内部不声明新事务同一个事务下就不存在这个问题了 Service public class PersonService {ResourcePersonDao personDao;public ListPerson getPersonList() {return personDao.getPersonList();}public Person getPersonById(Integer id) {return personDao.getPersonById(id);}Transactional(rollbackFor Exception.class)public void savePersonCreator(Person person, Long userId) {personDao.insert(person);} }在运行一下发现两条记录都插入成功了 内部事务抽出来 还有一种方式就是不要搞事务嵌套把内部方法抽出来和外层的平行内部方法执行依赖的入参由原外部事务的返回值给出做到不相互依赖。 问题场景 基于保密原则原始代码不能贴出来所以用一些示例表示其实真实场景比较复杂我们正在做的事情是数据迁移一个加盟商可能带一堆门店迁移它们都有公司的数据并且我们希望一个门店迁移失败不影响整体【加盟商是外层门店是内层】 所以我开始在加盟商和门店的同步方法都加了事务默认传播机制然后catch门店抛出的异常于是就导致了问题一Transaction rolled back because it has been marked as rollback-only为了解决问题一我将门店的同步方法声明为新事务结果发现事务不生效原来是我解决问题二的时候把门店方法放回到了加盟商同步方法一个类导致注解不生效把门店方法又挪出来后又发现数据同步时会偶发org.springframework.dao.CannotAcquireLockException发现是加盟商和门店都对公司表有插入行为产生了并发死锁。于是我就把门店的同步单独提出来和加盟商同步平级按顺序执行门店需要的参数由加盟商执行结果返回同时每个门店执行加了catch只影响自己 这样总算解决了问题表面看好像很简单但经历了一段时间的排查过程总结一句话事务是一系列紧密相关行为的集合。按这个定义其实我早就应该想到把门店的同步抽出来不要搞什么嵌套事务。不过怎么说排查过程中也加深了对Spring事务的理解吧 Spring事务的更多传播机制 以上两个示例是真实工作中遇到的基于安全原则模拟了两个类似的case其实spring还有更多的花式的事务使用机制可以参照带你读懂Spring 事务——事务的传播机制 总结一下 照例总结一下在单一的数据操作方法不要加事务事务应该是一系列操作指令的聚合添加了细粒度的事务可能会导致上层使用者在方法添加事务时产生了非预期的传播机制。当然如果内外层的方法调用都很复杂则基于自己的预期进行考虑如果不希望内层方法影响外层方法可以使用外层方法异常捕获加内层事务的REQUIRES_NEW传播机制解决。需要注意的是Spring的事务是基于AOP实现的所以对象内部方法调用不会通过Spring代理也就是事务不会起作用这点非常重要。
http://www.pierceye.com/news/113018/

相关文章:

  • linux系统怎么做网站女生去住建局好不好
  • 自己搭建环境建设网站网站开发温州
  • 下沙做网站软件erp系统的主要功能
  • 郑州网站建设专家最新手机排行榜2021
  • 宠物店网站建设策划书重庆网站建设 红旗河沟
  • 一般网站自己可以做播放器吗最简单的一个网站开发
  • 网站的开发商务网站安全方案设计
  • 如何建立网站教材漳诈网站建设
  • 开家网站设计公司广州网站建设app开发
  • 建站服务公司网站源码成都游戏外包公司排名
  • 呼伦贝尔网站建设呼伦贝尔astro wordpress
  • 做网站需要好多钱专业制作广告字
  • 网站建设的需要是什么seo营销方案
  • 网站开发服务的协议wordpress自动翻译
  • 网站网站制作400多少钱wordpress 会员积分
  • 天津网站建设首选津坤科技做视频网站用什么好处
  • wordpress ffmpegsem seo是什么意思呢
  • 九江建网站的公司做废钢那个网站好
  • 做网站官网需多少钱wordpress查看访问者ip
  • 美食网站php源码wordpress 文章消失
  • 四川住房和城乡建设厅网站万达网站建设
  • 网站运营一般做那些分析快手营销软件
  • 重庆大渡口建设网站站群搭建
  • 2018年网站开发技术动漫电影做英语教学视频网站
  • 设备管理系统网站模板网站开发基础知识试题
  • wordpress建立好的网站万能搜索网站
  • 杭州 高端网站建设wordpress 不显示ip
  • 校考前做试题的网站池州哪里有做网站
  • 四合一小说网站搭建教程WordPress主题资源
  • 网站制作com台州网站哪家专业