已经有域名,如何建设网站,北京网站制作工具,友情链接网站源码,网站关键词工具有哪些默认 Transactional 注解式事务
#xff08;1#xff09;EnableTransactionManagement
正常情况下#xff0c;我们是需要在 ApplicationConfig 类加上 EnableTransactionManagement 注解才能开启事务管理。通过 DataSource 的研究步骤 spring.factories 里面默认加载 Tran…默认 Transactional 注解式事务
1EnableTransactionManagement
正常情况下我们是需要在 ApplicationConfig 类加上 EnableTransactionManagement 注解才能开启事务管理。通过 DataSource 的研究步骤 spring.factories 里面默认加载 TransactionAutoConfiguration 类而我们看源码其里面已经加了此注解默认采用的 AdviceMode.PROXY所以默认情况的事务管理机制是代理方式的通过添加 Transactional 注解式配置方法查看 SimpleJpaRepository
Repository
Transactional(readOnly true)
public class SimpleJpaRepositoryT, ID implements JpaRepositoryT, ID, JpaSpecificationExecutorT {...}
所以每个 Respository 的方法是都是有默认的只读事务的。
2我们来查看一下 Transactional 源码
Target({ElementType.METHOD, ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Inherited
Documented
public interface Transactional {AliasFor(transactionManager)String value() default ;AliasFor(value)String transactionManager() default ;Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class? extends Throwable[] rollbackFor() default {};String[] rollbackForClassName() default {};Class? extends Throwable[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}
Transactional 注解中常用参数说明 参数名称 功能描述 readOnly rollbackFor rollbackForClassName noRollbackFor noRollbackForClassName propagation isolation timeout transactionManager/value
3propagation传播行为
所谓事务的传播行为是指如果在开始当前事务之前一个事务上下文已经存在此时有若干选项可以指定一个事务性方法的执行行为。
可以看 org.springframework.transaction.annotation.Propagation 枚举类中定义了 7 个表示传播行为的枚举值
public enum Propagation { REQUIRED(0), SUPPORTS(1), MANDATORY(2), REQUIRES_NEW(3), NOT_SUPPORTED(4), NEVER(5), NESTED(6); }
REQUIRED如果当前存在事务则加入该事务如果当前没有事务则创建一个新的事务。SUPPORTS如果当前存在事务则加入该事务如果当前没有事务则以非事务的方式继续运行。MANDATORY如果当前存在事务则加入该事务如果当前没有事务则抛出异常。REQUIRES_NEW创建一个新的事务如果当前存在事务则把当前事务挂起。NOT_SUPPORTED以非事务方式运行如果当前存在事务则把当前事务挂起。NEVER以非事务方式运行如果当前存在事务则抛出异常。NESTED如果当前存在事务则创建一个事务作为当前事务的嵌套事务来运行如果当前没有事务则该取值等价于REQUIRED。
设置方法通过使用propagation属性设置例如
Transactional(propagation Propagation.REQUIRED)
4Isolation 隔离级别
隔离级别是指若干个并发的事务之间的隔离程度与我们开发时候主要相关的场景包括脏读取、重复读、幻读。
我们可以看 org.springframework.transaction.annotation.Isolation 枚举类中定义了四个表示隔离级别的值
public enum Propagation {REQUIRED(0),SUPPORTS(1),MANDATORY(2),REQUIRES_NEW(3),NOT_SUPPORTED(4),NEVER(5),NESTED(6);
}
DEFAULT这是默认值表示使用底层数据库的默认隔离级别对大部分数据库而言通常这值就是READ_COMMITTED。READ_UNCOMMITTED该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读因此很少使用该隔离级别。READ_COMMITTED该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读这也是大多数情况下的推荐值。REPEATABLE_READ该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。SERIALIZABLE所有的事务依次逐个执行这样事务之间就完全不可能产生干扰也就是说该级别可以防止脏读、不可重复读以及幻读但是这将严重影响程序的性能。通常情况下也不会用到该级别。
设定方法为通过使用 isolation 属性设置例如
Transactional(isolation Isolation.DEFAULT)
5所以 Spring Boot 的这种默认机制只需要在我们用事务时在方法上或者此方法的类上加上 Transactional注解即可。
而实际工作中我们一般都要在 Service 层的某些方法上加事务以保证整个方法的事务。示例如下
Transactional(rollbackOn Exception.class)
public void saveUserInfo() throws Exception {userCustomerRepository.save(new UserCustomerEntity(jackzhangmail.com,jackzhang));userRepository.save(new UserInfoEntity(jack_test,name));throw new Exception(test);......//此方法体有多个repository的调用模拟异常事务会回滚的
}
6注意的几点
Transactional 只能被应用到 public 方法上对于其他非 public 的方法如果标记了 Transactional 也不会报错但方法没有事务功能。用 spring 事务管理器由 spring 来负责数据库的打开、提交、回滚默认遇到运行期例外throw new RuntimeException(注释);会回滚即遇到不受检查unchecked的例外时回滚而遇到需要捕获的例外throw new Exception(注释);不会回滚即遇到受检查的例外就是非运行时抛出的异常编译器会检查到的异常叫受检查例外或说受检查异常时需我们指定方式来让事务回滚要想所有异常都回滚要加上 Transactional( rollbackFor{Exception.class,其他异常})如果让 unchecked 例外不回滚Transactional(notRollbackForRunTimeException.class)。Transactional 注解应该只被应用到 public 可见度的方法上。如果你在 protected、private 或者 package-visible 的方法上使用 Transactional 注解它也不会报错但是这个被注解的方法将不会展示已配置的事务设置。Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而请注意仅仅 Transactional 注解的出现不足于开启事务行为它仅仅是一种元数据能够被可以识别 Transactional 注解和上述的配置适当的具有事务行为的 beans 所使用。上面的例子中其实正是 元素的出现开启了事务行为。Spring 团队的建议是你在具体的类或类的方法上使用 Transactional 注解而不要使用在类所要实现的任何接口上。当然可以在接口上使用 Transactional 注解但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的这就意味着如果你正在使用基于类的代理时那么事务的设置将不能被基于类的代理所识别而且对象也将不会被事务代理所包装将被确认为严重的。因此请接受 Spring 团队的建议并且在具体的类上使用 Transactional 注解。事务有两种配置方法一种是我们现在说的显式的注解式事务当我们注解式事务下不加注解 service 方法上是没有任何事务的。还有一种是隐式事务ASPECTJ 的思路配置方法所以不是没有加 Transactional 注解就一定没有事务。
声明式事务又叫隐式事务或者叫 ASPECTJ 事务
配置方法
在实际工作中每个方法都让我们加上 Transactional 注解可能工作量有点大也有时候会忘所以经常看到有开发团队配置拦截式事务。虽然 spring 官方不太推荐。只需要在我们的项目中新增一个类 AspectjTransactionConfig 即可如下
Configuration
EnableTransactionManagement
public class AspectjTransactionConfig {public static final String transactionExecution execution (* com.jackzhang.example..service.*.*(..));Autowiredprivate PlatformTransactionManager transactionManager;Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor() {//指定一般要拦截哪些类AspectJExpressionPointcut pointcut new AspectJExpressionPointcut();pointcut.setExpression(transactionExecution);//配置advisorDefaultPointcutAdvisor advisor new DefaultPointcutAdvisor();advisor.setPointcut(pointcut);//指定不同的方法用不通的策略Properties attributes new Properties();attributes.setProperty(get*, PROPAGATION_REQUIRED,-Exception);attributes.setProperty(add*, PROPAGATION_REQUIRED,-Exception);attributes.setProperty(save*, PROPAGATION_REQUIRED,-Exception);attributes.setProperty(update*, PROPAGATION_REQUIRED,-Exception);attributes.setProperty(delete*, PROPAGATION_REQUIRED,-Exception);//创建InterceptorTransactionInterceptor txAdvice new TransactionInterceptor(transactionManager, attributes);advisor.setAdvice(txAdvice);return advisor;}
}
这样我们的 Service 就会自动拥有了事务可以加 Transactional 来覆盖全局的配置。