最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring中父子線程共享事務的實現(xiàn)

 更新時間:2025年05月28日 10:09:07   作者:uncleqiao  
本文主要介紹了spring中父子線程共享事務的實現(xiàn),涵蓋原生JDBC手動傳遞連接、JdbcTemplate綁定資源、PlatformTransactionManager上下文管理及@Transactional注解的實現(xiàn),感興趣的可以了解一下

一、原生jdbc的父子線程共用事務

初始化數(shù)據(jù)庫中的數(shù)據(jù)

在這里插入圖片描述

1、單線程事務提交

private static void t1() throws Exception {
    Connection conn = getConn();
    PreparedStatement stmt1 = null;
    PreparedStatement stmt2 = null;
    try {
        // 1. 禁用自動提交,開啟事務
        conn.setAutoCommit(false);

        // 2. 執(zhí)行多個數(shù)據(jù)庫操作
        String sql1 = "UPDATE student SET age = age - 1 WHERE id = ?";
        stmt1 = conn.prepareStatement(sql1);
        stmt1.setInt(1, 1);
        stmt1.executeUpdate();

        String sql2 = "UPDATE student SET age = age + 1 WHERE id = ?";
        stmt2 = conn.prepareStatement(sql2);
        stmt2.setInt(1, 2);
        stmt2.executeUpdate();

        // 3. 事務回滾, 將會回滾兩個執(zhí)行語句的內(nèi)容
        conn.rollback();
        
        // 4. 提交事務
        conn.commit();
        System.out.println("Transaction committed successfully.");
    } catch (SQLException e) {
        // 發(fā)生異常時回滾事務
        if (conn != null) {
            try {
                conn.rollback();
                System.out.println("Transaction rolled back.");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        e.printStackTrace();
    } finally {
        close(stmt1, stmt2);
    }
}

獲取數(shù)據(jù)庫連接和釋放連接

private static Connection getConn() throws Exception {
        String url = "jdbc:mysql://localhost:3306/test";
        String username = "root";
        String password = "123456";
        // 1. 獲取數(shù)據(jù)庫連接
        return DriverManager.getConnection(url, username, password);
    }

    private static void close(AutoCloseable... closeables) {
        for (AutoCloseable closeable : closeables) {
            if (closeable != null) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    // ... do something
                    e.printStackTrace();
                }
            }
        }
    }

執(zhí)行完后, 數(shù)據(jù)庫中數(shù)據(jù)如下, 可以看到兩條語句都執(zhí)行成功

在這里插入圖片描述

2、父子線程提交事務

還原數(shù)據(jù)庫中的數(shù)據(jù)如下

在這里插入圖片描述

private static void t2() throws Exception {
        Connection conn = getConn();
        PreparedStatement stmt1 = null;
        try {
            // 1. 禁用自動提交,開啟事務
            conn.setAutoCommit(false);

            // 2. 父線程執(zhí)行
            String sql1 = "UPDATE student SET age = age - 1 WHERE id = ?";
            stmt1 = conn.prepareStatement(sql1);
            stmt1.setInt(1, 1);
            stmt1.executeUpdate();

            // 3. 子線程執(zhí)行
            Thread t1 = new Thread(() -> {
                String sql2 = "UPDATE student SET age = age + 1 WHERE id = ?";
                try {
                    PreparedStatement stmt2 = conn.prepareStatement(sql2);
                    stmt2.setInt(1, 2);
                    stmt2.executeUpdate();
                    // 子線程回滾
                    conn.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            });
            t1.start();
            // 等t1執(zhí)行完
            t1.join();

            // 4. 提交事務
            conn.commit();
            System.out.println("Transaction committed successfully.");
        } catch (SQLException e) {
            // 發(fā)生異常時回滾事務
            if (conn != null) {
                try {
                    conn.rollback();
                    System.out.println("Transaction rolled back.");
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            close(stmt1);
        }
    }

執(zhí)行之后看結(jié)果

在這里插入圖片描述

age沒有發(fā)生變化, 也就是說子線程回滾了, 主線程中的提交不會生效, 達到了異步任務中事務共享的效果。

二、jdbcTemplate實現(xiàn)父子共用事務

jdbcTemplateupdate方法為例, 看看內(nèi)部實現(xiàn)

// ... 只看核心update方法
protected int update(final PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss)
			throws DataAccessException {
    return updateCount(execute(psc, ps -> {
        try {
            // 賦值
            if (pss != null) {
                pss.setValues(ps);
            }
            // 使用PreparedStatement執(zhí)行
            int rows = ps.executeUpdate();
            if (logger.isTraceEnabled()) {
                logger.trace("SQL update affected " + rows + " rows");
            }
            return rows;
        }
        finally {
            // ...
        }
    }, true));
}

繼續(xù)看execute

private <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action, boolean closeResources)
			throws DataAccessException {
		// 從數(shù)據(jù)源中獲取一個鏈接
		Connection con = DataSourceUtils.getConnection(obtainDataSource());
		PreparedStatement ps = null;
		try {
            // ...省略部分代碼
			// 執(zhí)行
			T result = action.doInPreparedStatement(ps);
			return result;
		}
		catch (SQLException ex) {
			//...
		}
		finally {
            // 關閉資源
			if (closeResources) {
				if (psc instanceof ParameterDisposer) {
					((ParameterDisposer) psc).cleanupParameters();
				}
                // 關閉Statement
				JdbcUtils.closeStatement(ps);
                // 回收鏈接(連接池的場景下是對連接的引用數(shù)-1, 并不會直接釋放連接)
				DataSourceUtils.releaseConnection(con, getDataSource());
			}
		}
	}

這里是從連接池中獲取一個鏈接, 然后執(zhí)行對應的db操作, 這里重點看一下 Connection con = DataSourceUtils.getConnection(obtainDataSource());

DataSourceUtils.getConnection的核心邏輯如下

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
		Assert.notNull(dataSource, "No DataSource specified");

    	// 上下文中獲取當前數(shù)據(jù)源中的連接句柄
		ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    	// 1.連接句柄存在 并且 2(句柄中有鏈接 或者 是事務同步)
		if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
            // 引用數(shù)+1
			conHolder.requested();
			// 直接獲取連接
			return conHolder.getConnection();
		}
		// 從數(shù)據(jù)源中獲取連接
		Connection con = fetchConnection(dataSource);

    	// ... 省略事務同步處理邏輯

		return con;
	}

從這個方法可以知道兩點

  • 如果當前上下文中存在連接就用該連接
  • 不存在上下文中的連接就從數(shù)據(jù)源中獲取

清楚了這個邏輯后, 我們來構(gòu)建多線性下使用事務的場景

@Autowired
private DataSource dataSource;

@Autowired
private JdbcTemplate jdbcTemplate;

private void jdbcTemplateTest() throws Exception {
    Connection con = DataSourceUtils.getConnection(dataSource);
    con.setAutoCommit(false);
    ConnectionHolder holderToUse = new ConnectionHolder(con);
    // 在jdbcTemplate執(zhí)行update之前將數(shù)據(jù)庫連接放到上下文中
    TransactionSynchronizationManager.bindResource(dataSource, holderToUse);

    String sql1 = "UPDATE student SET age = age - 1 WHERE id = ?";
    jdbcTemplate.update(sql1, "1");
    Thread t1 = new Thread(() -> {
        TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
        String sql2 = "UPDATE student SET age = age + 1 WHERE id = ?";
        jdbcTemplate.update(sql2, "2");
        try {
            con.rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    });
    t1.start();
    t1.join();
    con.commit();
    con.setAutoCommit(true);
}

注意這里需要在jdbcTemplate執(zhí)行update之前調(diào)用bindResource操作, 因為上面介紹的update里面會先從上下文中獲取數(shù)據(jù)庫連接, 在子線程中也需要執(zhí)行bindResource將連接綁定到子線程中, 這樣父子線程就用的同一個連接了。

注意這里是使用Connection直接調(diào)用的setAutoCommit控制手動提交, 所以用完后記得設置為自動提交

三、PlatformTransactionManager 管理事務下的父子線程共享事務

簡單demo

先看下一般的單線程下的手動事務

@Autowired
private PlatformTransactionManager transactionManager;

@Autowired
private TransactionDefinition definition;

private void manualTx() {
    String sql1 = "UPDATE student SET age = age - 1 WHERE id = ?";
    // 開啟手動事務
    TransactionStatus status = this.transactionManager.getTransaction(definition);
    try {
        jdbcTemplate.update(sql1, "1");
        throw new RuntimeException("錯誤了");
    } catch (Exception e) {
        this.transactionManager.rollback(status);
    }
    if (!status.isCompleted()) {
        this.transactionManager.commit(status);
    }
}

這里主要是使用getTransaction方法開啟手動提交, 然后rollback方法回滾事務, commit方法提交事務

原理剖析

這里我們看看手動開啟方法getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// Use defaults if no transaction definition given.
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

    	// 上下文中獲取事務
		Object transaction = doGetTransaction();
		// 判斷是否獲取到了連接和并且事務由jdbc管理
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// 以下是事務不存在的情況
    	// 判斷傳播機制; 這里是必須有事務的傳播機制
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
    	// 需要事務的傳播機制
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			// 創(chuàng)建新的事物
			try {
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// 創(chuàng)建空事物
            // ....
		}
	}

核心邏輯

  • 如果存在事務, 則使用當前事務
  • 如果不存在事務, 并且隔離界別需要開啟事務, 那么創(chuàng)建新事務

再跟一下doGetTransaction方法

protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    ConnectionHolder conHolder =
            (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

我們看到了上面也介紹過的從上下文中獲取連接句柄的方法TransactionSynchronizationManager.getResource

繼續(xù)看startTransaction方法, 創(chuàng)建新的事物

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
			boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    DefaultTransactionStatus status = newTransactionStatus(
            definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    // 開啟事務
    doBegin(transaction, definition);
    // 將事物相關信息放入到上下文中
    prepareSynchronization(status, definition);
    return status;
}

這里做了兩件事: 1. 開啟事務 2. 將事物相關信息放入到上下文中

先看一下開啟事務doBegin方法

protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;
    try {
        // 1.上下文中沒有連接 2.或者需要將事務資源綁定到上下文中
        if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // 創(chuàng)建新的數(shù)據(jù)庫連接
            Connection newCon = obtainDataSource().getConnection();
            // 標記為新創(chuàng)建的數(shù)據(jù)庫連接
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }
        // 設置為綁定資源到上下文
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        con = txObject.getConnectionHolder().getConnection();

        // 隔離級別
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
        txObject.setReadOnly(definition.isReadOnly());

        // 設置為手動提交
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            con.setAutoCommit(false);
        }
        // 設置事務只讀
        prepareTransactionalConnection(con, definition);
        // 標記事務激活狀態(tài)
        txObject.getConnectionHolder().setTransactionActive(true);

        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }

        // 新的數(shù)據(jù)庫連接, 就將連接綁定的上下文中
        if (txObject.isNewConnectionHolder()) {
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }
}

方法小結(jié)

  • 沒事務就開啟事務
  • 設置事務為手動提交
  • 將數(shù)據(jù)庫連接放到上下文中TransactionSynchronizationManager.bindResource

咋們再來看看prepareSynchronization方法, 將事務信息放到上下文

protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    // 新事務打開了事務同步
    if (status.isNewSynchronization()) {
        // 事務激活狀態(tài)
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        // 隔離級別
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
                        definition.getIsolationLevel() : null);
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        TransactionSynchronizationManager.initSynchronization();
    }
}

