当前位置: 首页> 汽车> 车展 > 网站建设与制作实验报告_竞价排名名词解释_网络营销公司名称_专业seo整站优化

网站建设与制作实验报告_竞价排名名词解释_网络营销公司名称_专业seo整站优化

时间:2025/7/13 4:29:45来源:https://blog.csdn.net/u012453843/article/details/147105955 浏览次数: 0次
网站建设与制作实验报告_竞价排名名词解释_网络营销公司名称_专业seo整站优化

       这是一道非常常见的面试题了,了解这个对于我们平常开发也是很有帮助的,下面总结一下导致事务失效的场景。

一、内部方法调用

       比如我们看如下的例子,我们的Teacher类,假如执行这个类中的saveData()方法,这个方法上没有加事务注解,这个方法内部调用了batchInsert();方法,这个batchInsert()方法上面有@Transactional注解。这种场景下事务是不生效的。

1.1 失败原因

       像Teacher类被spring托管创建时,是以CGLIB动态代理的方式生成代理对象,但是由于一开始调用的是非事务方法,非事务方法内部调用带事务的方法,这时真正去执行batchInsert()方法是被代理的这个Teacher类本身,并不是代理对像,因此事务失效了。       

package com.example.bean;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class Teacher {public void saveData() {this.batchInsert();}@Transactionalpublic void batchInsert() {//真正执行保存数据}
}

1.2 解决方案

        那么如何解决这个问题?常见有两种解决方案

1.2.1 事务方法剥离到其他类

          将batchInsert()方法单独拆分到另一个类中,比如CommonSaveData类,如下所示

package com.example.bean;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class CommonSaveData {@Transactionalpublic void batchInsert() {//真正执行保存数据}
}

         而Teacher类代码如下,可以看到把CommonSaveData类通过依赖注入的方式给注入进来了,然后通过调用commonSaveData.batchInsert();来保存数据。这种场景事务就生效了,因为我们此时拿到的CommonSaveData对象是代理对象,而且是我们这时调用不再是同类调用了,跨类调用,并且这个方法上有@Transactional注解,事务是有效的。

package com.example.bean;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class Teacher {@Autowiredprivate CommonSaveData commonSaveData;public void saveData() {commonSaveData.batchInsert();}}
1.2.2 在同类中获取代理对象

         要达到目的,首先我们得在这个类上加@EnableAspectJAutoProxy(exposeProxy = true)注解,作用是启用暴露代理对象。

       然后就是通过(Teacher)AopContext.currentProxy();这样获取到Teacher类的代理对象,然后由代理对象去调用带有事务注解的方法batchInsert(),此时事务就是有效的。

package com.example.bean;import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class Teacher {public void saveData() {Teacher proxy = (Teacher) AopContext.currentProxy();proxy.batchInsert();}@Transactionalpublic void batchInsert() {//真正执行保存数据}
}

二、异常未正常抛出

2.1 失效原因

        我们在加事务注解的方法中,默认情况只有抛出的异常是RuntimeException或者Error异常时才会回滚,假如我们抛出的异常是其它类型,那么默认情况下会导致事务失效,如下例子。

package com.example.bean;import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.concurrent.TimeoutException;@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class Teacher {public void saveData() throws TimeoutException {Teacher proxy = (Teacher) AopContext.currentProxy();proxy.batchInsert();}@Transactionalpublic void batchInsert() throws TimeoutException {//真正执行保存数据throw new TimeoutException();}
}

2.2 解决方案

        像下面代码,我们在@Transactional注解中添加了(rollbackFor = TimeoutException.class)这样就可以覆盖spring默认事务回滚异常策略,从而当抛出TimeoutException时也支持事务回滚。

        如果你这个带事务的方法想要在任何异常场景都自动回滚,那么就直接设置成@Transactional(rollbackFor = Exception.class)

package com.example.bean;import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.concurrent.TimeoutException;@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class Teacher {public void saveData() throws TimeoutException {Teacher proxy = (Teacher) AopContext.currentProxy();proxy.batchInsert();}@Transactional(rollbackFor = TimeoutException.class)public void batchInsert() throws TimeoutException {//真正执行保存数据throw new TimeoutException();}
}

三、非public方法

        如果我们事务注解加到了私有方法上,如下所示,batchInsert方法是protected修饰的,不是public,这种情况事务会失效,失效原因如下。

3.1  失效原因

3.1.1 CGLIB代理的继承限制

       CGLIB通过生成目标类的子类作为代理对象,并重写父类的public方法来实现拦截。由于非public方法无法被重写,导致代理对象无法插入事务逻辑。

3.1.2 Spring AOP的默认行为

       Spring AOP默认仅拦截public方法,这是出于性能和安全性的考虑。

package com.example.bean;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class Teacher {@Transactionalprotected void batchInsert() {//真正执行保存数据}
}

解决方案:

           上面的例子中只要将protected改为public即可。

四、数据库引擎不支持索引

4.1 失效原因       

       我们一般开发场景中数据库设计时都是使用innodb作为引擎的,但是可能有些特殊场景的表使用的是myisam引擎,我们都知道数据库中myisam引擎是不支持事务的。

4.2 解决方案:

       将数据库引擎由myisam改为innodb即可解决问题。

五、未启用事务管理

5.1 失效原因

       我们在spring配置类中没有添加@EnableTransactionManagement注解,这样的话,就是没有开启事务功能,这种情况我们无论如何加@Transactional注解都是无效的了。

5.2 解决方案

       在我们的主配置类上加上@EnableTransactionManagement注解,即可开启事务支持,从而解决事务不生效的问题。

六、传播行为不当

6.1 失效原因

        我们默认给事务注解添加的传播属性不准确,如下所示,在batchInsert方法上,事务注解指定的传播属性是Propagation.NEVER,这时事务会被禁止。还有一个是将传播属性设置为了Propagation.NOT_SUPPORTED,这个是将事务挂起了。

package com.example.bean;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import java.util.concurrent.TimeoutException;@Service
public class Teacher {@Transactional(propagation = Propagation.NEVER)protected void batchInsert() throws TimeoutException {//真正执行保存数据}
}

6.2 解决方案

     我们修改传播行为Propagation.REQUIRED,这样就可以解决事务失效的问题了

七、异常被捕获未抛出

7.1 失效原因

      在try catch中捕获异常但并未再抛出,事务无法感知异常导致事务失效。

7.2 解决方案

      我们在捕获到异常后,要么重新抛出,要么在catch中自己处理回滚逻辑。

八、类未被spring管理

8.1  失效原因

       比如我们上面提到的Teacher类上没有加@Service注解,这样spring无法自动帮我们管理这个bean,也就无法自动帮我们生成代理类,或者我们不是拿的spring帮我们生成的Teacher对象,而是自己又通过代码new 出来了一个Teacher对象,这个new出来的对象不是代理对象,因此也就事务失效了。

8.2  解决方案

       我们在我们的Teacher类上正常加上@Service注解,让它被spring容器纳管,这样便可以解决事务失效问题。

九、多线程场景

9.1 失效原因

       假如在我们一个大的事务中,通过线程池异步去处理一些业务逻辑了,那么假如主线程发生异常,那么被线程处理的数据是无法发生回滚的。同理,如果是线程里面出现失败回滚,但主线程是无法回滚的。因为线程中的事务跟主线程中的事务压根就不是同一个。

9.2  解决方案

       避免跨线程操作,或者使用成熟的分布式事务框架来解决,比如Seta、TCC等。

       以上便是最常见的事务失效的场景。

关键字:网站建设与制作实验报告_竞价排名名词解释_网络营销公司名称_专业seo整站优化

版权声明:

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

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

责任编辑: