Spring 事务

事务定义

单个逻辑工作单元执行的一系列操作, 这一系列操作要么全部执行, 要么全部不执行.
从生活示例转账的逻辑来看, A 向 B 转账 100元, 可以分为两步: 1. A 扣款 100 ,2. B 加款 100. 这两步要么全部执行, 要么全部不执行 才是真正完成一次转账. 那么这两步就属于一个事务.

事务的特性(ACID)

  • 原子性(Atomicity) : 事务操作必须是原子工作单元, 对数据修改时, 要么全部执行, 要么全部不执行.
  • 一致性(Consistency) : 事务操作必须从一个一致性的状态转换到另一个一致性的转台. 例如: 读操作可以读到提交的更新数据; 一个操作读到刚更新的值, 那么后续就不会读到更早更新的值. 这儿的一致性我理解为数据系统状态正常.
  • 隔离性(Isolation) : 事务执行状态隔离, 不同事务中在执行过程中相互不干扰. 一个事务执行过程中也不会查看另外事务的中间状态数据.
  • 持久性(Durability) : 事务执行完毕后, 对系统的影响是永久性的.

Spring 事务管理器

Spring的事务管理器是由接口 org.springframework.transaction.PlatformTransactionManager 提供的. 它是接口, 所以本身不提供事务管理的能力, 必须有具体的平台 Jdbc, Hibernate, JPA等来提供对应的事务管理器.

// PlatformTransactionManager 的结构
public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; // 获取TransactionStatus 对象
    void commit(TransactionStatus var1) throws TransactionException; // 提交事务
    void rollback(TransactionStatus var1) throws TransactionException; // 回滚事务
}

TransactionStatus 提供了事务的状态信息的查询和控制方法.

public interface TransactionStatus extends SavepointManager, Flushable {
    void flush() throws IOException; //  extends Flushable 刷新缓冲区 
    Object createSavepoint() throws TransactionException; //  extends SavepointManager 创建还原点
    void rollbackToSavepoint(Object var1) throws TransactionException;  //  extends SavepointManager 回滚到指定还原点
    void releaseSavepoint(Object var1) throws TransactionException;  //  extends SavepointManager 移除指定还原点
    boolean isNewTransaction(); // 是否是新的事务
    boolean hasSavepoint(); // 是否有还原点
    void setRollbackOnly(); // 设置回滚
    boolean isRollbackOnly(); // 是否已回滚
    void flush(); // extends Flushable
    boolean isCompleted(); // 是否已完成
}

Spring 的事务属性定义

获取一个事务需要传入 TransactionDefinition 对象, 这个接口定义 7 种事务传播行为 和 5 种数据库隔离级别定义.

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(); // 是否只读, 一般查询只读, 读写非只读. 一般只读会有优化.
    @Nullable
    String getName(); // 事务的名称 一般是 save* find* select* ...
}

事务的隔离级别就是为了解决并发过程中的典型问题, 隔离级别从低到高并发性越来越差.

  1. 读脏: 一个事务读到了另外一个事务未提交的数据, 解决方式使用: 读已提交或者更高隔离级别
  2. 不可重复读: 同一个事务中多次读取时每次都读到不同数据. 主要是数据修改
  3. 幻读: 同一个是事务, 多次读取的时候, 可能出现前一次查询不存在的数据或者查询不到前一次已经查询到的数据. 主要是 数据新增和删除.
隔离级别可能会出现的并发问题读脏不可重复读幻读
读未提交
读已提交×
不可重复读××
序列化×××

常用Spring事务的实现

  1. 使用 @Transaction 注解声明式事务管理.
// 代表启用事务, 使用数据库默认隔离级别, 默认事务属性
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public void insert(User user){}

// 需要在配置事务时启用事务注解
<!-- 事务管理器 -->
<bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
	
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="tracnsactionManager"/> 

  1. 使用 Aspectj AOP配置事务
<!-- 事务管理器 -->
<bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<tx:advice id="txAdvice" transaction-manager="tracnsactionManager">
	<tx:attributes> 
		<tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/> <!-- 以insert开头的方法使用事务 -->
	</tx:attributes>
</tx:advice> 

<aop:config>
    <aop:pointcut expression="execution(* *..service.*.*(..))" id="point"> <!-- 包名为service下所有方法都事务处理 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>

总结

Spring 事务实际就是使用依托了 Spring 强大的Aop功能, 将数据库事务封装在框架中, 搞清楚了实现原理, 发现理解起来还是挺简单的.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值