在傳播機制是PROPAGATION_REQUIRED(有事務就用當前事務, 沒有就新建)的場景下我們看一下handleExistingTransaction方法, 用來獲取當前事務

// ... 省略傳播機制判斷的代碼

if (isValidateExistingTransaction()) {
    // 非默認隔離級別, 校驗隔離級別
    if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
        Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
        if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
            // ...拋異常
        }
    }
    // 校驗readOnly
    if (!definition.isReadOnly()) {
        if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
            // ...拋異常
        }
    }
}
// 將事務信息綁定到線程上下文
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);

總結(jié)一下transactionManager.getTransaction方法

  • 從當前上下文獲取數(shù)據(jù)庫連接句柄TransactionSynchronizationManager.getResource
  • 如果存在連接和事務
  • 直接使用當前事務
  • 校驗事務的傳播機制, 是否只讀
  • 將事務信息放到上下文
  • 如果當前不存在事務(PROPAGATION_REQUIRED場景下)
  • 創(chuàng)建新的數(shù)據(jù)庫連接
  • 設置為手動提交
  • 綁定數(shù)據(jù)庫連接句柄到上下文TransactionSynchronizationManager.bindResource
  • 將事務信息放到上下文

關于TransactionStatuscommit方法和rollback方法我們就不看了, 它里面都校驗了事務是否已經(jīng)激活事務同步, 可以使用TransactionSynchronizationManager.initSynchronization方法來激活

有了以上信息支撐后, 我們再來看PlatformTransactionManager下的父子線程共享事務

我們只需要將父線程中的數(shù)據(jù)庫句柄放到子線程, 并且設置傳播機制是否只讀激活事務同步就可以了;

PlatformTransactionManager下的父子線程使用同一個事務的demo

private void manualMultiTx() throws Exception {
        String sql1 = "UPDATE student SET age = age - 1 WHERE id = ?";

        // 開啟手動事務
        TransactionStatus status = this.transactionManager.getTransaction(definition);
    	// 獲取父線程中綁定的數(shù)據(jù)庫連接句柄
        ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

        // 因為getTransaction已經(jīng)將ConnectionHolder綁定到當前線程(TransactionSynchronizationManager.bindResource),所以這里會直接拿這個連接
        jdbcTemplate.update(sql1, "1");
        Thread t1 = new Thread(() -> {
            /******************** 核心步驟start ***************/
            // 將ConnectionHolder綁定到當前線程
            TransactionSynchronizationManager.bindResource(dataSource, connectionHolder);
            // 將事務相關信息綁定到現(xiàn)成上下文
            // 設置隔離級別
 TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(definition.getIsolationLevel());
            // 設置是否只讀
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
            // 激活事務同步
            TransactionSynchronizationManager.initSynchronization();
			/******************** 核心步驟end ***************/
            
            System.out.println("線程1執(zhí)行");
            jdbcTemplate.update(sql1, "2");
            if (!status.isCompleted()) {
            	this.transactionManager.rollback(status);
            }
        });
        t1.start();
        t1.join();
        System.out.println("run線程執(zhí)行");
        if (!status.isCompleted()) {
            this.transactionManager.commit(status);
        }
    }

其實這里的將事務相關信息綁定到現(xiàn)成上下文直接copy上面的prepareSynchronization方法的內(nèi)容即可

改成這樣更完整

/******************** 核心步驟start ***************/
TransactionSynchronizationManager.bindResource(dataSource, connectionHolder);
DefaultTransactionStatus s = (DefaultTransactionStatus) status;
// 事務激活狀態(tài)
TransactionSynchronizationManager.setActualTransactionActive(s.hasTransaction());
// 隔離級別, 這里稍微不一樣
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(definition.getIsolationLevel());
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
TransactionSynchronizationManager.initSynchronization();
/******************** 核心步驟end ***************/

