在不同线程中运行 getConnection 时,HikariCP.getConnection() 是否返回相同的连接?

问题描述 投票:0回答:0

我目前正在使用 Hikari 连接池。

当我在不同的线程中运行

hikariDataSource.getConnection()
时,我得到了相同的连接。

在我看来,通过

@Transactional
,JDBC连接首先设置在
TransactionSynchronizationManager
中,也就是ThreadLocal。而 JDBC 连接仅在线程内有效。但是,正如您在
userRepositoryJDBC.findUser(..)
方法中看到的那样,即使在不同线程中获得连接后,活动连接数仍然相同。

总结一下我的想法,

nio-8080-exec-2
线程本地有JDBC连接,但是当
db-thread-1
线程请求连接时,HikariCP也返回同样的连接给
db-thread-1
。我认为这个问题是由于 lambda 捕获而发生的。当我使用 CompletableFuture 和 lambda 表达式运行一个新线程时,lambda 捕获局部变量(具有包含该连接的 TransactionSynchronizationManager)。

但即使这是因为lambda捕获,

db-thread-1
仍然无法打印
TransactionSynchronizationManager.getCurrentTransactionName()
.

所以,请告诉我我错过了什么,错了什么。

我的代码在下面。

结果

[nio-8080-exec-2] c.c.domain.user.service.UserServiceImpl  : currentTXName:chatting.chat.domain.user.service.UserServiceImpl.login
[nio-8080-exec-2] c.c.domain.user.service.UserServiceImpl  : HikariCP[Total:10, Active:1, Idle:9, Wait:0]
[nio-8080-exec-2] c.c.d.u.repository.UserRepositoryJDBC    : currentTXName:chatting.chat.domain.user.service.UserServiceImpl.login
[nio-8080-exec-2] c.c.d.u.repository.UserRepositoryJDBC    : HikariCP[Total:10, Active:1, Idle:9, Wait:0]
[    db-thread-1] c.c.d.u.repository.UserRepositoryJDBC    : currentTXName:null
[    db-thread-1] c.c.d.u.repository.UserRepositoryJDBC    : HikariCP[Total:10, Active:1, Idle:9, Wait:0] before get connection
[    db-thread-1] c.c.d.u.repository.UserRepositoryJDBC    : HikariCP[Total:10, Active:1, Idle:9, Wait:0] after get connection
[    db-thread-1] c.c.d.u.repository.UserRepositoryJDBC    : HikariCP[Total:10, Active:0, Idle:10, Wait:0]after release connection

UserServiceImpl.java

@Service
public class UserServiceImpl {
    ...
    @Transactional
    public DeferredResult<ResponseEntity<?>> login(String userId, String userPw) throws CustomException{
        DeferredResult<ResponseEntity<?>> dr = new DeferredResult<>();

        printCurrentTXName(); // login
        printHikariStatus(); // [HikariCP:Active=1]

        userRepositoryJDBC.findUser(userId, userPw)
                .thenComposeAsync(user->{

                    printHikariCPInfo(); // [HikariCP:Active=0]

                    ...
                },serviceExecutor).thenAcceptAsync((rs)->{
                    log.info("currentTXName:"+TransactionSynchronizationManager.getCurrentTransactionName());
                    printHikariCPInfo();
                    ...
                },serviceExecutor)
                .exceptionally(e-> {
                    ...
                });
        return dr;
    }
}

UserRepositoryJDBC.java

public class UserRepositoryJDBC {
    ...
    @Transactional
    public CompletableFuture<User> findUser(String user_id, String user_pw) {

        printCurrentTXName(); // login
        printHikariStatus(); // [HikariCP:Active=1]
                
        return CompletableFuture.supplyAsync(()->{
            PreparedStatement pstmt = null;
            Connection conn = null;
            ResultSet rs = null;

            printCurrentTXName(); // null

            ...

            try {
                printHikariStatus(); // before get connection [HikariCP:Active=1]
                conn = hikariDataSource.getConnection();
                log.info(printHikariCPInfo()+" after get connection"); // Still Active is 1, even if get connection in different thread
                ...
            } catch (SQLException e) {
                throw new RuntimeException(e);
            } catch (CustomException customException){
                throw customException;
            } finally {
                if(rs != null) try { rs.close();} catch(SQLException ex) {}
                if(pstmt != null) try { pstmt.close();} catch(SQLException ex) {}
                if(conn != null) try {
                    conn.close();
                    log.info(printHikariCPInfo()+" after release connection");
                } catch(SQLException ex) {}
            }
        },databaseExecutor).exceptionally(e->{
            ...
        });
    }
}

为什么HikariCP在不同的线程中返回相同的连接?如果 lambda 表达式捕获局部变量,为什么

TransactionSynchronizationManager.getCurrentTransactionName()
为空?

java spring-boot asynchronous transactions hikaricp
© www.soinside.com 2019 - 2024. All rights reserved.