spring事务

  1. 事务的特性ACID
  2. 事务的传播方式
  3. 事务的隔离级别
  4. 脏 幻 不可重复读
  5. 声明式 @Transactional的使用
  6. 编程式事务

事务的特性ACID

  • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
  • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
  • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
  • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

事务的传播方式

spring通过枚举类Propagation定义好了事务的传播方式 ,默认采用Propagation.REQUIRED

public enum Propagation {

	/**
	 Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行
	 */
	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

	/**
	 如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
	 */
	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

	/**
	 * Support a current transaction, throw an exception if none exists.
	 与NEVER相反,如果外层没有事务,则抛出异常
	 */
	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

	/**
	 该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
	 */
	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

	/**
	 该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
	 */
	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

	/**
	 * Execute non-transactionally, throw an exception if a transaction exists.
	 该传播机制不支持外层事务,即如果外层有事务就抛出异常
	 */
	NEVER(TransactionDefinition.PROPAGATION_NEVER),

	/**
	 * Execute within a nested transaction if a current transaction exists,
	 该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
	 */
	NESTED(TransactionDefinition.PROPAGATION_NESTED);
}

事务的隔离级别

spring通过枚举类Isolation定义好事务的隔离级别 Isolation.DEFAULT

public enum Isolation {

	/**
	 * Use the default isolation level of the underlying datastore.
	 数据库默认级别
     
	 */
	DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),

	/**
	 * A constant indicating that dirty reads, non-repeatable reads and phantom reads
	 允许读取尚未提交的更改。可能导致脏读、幻读或不可重复读。
	 */
	READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),

	/**
	 * A constant indicating that dirty reads are prevented; non-repeatable reads
	 * and phantom reads can occur. This level only prohibits a transaction
	(Oracle 默认级别)允许从已经提交的并发事务读取。可防止脏读,但幻读和不可重复读仍可能会发生。
	 */
	READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),

	/**
	 * A constant indicating that dirty reads and non-repeatable reads are
	 * prevented; phantom reads can occur. This level prohibits a transaction
	 * from reading a row with uncommitted changes in it, and it also prohibits
	 * the situation where one transaction reads a row, a second transaction
	 * alters the row, and the first transaction rereads the row, getting
	 (MYSQL默认级别)对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可能发生。
	 */
	REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),

	/**
	 * A constant indicating that dirty reads, non-repeatable reads and phantom
	 * reads are prevented. This level includes the prohibitions in
	 * {@code ISOLATION_REPEATABLE_READ} and further prohibits the situation
	 * where one transaction reads all rows that satisfy a {@code WHERE}
	 * condition, a second transaction inserts a row that satisfies that
	 * {@code WHERE} condition, and the first transaction rereads for the
	 * same condition, retrieving the additional "phantom" row in the second read.
	 * 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。
	 */
	SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
}

脏 幻 不可重复读

  • 脏读(Dirty read):脏读发生在一个事务读取了被另一个事务改写但尚未提交的数据时。如果这些改变在稍后被回滚了,那么第一个事务读取的数据就会是无效的。

  • 幻读(Phantom reads):幻读和不可重复读相似。当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入了一些记录时,幻读就发生了。在后来的查询中,第一个事务(T1)就会发现一些原来没有的额外记录。

  • 不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同时。这通常是由于另一个并发事务在两次查询之间更新了数据。

声明式 @Transactional的使用

@Transactional可加在类 或方法 上面。Transactional这个注解中有以下参数

public @interface Transactional {

	/**
	 * Alias for {@link #transactionManager}.
	 * @see #transactionManager 事务管理器别名默认即可
	 */
	@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;

	/**
	 * 指定0到多个异常类 当发生这些异常时回滚
	 */
	Class<? extends Throwable>[] rollbackFor() default {};

	/**
	 * 指定0到多个异常类名 当发生这些异常时回滚
	 */
	String[] rollbackForClassName() default {};

	/**
	 * 指定0到多个异常类 当发生这些异常时不回滚
	 */
	Class<? extends Throwable>[] noRollbackFor() default {};

	/**
	 * 指定0到多个异常类名 当发生这些异常时不回滚
	 */
	String[] noRollbackForClassName() default {};

}

编程式事务

spring提供的一个模板类 TransactionTemplate 该方法一般通过一个事务管理器创建,通过查看spring的测试案例我们可以看到其使用方式。

@Test
	public void testPropagationNeverWithExistingTransaction() throws Exception {
        //通过事务管理器创建TransactionTemplate
		final TransactionTemplate tt = new TransactionTemplate(tm);
		...

		try {
			tt.execute(new TransactionCallbackWithoutResult() {
				@Override
				protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
                    //具体的业务逻辑等 
                    .....
				}
			});
		}
		catch (IllegalTransactionStateException ex) {
			// expected
		}
        ...
	}

//TransactionCallbackWithoutResult是TransactionCallback的实现 ,其中的doInTransaction调用doInTransactionWithoutResult
public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {

	@Override
	@Nullable
	public final Object doInTransaction(TransactionStatus status) {
		doInTransactionWithoutResult(status);
		return null;
	}

	protected abstract void doInTransactionWithoutResult(TransactionStatus status);

}


// 也可直接实现TransactionCallback接口的doInTransaction

@Test
	public void testPropagationNeverWithExistingTransaction() throws Exception {
        //通过事务管理器创建TransactionTemplate
		final TransactionTemplate tt = new TransactionTemplate(tm);
		...

		try {
			tt.execute(status->{
                //具体的业务逻辑等 
                ...
            });
		}
		catch (IllegalTransactionStateException ex) {
			// expected
		}
        ...
	}


//事务前后的
//是否有进行中的事务
if(TransactionSynchronizationManager.isActualTransactionActive()){

    	TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
	        //事务提交后执行
			@Override
	        public void afterCommit() {
            	// 具体的业务逻辑等
              ...
            }
			 @Override
            public void beforeCommit(boolean readOnly) {
                //事务提交前 beforeCompletion之前
            }

            @Override
            public void beforeCompletion() {
                //事务提交/回滚前 
            }

            @Override
            public void afterCompletion(int status) {
                //事务提交/回滚后执行
            }
		});
	}