首页 > 编程语言 > 详细

Spring事务简介

时间:2021-02-22 23:29:24      阅读:41      评论:0      收藏:0      [点我收藏+]

事务可以看做是一次大的活动, 由不同的小活动组成, 这些活动要么全部成功, 要么全部失败.

1. 基本特性ACID

  • 原子性: 执行单元中的操作要么全部执行成功, 要么全部失败. 如果有一部分成功一部分失败那么成功的操作要全部回滚到执行前的状态.
  • 一致性: 执行一次事务会使用数据从一个正确的状态转换到另一个正确的状态, 执行前后数据都是完整的.
  • 隔离性: 在该事务执行的过程中, 任何数据的改变只存在于该事务之中, 对外界没有影响, 事务与事务之间是完全的隔离的. 只有事务提交后其它事务才可以查询到最新的数据.
  • 持久性: 事务完成后对数据的改变会永久性的存储起来, 即使发生断电宕机数据依然在.

2. 事务并发

  • 脏读: 事务A读取了事务B更新的数据, 然后B回滚操作导致A读取的数据是脏数据.
  • 不可重复读: 事务A多次读取同一数据, 事务B在事务A多次读取的过程中, 对数据做了更新并提交, 导致事务A多次读取同一数据时, 结果不一致.
  • 幻读: 事务不是独立执行时发生的一种现象. 例如事务A对表中数据进行修改, 这种修改涉及表中所有数据. 同时事务B也修改这个表的数据, 此时就会发生操作事务A的用户发现表中还有数据没有被修改, 就像发生了幻觉一样. (不可重复读的重点是修改: 同样的条件, 两次读取的数据不一致. 幻读的重点在于新增或者删除: 同样的条件, 两次读取的数据记录数不同.)

3. 事务隔离级别

SQL定义中定义了四种隔离级别:

  • 读未提交(READ-UNCOMMITTED): 最低的隔离级别, 允许读取尚未提交的数据变更. 可能会导致脏读、幻读或不可重复读.
  • 读取已提交(READ-COMMITTED): 允许读取并发事务已经提交的数据, 可以阻止脏读, 但是幻读或不可重复读仍有可能发生.
  • 可重复读(REPEATABLE-READ): 对同一字段的多次读取结果都是一致的, 除非数据是被本身事务自己所修改, 可以阻止脏读和不可重复读, 但幻读仍有可能发生.
  • 可串行化(SERIALIZABLE): 最高的隔离级别, 完全服从ACID的隔离级别. 所有的事务依次逐个执行, 这样事务之间就完全不可能产生干扰, 也就是说, 该级别可以防止脏读、不可重复读以及幻读.
事务隔离级别 脏读 不可重复读 幻读
读未提交
读取已提交
可重复读
串行化

在Spring中定义了5中隔离级别:

  • ISOLATION_DEFAULT: 这是一个PlatformTransactionManager默认的隔离级别, 使用数据库默认的事务隔离级别. 另外四个与JDBC的隔离级别相对应
  • ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别, 它充许令外一个事务可以看到这个事务未提交的数据. 这种隔离级别会产生脏读, 不可重复读和幻像读.
  • ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取. 另外一个事务不能读取该事务未提交的数据
  • ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读, 不可重复读. 但是可能出现幻像读. 它除了保证一个事务不能读取另一个事务未提交的数据外, 还保证了避免下面的情况产生(不可重复读).
  • ISOLATION_SERIALIZABLE: 这是花费最高代价但是最可靠的事务隔离级别. 事务被处理为顺序执行. 除了防止脏读, 不可重复读外, 还避免了幻像读.

4. 事务的传播特性

事务传播行为指的是多个事务方法调用时, 如何定义方法间事务的传播. 在Spring中定义了7种传播行为:

  • propagation_required: 如果当前没有事务, 就新建一个事务, 如果已存在一个事务中, 加入到这个事务中, 这是Spring默认的选择.
  • propagation_supports: 支持当前事务, 如果没有当前事务, 就以非事务方法执行.
  • propagation_mandatory: 使用当前事务, 如果没有当前事务, 就抛出异常.
  • propagation_required_new: 新建事务, 如果当前存在事务, 把当前事务挂起.
  • propagation_not_supported: 以非事务方式执行操作, 如果当前存在事务, 就把当前事务挂起.
  • propagation_never: 以非事务方式执行操作, 如果当前事务存在则抛出异常.
  • propagation_nested: 如果当前存在事务, 则在嵌套事务内执行. 如果当前没有事务, 则执行与propagation_required类似的操作.