四、@Transactional注解下的父子線程事務共享

我們得看到@Transactional注解的增強類TransactionInterceptor中去;

在invoke中調(diào)用了invokeWithinTransaction方法, 我們關注一下

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

    // 事務屬性
    TransactionAttributeSource tas = getTransactionAttributeSource();
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // 事務管理器
    final TransactionManager tm = determineTransactionManager(txAttr);
    // ... 省略一些其它代碼

    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    // 切點方法
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    // 這里是JdbcTransactionManager, 也是PlatformTransactionManager實現(xiàn)類
    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
        // 創(chuàng)建事務
        TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

        Object retVal;
        try {
            // 調(diào)用目標方法
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // 這里會rollback
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }

        // 這里會commit
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }
    // ... 省略部分代碼
}

這里我們只需要關注用來創(chuàng)建事務的createTransactionIfNecessary方法即可

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

    // ... 省略部分代碼
    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            status = tm.getTransaction(txAttr);
        }
    }
    // 包裝一下返回
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

回到了上面原理剖析中介紹的PlatformTransactionManager#getTransaction方法了, 也就是說它也會先從線程上下文中獲取數(shù)據(jù)庫連接句柄, 有的話直接用了, 沒有就去創(chuàng)建然后放到當前上下文, 和上面介紹的第3節(jié)中的一樣, 這里就不贅述了。

demo和上面的也基本沒有區(qū)別

private void transactionalTest() throws Exception {

    // 開啟手動事務
    TransactionStatus status = this.transactionManager.getTransaction(definition);
    ConnectionHolder connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

    // 因為getTransaction已經(jīng)將ConnectionHolder綁定到當前線程(TransactionSynchronizationManager.bindResource),所以這里會直接拿這個連接
	// 主線程中service調(diào)用
    myService.tranTest();
    Thread t1 = new Thread(() -> {
        // 將ConnectionHolder綁定到當前線程
        TransactionSynchronizationManager.bindResource(dataSource, connectionHolder);
        DefaultTransactionStatus s = (DefaultTransactionStatus) status;
        // 標記當前事務已存在
        TransactionSynchronizationManager.setActualTransactionActive(s.hasTransaction());
        // 設置隔離級別
   TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(definition.getIsolationLevel());
        // 設置是否只讀
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        TransactionSynchronizationManager.initSynchronization();

        System.out.println("線程1執(zhí)行");
        // 子線程中service調(diào)用
        myService.tranTest();
        if (!status.isCompleted()) {
            this.transactionManager.rollback(status);
        }
    });
    t1.start();
    t1.join();
    System.out.println("run線程執(zhí)行");
    if (!status.isCompleted()) {
        this.transactionManager.commit(status);
    }

}

service

@Component
public class MyService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void tranTest() {
        String sql1 = "UPDATE student SET age = age - 1 WHERE id = ?";
        jdbcTemplate.update(sql1, "2");
    }

}

五、總結(jié)

  • 父子線程中事務共享的原理就是要讓一個數(shù)據(jù)庫連接在父子線程中同時使用
  • 原生jdbc中, 將數(shù)據(jù)庫連接直接從父線程傳遞到子線程即可
  • jdbcTemplate的使用中, 只需將同一個數(shù)據(jù)庫連接同時綁定到父子線程中接口, 使用TransactionSynchronizationManager.bindResource
  • 在spring中使用PlatformTransactionManager開啟手動事務, 除了第三點的需要將數(shù)據(jù)庫連接同時在父線程中綁定transactionManager.getTransaction(definition)和在子線程中綁定TransactionSynchronizationManager.bindResource之外, 還需要將事務的相關信息綁定到子線程(詳細見文章內(nèi)部)
  • 在spring中使用PlatformTransactionManager不管是配合jdbcTemplate還是調(diào)用@Transactional使用聲明式原理都是一樣的, 都是得從在子線程中綁定父線程中的相同的事務信息和連接信息

