事务是逻辑上的一组操做,要么都执行,要么都不执行java
程序是否支持事务是取决于数据库是否支持事务spring
MySQL是如何保证原子性的:sql
恢复机制是依赖回滚日志实现的数据库
编程式事务,在代码中硬编码(不推荐使用)编程
声明式事务,在配置文件中配置(推荐使用),代码侵入性小,经过AOP实现后端
Spring中事务管理相关的最重要的三个接口以下服务器
Spring并不直接管理事务,而是提供了多种事务管理器。spring经过该事务管理接口为多个平台提供了对应的事务管理器,具体的实现就是各个平台本身的事情了。并发
该接口主要是将事务管理行为抽象出来,而后不一样的平台去实现它,能够保证提供给外部的行为不变,方便咱们扩展。性能
该类定义了一些基本的事务属性。优化
事务属性包括了五个方面
该接口用来记录事务的状态,该接口定义了一组方法,用来获取或判断事务的相应状态信息。
public interface TransactionStatus{ boolean isNewTransaction(); // 是不是新的事务 boolean hasSavepoint(); // 是否有恢复点 void setRollbackOnly(); // 设置为只回滚 boolean isRollbackOnly(); // 是否为只回滚 boolean isCompleted; // 是否已完成 }
事务传播行为是为了解决业务层之间互相调用的事务问题。
当事务方法被另外一个事务方法调用时,必须制定事务应该如何传播。例如:方法可能继续在现有的事务中运行,也可能开启一个新事务,并在本身的事务中运行。
事务传播行为类型 | 说明 | 是否支持当前事务 |
---|---|---|
REQUIRED | 若是当前存在事务,则加入该事务;若是当前没有事务,则建立一个新的事务。(默认状况) | ✔ |
SUPPORTS | 若是当前存在事务,则加入该事务;若是当前没有事务,则以非事务的方式继续运行。 | ✔ |
MANDATORY | 若是当前存在事务,则加入该事务;若是当前没有事务,则抛出异常。(mandatory:强制性) | ✔ |
REQUIRES_NEW | 建立一个新的事务,若是当前存在事务,则把当前事务挂起。 | ✘ |
NOT_SUPPORTED** | 以非事务方式运行,若是当前存在事务,则把当前事务挂起。 | ✘ |
NEVER | 以非事务方式运行,若是当前存在事务,则抛出异常。 | ✘ |
NESTED | 若是当前存在事务,则建立一个事务做为当前事务的嵌套事务来运行;若是当前没有事务,则该取值等价于REQUIRED。 | ☹ |
TransactionDefinition接口中定义了五个表示隔离级别的常量。
所谓事务超时,就是指一个事务所容许执行的最长时间,若是超过该时间限制但事务尚未完成,则自动回滚事务。在TransactionDefinition中以int的值来表示超时时间,其单位是秒,默认值是-1
对于只有读取数据查询的事务,能够指定事务类型为readonly,即只读属性。只读事务不涉及数据的修改,数据库会提供一些优化手段,适合用在有多条数据库查询操做的方法中。
MySQL默认对每个新创建的链接都启用了autocommit模式,在该模式下,每个发送到MySQL服务器的sql语句都会在一个单独的事务中处理,执行结束后会自动提交事务,并开启一个新事务。
若是不加Transaction,每条sql会开启一个单独的事务,中间被其余事务改了数据,都会实时读取到最新值。
若是你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询 SQL 必须保证总体的读一致性,不然,在前条 SQL 查询以后,后条 SQL 查询以前,数据被其余用户改变,则该次总体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持
这些规则定义了那些异常会致使事务回滚而那些不会。默认状况下,事务只有遇到了运行时异常(RuntimeException的子类)时才会回滚,Error也会致使事务回滚,可是在遇到检查型(Checked)异常时不会回滚。
若是要定义你回滚的异常类型能够这样
@Transactional(rollbackFor = MyException.class)
@Target({ElementType.TYPE, ElementType.METHOD}) @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的经常使用配置参数总结
属性名 | 说明 |
---|---|
propagation | 事务的传播方式,默认REQUIRED |
isolation | 事务的隔离级别,默认DEFAULT |
timeout | 事务超时时间,默认-1(不会超时)。若是超过期间限制没有完成,则自动回滚 |
readOnly | 指定事务是否只读,默认为false |
rollbackFor | 用于指定可以触发事务回滚的异常类型,而且能够指定多个异常类型 |
@Transaction的工做机制是基于AOP实现的,AOP有事使用动态代理实现的。若是目标对象实现了接口,默认状况下采用JDK的动态代理,若是对象没有实现接口,会使用Cglib来作动态代理
createAopProxy()方法决定了使用JDK仍是Cglib来作动态代理
若是一个类或者一个类中的public方法上被标注@Transaction注解的话,Spring容器会在启动的时候为其建立一个代理类,在调用被@Transaction注解的public方法的时候,实际调用的是TransactionInterceptor类中的invoke方法。这个方法的做用就是在目标方法以前开启事务,方法执行过程当中若是遇到异常的时候回滚事务,方法调用完成后提交事务。
若同一类中的其余没有@Transaction注解的方法内部调用有@Transaction注解的方法,有@Transaction注解的方法的事务会失效。
这是因为Spring AOP代理的缘由形成的,由于只有@Transaction注解的方法在类之外被调用的时候,Spring事务管理才生效。
解决方法就是避免同一类中自调用或者使用AspectJ取代Spring AOP代理。
——我是冢狐,和你同样热爱编程。
欢迎关注公众号“Java冢狐”获取最新消息