大型网站服务器多少钱,南京奥体建设公司,十堰seo优化服务,协会网站建设必要性Transactional的底层是如何实现的
底层是通过动态代理实现的。Spring Boot 在运行时会生成一个代理对象#xff0c;该代理对象被注解的方法调用#xff0c;并在方法调用前后进行事务管理#xff0c;事务管理包括开启事务#xff0c;提交事务或回滚事务等操作。 1开启事务 …Transactional的底层是如何实现的
底层是通过动态代理实现的。Spring Boot 在运行时会生成一个代理对象该代理对象被注解的方法调用并在方法调用前后进行事务管理事务管理包括开启事务提交事务或回滚事务等操作。 1开启事务 2执行业务逻辑 3提交/回滚事务 Transational中常见的参数有哪些
value-指定bean的名称
指定事务管理器的 bean 名称。当应用中存在多个事务管理器时可以通过该参数指定要使用的事务管理器
Transactional(value myTransactionManager)
public void someMethod() {// 业务逻辑
} propagation-指定Spring事务的传播行为
指定事务的传播行为即当一个事务方法被另一个事务方法调用时事务如何进行传播。Spring 定义了 7 种传播行为常用的有以下几种
Propagation.REQUIRED默认值如果当前存在事务则加入该事务如果当前没有事务则创建一个新的事务。Propagation.REQUIRES_NEW无论当前是否存在事务都会创建一个新的事务并且挂起当前事务如果存在。Propagation.NOT_SUPPORTED以非事务方式执行操作如果当前存在事务则挂起当前事务。Propagation.SUPPORTS如果当前存在事务则加入该事务如果当前没有事务则以非事务方式执行。Propagation.MANDATORY表示该方法必须在一个事务中运行如果当前没有事务则抛出异常。Propagation.NEVER表示该方法不能在一个事务中运行如果当前存在事务则抛出异常。Propagation.NESTED如果当前存在事务则在嵌套事务内执行如果当前没有事务则创建一个新的事务
Transactional(propagation Propagation.REQUIRES_NEW)
public void someMethod() {// 业务逻辑
} timeout-事务的超时时间
Transactional(timeout 5)
public void someMethod() {// 业务逻辑
} readOnly-事务只读不可进行写操作
Transactional(readOnly true)
public void someMethod() {// 只读业务逻辑
} rollbackFor-遇到哪些异常回滚
指定哪些异常类型会导致事务回滚。可以指定多个异常类型用逗号分隔
Transactional(rollbackFor {SQLException.class, MyCustomException.class})
public void someMethod() throws SQLException, MyCustomException {// 业务逻辑
} 什么情况会导致Transactional失效
1.添加到非public方法上
2.使用try catch处理异常
3.调用类内部的Transactional注解嵌套使用
4.事务的传播机制使用不当
5.数据库不支持事务 为什么Transational注解内部调用会导致事务失效呢
Spring 的 Transactional 注解是基于 AOP面向切面编程实现的。AOP 通过代理模式为目标对象创建代理对象在代理对象中织入事务管理的逻辑例如在方法调用前后开启、提交或回滚事务。
当外部调用带有 Transactional 注解的方法时实际上是调用的代理对象的方法代理对象会处理事务相关的操作
当在同一个类的一个方法中调用另一个带有 Transactional 注解的方法时这种调用属于内部调用
在内部调用时并没有经过代理对象而是直接调用了目标对象的方法绕过了 AOP 代理的事务增强逻辑从而导致事务失效 为什么参数rollbackFor要用Exception.class
如果不配置Exception.class的话事务只会遇到RunTimeException的时候回滚
如果配置了的话那么事务遇到非运行时异常时也回滚
也就是我们的Exception包含了所有异常这个的意思是我们遇到异常就回滚而不是遇到特定的运行时异常RunTimeException的时候回滚 如果想要嵌套事务调用Transational修饰的方法生效该怎么办
方法一注入自身 Bean
在类中通过依赖注入自身的 Bean然后使用注入的 Bean 进行内部方法调用这样就可以通过代理对象调用方法使事务注解生效
因为我们Bean注入了所以这个对象可以通过代理对象调用方法
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;Service
public class UserService {// 注入自身的 BeanAutowiredprivate UserService self;public void outerMethod() {// 通过注入的 Bean 调用带有 Transactional 注解的方法self.innerMethod();}Transactionalpublic void innerMethod() {// 业务逻辑System.out.println(执行内部方法的业务逻辑事务生效);}
} 方法二使用 AopContext.currentProxy() 获取代理对象
在配置类中开启 exposeProxy true之后在代码里使用 AopContext.currentProxy() 获取当前代理对象再通过代理对象调用方法
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;// 配置类开启 exposeProxy
Configuration
EnableAspectJAutoProxy(exposeProxy true)
class AopConfig {// 可以添加其他配置
}Service
public class UserService {public void outerMethod() {// 获取代理对象并调用带有 Transactional 注解的方法((UserService) AopContext.currentProxy()).innerMethod();}Transactionalpublic void innerMethod() {// 业务逻辑System.out.println(执行内部方法的业务逻辑事务生效);}
} 方法三getBean方法获取自身Bean实例
这种方法是和注入Bean是一样的
借助 ApplicationContext 获取 Bean 实例。首先要将 ApplicationContext 注入到服务类中然后使用 getBean 方法获取自身 Bean 实例再通过该实例调用带有 Transactional 注解的方法
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;Service
public class UserService implements ApplicationContextAware {private ApplicationContext applicationContext;Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext applicationContext;}public void outerMethod() {// 通过 getBean 方法获取自身 Bean 实例UserService self applicationContext.getBean(UserService.class);// 调用带有 Transactional 注解的方法self.innerMethod();}Transactionalpublic void innerMethod() {// 业务逻辑System.out.println(执行内部方法的业务逻辑事务生效);}
}