简单理解下其事务传播机制的体现以及生效原理。

1. mysql 和 jdbc 提供的保存点  

   在看事务源码的过程中发现有个savepoint 的一操作,简单研究下其使用。

1. mysql 提供的savepoint

start TRANSACTION;

SELECT * FROM `message`

insert into message(title) values ("tx1");

SAVEPOINT point_tx1;

insert into message(title) values ("tx2");

SAVEPOINT point_tx3;

insert into message(title) values ("tx3");

rollback to point_tx1;

// 删除保存点(commit 之后也会删除回滚点)
release SAVEPOINT point_tx1;

// 同名会覆盖
SAVEPOINT point_tx1;

// commit 也会删除点
commit;

2. JDBC提供的savepoint

import java.sql.*;

public class Client {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/media?useSSL=false", "root", "123456");
            con.setAutoCommit(false);

            Savepoint savepoint = null;
            PreparedStatement preparedStatement = con.prepareStatement("insert into message(title) values (\"tx1\")");
            preparedStatement.execute();
            savepoint = con.setSavepoint("point_tx1");
            PreparedStatement preparedStatement2 = con.prepareStatement("insert into message(title) values (\"tx2\")");
            preparedStatement2.execute();

            // 回滚到指定保存点然后commit, 第二条数据会回滚
            con.rollback(savepoint);
            con.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. 事务传播机制以及对dao 的影响

  这里简单研究下事务AOP是如何影响到dao 的,也可以理解为如何传递connection 的; 接着研究下事务默认的传播行为。

1. 以mybatis 为例子分析其事务如何影响到dao

   根据之前的操作大体可以理解到。事务相关实际是改变Connection 相关信息,也就是设置自动提交为false, 然后手动commit。 接下来简单研究下,事务在AOP层面修改为手动提交之后,dao 是如何拿到相对应的Connection 对象的。

1. 事务AOP修改Connection 对象相关属性

(1)  org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 标志事务AOP开始执行,调用createTransactionIfNecessary 获取一个TransactionInfo 对象, 这个对象包含事务管理器、事务属性、连接点、以及上一个事务信息, TransactionInfo 源码如下: (oldTransactionInfo 是一个重要的对象,可以理解为是执行权交给上一个事务的重要对象)

    /**
     * Opaque object used to hold transaction information. Subclasses
     * must pass it back to methods on this class, but not see its internals.
     */
    protected static final class TransactionInfo {

        @Nullable
        private final PlatformTransactionManager transactionManager;

        @Nullable
        private final TransactionAttribute transactionAttribute;

        private final String joinpointIdentification;

        @Nullable
        private TransactionStatus transactionStatus;

        @Nullable
        private TransactionInfo oldTransactionInfo;

        public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
                @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {

            this.transactionManager = transactionManager;
            this.transactionAttribute = transactionAttribute;
            this.joinpointIdentification = joinpointIdentification;
        }

        public PlatformTransactionManager getTransactionManager() {
            Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
            return this.transactionManager;
        }

        @Nullable
        public TransactionAttribute getTransactionAttribute() {
            return this.transactionAttribute;
        }

        /**
         * Return a String representation of this joinpoint (usually a Method call)
         * for use in logging.
         */
        public String getJoinpointIdentification() {
            return this.joinpointIdentification;
        }

        public void newTransactionStatus(@Nullable TransactionStatus status) {
            this.transactionStatus = status;
        }

        @Nullable
        public TransactionStatus getTransactionStatus() {
            return this.transactionStatus;
        }

        /**
         * Return whether a transaction was created by this aspect,
         * or whether we just have a placeholder to keep ThreadLocal stack integrity.
         */
        public boolean hasTransaction() {
            return (this.transactionStatus != null);
        }

        private void bindToThread() {
            // Expose current TransactionStatus, preserving any existing TransactionStatus
            // for restoration after this transaction is complete.
            this.oldTransactionInfo = transactionInfoHolder.get();
            transactionInfoHolder.set(this);
        }

        private void restoreThreadLocalStatus() {
            // Use stack to restore old transaction TransactionInfo.
            // Will be null if none was set.
            transactionInfoHolder.set(this.oldTransactionInfo);
        }

        @Override
        public String toString() {
            return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
        }
    }
View Code

相关文章:

  • 2021-08-09
  • 2022-12-23
  • 2021-06-04
  • 2021-09-30
  • 2021-05-20
  • 2021-08-04
  • 2021-11-02
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-01-17
  • 2021-11-02
  • 2021-09-01
  • 2021-06-19
相关资源
相似解决方案