到此這篇關于spring中父子線程共享事務的實現(xiàn)的文章就介紹到這了,更多相關spring 父子線程共享事務內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • 關于Java從本地文件復制到網(wǎng)絡文件上傳

    關于Java從本地文件復制到網(wǎng)絡文件上傳

    這篇文章主要介紹了關于Java從本地文件復制到網(wǎng)絡文件上傳,File?和?IO?流其實是很相似的,都是將文件從一個地方轉(zhuǎn)移到另一個地方,這也是流的特點之一,需要的朋友可以參考下
    2023-04-04
  • Mybatis-Plus設置全局或者局部ID自增的實現(xiàn)

    Mybatis-Plus設置全局或者局部ID自增的實現(xiàn)

    在使用Mybatis-Plus新增的時候,我們往往想要id隨著數(shù)據(jù)庫自增,本文主要介紹了Mybatis-Plus設置全局或者局部ID自增的實現(xiàn),具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • SpringBoot3整合MinIO實現(xiàn)分布式文件存儲系統(tǒng)

    SpringBoot3整合MinIO實現(xiàn)分布式文件存儲系統(tǒng)

    MinIO是一個高性能的分布式對象存儲系統(tǒng),兼容Amazon S3協(xié)議,廣泛用于存儲大量非結(jié)構(gòu)化數(shù)據(jù),SpringBoot3提供了與MinIO的良好集成,可以很方便地將MinIO用于分布式文件存儲,在這篇文章中,我們將介紹如何在SpringBoot3中集成MinIO,搭建一個分布式文件存儲系統(tǒng)
    2025-07-07
  • Java中合并Excel文件的實用方法詳解

    Java中合并Excel文件的實用方法詳解

    在企業(yè)應用中,處理 Excel 文件是非常常見的需求,這篇文章主要介紹了Java中合并Excel文件的幾個實用方法,感興趣的小伙伴可以跟隨小編一起學習一下
    2026-04-04
  • Java基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法

    Java基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法

    下面小編就為大家?guī)硪黄狫ava基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • Java中Arraylist的最大長度

    Java中Arraylist的最大長度

    這篇文章主要介紹了Java中Arraylist的最大長度,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • springboot整合xxl-job的實現(xiàn)示例

    springboot整合xxl-job的實現(xiàn)示例

    本文主要介紹了springboot整合xxl-job的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • 詳解SpringCloud服務認證(JWT)

    詳解SpringCloud服務認證(JWT)

    本篇文章主要介紹了SpringCloud服務認證(JWT),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java面試必備八股文整理

    Java面試必備八股文整理

    這篇文章主要介紹了Java面試必備八股文整理,小伙伴們出去面試的時候會被問到很多java專業(yè)性的知識,那么八股文就是為此而出現(xiàn)的,需要的朋友可以參考下
    2023-03-03
  • @Autowired自動裝配接口時存在多個實現(xiàn)的處理過程

    @Autowired自動裝配接口時存在多個實現(xiàn)的處理過程

    文章介紹了在Spring中@Autowired自動裝配接口如果存在多個實現(xiàn)類時的注入問題,建議通過@Resource或@Qualifier注解按名稱指定注入,避免編譯報錯,并分享了個人實踐經(jīng)驗
    2025-10-10

最新評論

浠水县| 沛县| 信阳市| 梓潼县| 镇远县| 恩平市| 鱼台县| 五大连池市| 得荣县| 武安市| 临安市| 安乡县| 石景山区| 兴隆县| 开封市| 伊川县| 沙洋县| 新竹市| 永康市| 陈巴尔虎旗| 明水县| 永春县| 永清县| 泗阳县| 印江| 伊宁县| 达孜县| 门头沟区| 东台市| 晋城| 安塞县| 舟山市| 邵阳市| 沅江市| 二连浩特市| 兴国县| 清河县| 麟游县| 沅江市| 和田县| 邹平县|