一、数据库事务的知识

数据库事务具有以下个基本特征也就是著名的ACID

Atomic (原子性)

事务中包含的操作被看作一个整体的务单元这个业务单元中的操作要么全部成功,要么全部失败,不会出现部分失败、部分成功的场景。

Consistency (一致性)

事务在完成时,必须使所有的数据都保持一致状态,在数据库中所有的修改都基于事务,保证了数据的完整性。

Isolation (隔离性)

多个应用程序线程同时访问数据,这样数据库同样的数据就会在各个不同的事务中被访问,这样会产生丢失更新。
为了压制丢失更新的产生,数据库定义了隔离级别的概念,通过它的选择,可以在不同程度上压制丢失更新的发生。因为互联网的应用常常面对高并发的场景

Durability (持久性)

事务结束后,所有的数据会固化到个地方,如保存到磁盘当中,即使断电重启后也可以提供给应用程序访问。

二、数据库事务的隔离等级

第一类更新丢失,但是多数数据库已经解决这个问题:

image.png

第二类更新丢失: 为了解决这个问题,设计了隔离等级

image.png

四种隔离等级解决的问题以及仍存在的问题如下:√ 是存在问题,X 代表 已经不存问题。
image.png

1. 读未提交 (read-uncommitted) - 最低的 隔离等级。但是效率比较高,适合不要求一致性的场景。

这个隔离等级,运行 读取另一个事务没有提交的数据。所以有脏读的可能。
image.png
当我读取 库存为1 的时候,这个是为 提交或者回滚的结果,所以是脏数据。

2. 读写提交(read-commite ) - 解决了 脏读

只能读取到 另外线程提交后的数据,在提交之前是读不到的。但是存在 不可重复读的场景。
image.png

3. 可重复读(read-repeat)- 解决不可重复读 重复读

他的做法是 ,读取时候,必须等到另外的 事务提交结束后,才能读到数据,否则 就阻塞,等到其他事务提交结束。

解决不可重复读的过程如下:
image.png

但是这个隔离等级,无法解决下面的场景问题:幻读
image.png

4. 串行化(Serializable)

解决一起不服问题。所有操作穿行,按照提交的顺序进行处理。

注:对于隔离等级不同的数据库所支持的是不一样的。例如 Oracle 支持 读写提交与 穿行话,而 mysql支持全部四种,而oracle 的默认隔离等级是 读写提交, mysql的默认是 可重复读 。 这个需要 详细的去找相关资料

三、程序中的运用

1.通过 @Transactional 主键来配置隔离等级

代码示例如下,这里设置了 串行化的 隔离等级。这个等级 会在高并发情况下,引发效率问题。并不适合高并发的场景。
但是准确率很高。

  1. @Transactional(isolation=Isolation.SERIALIZABLE) //串行化
  2. public int insertUser(User user){
  3. return Dao.insertUser(user);
  4. }

这个用法中,是针对每个操作进行配置的。当然还可以通过其他的配合,来确定一个统一的默认隔离等级。

2.Spring Boot 可以通过配置文件来设置隔离等级

可以通过配置 application.property文件来设置等级:

image.png

代码中 设置了隔离等级。 具体配置 可以留作之后来找相关资料进行 学习他起到的作用。

四、事务的传播行为


/**
 * Enumeration that represents transaction propagation behaviors for use
 * with the {@link Transactional} annotation, corresponding to the
 * {@link TransactionDefinition} interface.
 *
 * @author Colin Sampaleanu
 * @author Juergen Hoeller
 * @since 1.2
 */
public enum Propagation {

    /**
     * Support a current transaction, create a new one if none exists.
     * Analogous to EJB transaction attribute of the same name.
     * <p>This is the default setting of a transaction annotation.
       * 支持当前事务,如果不存在,创建一个新的事务。
       * 如果存在事务,沿用当前事务。
       * 如果当前不存在事务,则创建事务运行字方法。
      * 这个是默认的事务设置
     */
    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

    /**
     * Support a current transaction, execute non-transactionally if none exists.
     * Analogous to EJB transaction attribute of the same name.
     * <p>Note: For transaction managers with transaction synchronization,
     * PROPAGATION_SUPPORTS is slightly different from no transaction at all,
     * as it defines a transaction scope that synchronization will apply for.
     * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
     * will be shared for the entire specified scope. Note that this depends on
     * the actual synchronization configuration of the transaction manager.
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
     *
    * 支持事务,如果当前存在事务,就沿用当前事务 ,如果不存在,则继续采用无事务的方式运行子方法
    */
    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

    /**
     * Support a current transaction, throw an exception if none exists.
     * Analogous to EJB transaction attribute of the same name.
     *必须使用事务,如果当前没有事务,则会抛出异常,如果存在当前事务,就沿用当前事务
     */
    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

    /**
     * Create a new transaction, and suspend the current transaction if one exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     * 无论当前事务是否存在,都会创建新事务运行方法,这样新事务就可以拥有新的锁和隔离级别等特性,
     * 与当前事务相互独立
     */
    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

    /**
     * Execute non-transactionally, suspend the current transaction if one exists.
     * Analogous to EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     * 不支持事务,当前存在事务时,将挂起事务,运行方法
     */
    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

    /**
     * Execute non-transactionally, throw an exception if a transaction exists.
     * Analogous to EJB transaction attribute of the same name.
     * 不支持事务,如果当前方法存在事务,则抛出异常,否则继续使用无事务机制运行
     */
    NEVER(TransactionDefinition.PROPAGATION_NEVER),

    /**
     * Execute within a nested transaction if a current transaction exists,
     * behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.
     * <p>Note: Actual creation of a nested transaction will only work on specific
     * transaction managers. Out of the box, this only applies to the JDBC
     * DataSourceTransactionManager when working on a JDBC 3.0 driver.
     * Some JTA providers might support nested transactions as well.
     * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
     * 在当前方法调用子方法时,如果子方法发生异常,只因滚子方法执行过的SQL,而不回滚当前方法的事务
     */
    NESTED(TransactionDefinition.PROPAGATION_NESTED);


    private final int value;


    Propagation(int value) { this.value = value; }

    public int value() { return this.value; }

}

具体使用时候的效果,需要后续进行应用测试。