5. Spring中的事务

一般情况下, 只有无状态的bean才可以在多线程环境下共享. Spring针对一些bean(RequestContextHolder, TransactionSynchronizationManager, LocaleContextHolder)中非线程安全的状态型对象采用ThreadLocal进行封装, 让它们也成为线程安全的状态型对象.

Spring为事务管理提供了一致的编程模板, 不管选择Spring JDBC, Hibernate, MyBatis, 都可以让用户使用同一的编程模型进行事务管理. 整个事务管理的抽象层主要包含三个接口.

PlatformTransactionManager

事务管理器. 该类只包含三个方法: 获取事务, 回顾事务, 提交事务.

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}
TransactionDefinition

定义事务的类型. 事务包含很多属性: 是否可读, 事务隔离级别, 事务传播级别.

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;

    int getPropagationBehavior();

    int getIsolationLevel();

    int getTimeout();

    boolean isReadOnly();

    String getName();
}
TransactionStatus

代表一个事务运行的状态. 事务管理器通过状态可以知道事务的状态信息, 然后进行事务的控制事务是否完成, 是否是新的事务, 是不是只能回滚等.

public interface TransactionStatus extends SavepointManager, Flushable {
    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();
}

5.1 Spring事务管理器

Spring将事务管理委托给底层具体的持久化实现框架来完成, 因此Spring为不同的持久化框架提供了PlatformTransactionManager接口的实现类, 例如JpaTransactionManager, HibernateTransactionManager, DataSourceTransactionManager, JdpTransactionManager, JtaTransactionManager. 这些事务管理器都是对特定事务实现框架的代理, 这样就可以通过Spring的高级抽象对不同种类的事务实现使用相同的方式进行管理, 而不需要关心具体的实现.

5.2 Spring事务同步管理器

Spring将JDBC的Connection, Hibernate的Session等访问数据库的连接或会话对象统称为资源, 为了让这些资源做到多线程之间共享, Spring中的TransactionSynchronizationManager使用ThreadLocal为不同事务线程提供了独立的资源副本, 同时维护事务配置的属性和运行状态信息.

public abstract class TransactionSynchronizationManager {
    // 用于保存每个事务线程对应的Connection或Session等类型的资源
    private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");
    // 用于保存每个事务线程对应事务的名称
    private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal("Current transaction name");
    // 用于保存每个事务线程对应事务的read-only状态
    private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal("Current transaction read-only status");
    // 用于保存每个事务线程对应事务的隔离级别
    private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal("Current transaction isolation level");
    // 用于保存每个事务线程对应事务的激活状态
    private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal("Actual transaction active");
}

TransactionSynchronizationManager将Dao, Service类中影响线程安全的所有状态统一抽取到该类中, 并用ThreadLocal进行替换, 从而保证Dao, Service的线程安全性.

5.3 编程式事务管理

在实际中, 很少需要通过编程来实现事务管理. 即便如此, Spring还是为编程式事务提供模板类TransactionTemplate以满足一些特殊场合的需要.

public class Service {
    public void doSomething() {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // do something
            }
        });        
    }
}

也可以直接操作PlatformTransactionManager对事务进行commit或rollback.

5.4 XML配置声明式事务

XML方式配置声明式事务一共有两种, 可以使用原始的TransactionProxyFactoryBean, 也可以使用基于aop/tx命名空间的配置.

<beans>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource" />

    <aop:config>
        <aop:pointcut id="serviceMethod" expression="execution(* com.annwyn.service.*.*(..))" />
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>
    
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
        </tx:attributes>
    </tx:advice>
</beans>

如果需要为不同的业务类应用不同的事务管理风格, 可以在<aop:config>中定义另外多套事务切面进行配置.

如果rollback-for属性没有指定异常或者没有进行配置, 默认情况下只能回滚运行时异常(RuntimeException)以及错误(Error), 而捕获到编译时异常不会进行回滚.

5.5 注解配置声明式事务

除了XML方式配置外, 还可以使用@Transaction进行事务管理. Transaction注解可以使用在接口定义, 接口方法, 类定义以及public方法上.

使用xml配置需要添加<tx:annotation-driven transaction-manager="txManager" />, 而使用JavaConfig配置需要添加@EnableTransactionManagement, 而在SpringBoot应用下, 可以不添加该注解, 因为在TransactionAutoConfiguration下已经进行了自动配置.

6. 总结

Spring事务大致介绍这里, 下次有时间再分析其详细代码.

Spring事务简介

原文:https://www.cnblogs.com/annwyn/p/14432914.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!