开发者社区> 问答> 正文

请教一个问题,druid是如何保证一个线程如果多次获取的connection是同一个的?

如果不是同一个Connection的话,事务可能会出问题。

原提问者GitHub用户bscoder1992

展开
收起
山海行 2023-07-05 20:50:41 523 0
4 条回答
写回答
取消 提交回答
  • Druid连接池通过使用ThreadLocal来实现线程内共享Connection的机制,这样可以保证同一线程中多次获取的Connection是同一个。具体来说,当一个线程第一次从连接池中获取连接时,Druid会在当前线程的ThreadLocal变量中保存连接对象;后续获取连接时,会首先检查ThreadLocal中是否已经存在连接对象,如果存在,则直接返回该连接对象;如果不存在,则会从连接池中获取一个新的连接对象并保存到ThreadLocal中,以便下次使用。

    这种方式可以确保在同一线程中,多次获取的Connection对象是同一个,并且可以解决事务问题。因为在同一事务中,需要使用同一个数据库连接来执行多个操作,以保持事务的一致性和隔离性。

    请注意,对于不同的线程,Druid连接池会为每个线程分配独立的连接对象。这样可以避免多个线程之间共享同一个Connection对象,从而保证线程安全性。

    通过以上机制,Druid连接池可以保证一个线程多次获取的Connection是同一个。如果您有其他疑问,请随时提问。

    2023-07-30 15:09:19
    赞同 展开评论 打赏
  • 北京阿里云ACE会长

    Druid连接池通过使用ThreadLocal来实现线程内共享Connection的机制,这样可以保证同一线程中获取的Connection是同一个。当一个线程第一次从连接池中获取连接时,Druid会在当前线程的ThreadLocal变量中保存连接对象,后续获取连接时,会首先检查ThreadLocal中是否已经存在连接对象,如果存在,则直接返回该连接对象,否则会从连接池中获取一个新的连接对象并保存到ThreadLocal中,以便下次使用。

    此外,Druid还提供了一些配置参数来控制连接池的行为,例如:maxPoolPreparedStatementPerConnectionSize(每个连接池中最大的预编译语句数量)和poolPreparedStatements(是否缓存预编译语句),这些参数可以根据应用的实际情况进行调整,以获得最佳的性能和可靠性。

    2023-07-30 13:14:42
    赞同 展开评论 打赏
  • 具体来说,Druid连接池会将连接池中的连接对象保存在一个Map中,Map的key是连接池中的连接对象,value是连接池中的连接对象的引用。当一个线程获取连接池中的连接对象时,Druid连接池会先检查Map中是否已经存在该连接对象的引用,如果存在,则将该连接对象的引用返回给该线程;如果不存在,则创建一个新的连接对象,并将其保存在Map中,以便其他线程也可以获取该连接对象。

    2023-07-11 10:24:29
    赞同 展开评论 打赏
  • 你指的多次获取是什么意思呢?是指同一个线程中多次调用DruidDataSource#getConnection()? 如果是上面这个意思的话,Druid自身是保证不了这个事情的吧,要你自己取到一个连接然后保存起来重用吧.

    Test code:

    `package cn.kenshinn.cube.app.config;

    import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidPooledConnection;

    import java.sql.SQLException;

    /**

    Created by kenshinn on 17-7-28. */ public class Test {

    public static void main(String[] args) { DruidDataSource druidDataSource = new Test().syncerDataSource(); try { DruidPooledConnection connection = druidDataSource.getConnection(); DruidPooledConnection connection2 = druidDataSource.getConnection(); DruidPooledConnection connection3 = druidDataSource.getConnection();

     System.out.println("foo");
    

    } catch (SQLException e) { e.printStackTrace(); }

    }

    private DruidDataSource syncerDataSource() { DruidDataSource dataSource = new DruidDataSource();

    try { dataSourceProperties(dataSource); } catch (Exception e){ e.printStackTrace(); }

    return dataSource;

    }

    private void dataSourceProperties(DruidDataSource dataSource) { String driverClass = "com.mysql.jdbc.Driver"; dataSource.setDriverClassName(driverClass);

    String jdbcUrl = "jdbc:mysql://host:3306/test_db?characterEncoding=UTF-8&autoReconnect=true&useSSL=false"; dataSource.setUrl(jdbcUrl);

    String username = "user"; dataSource.setUsername(username);

    String password = "key"; dataSource.setPassword(password);

    Integer initialPoolSize = 1; dataSource.setInitialSize(initialPoolSize);

    Integer connMinIdle = 1; dataSource.setMinIdle(connMinIdle);

    Integer connMaxActive = 150; dataSource.setMaxActive(connMaxActive);

    Integer maxWaitMillis = 60000; dataSource.setMaxWait(maxWaitMillis);

    Integer timeBetweenEvictionRunsMillis = 60000; dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

    Integer minEvictableIdleTimeMillis = 300000; dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);

    dataSource.setValidationQuery("SELECT 1"); dataSource.setTestOnBorrow(false); dataSource.setTestWhileIdle(true); dataSource.setTestOnReturn(false);

    dataSource.setPoolPreparedStatements(true); dataSource.setMaxPoolPreparedStatementPerConnectionSize(20); try { dataSource.setFilters("stat"); } catch (SQLException e) { e.printStackTrace(); }

    // always login dataSource.setLoginTimeout(0);

    dataSource.setRemoveAbandoned(true); dataSource.setRemoveAbandonedTimeout(30);

    原回答者GitHub用户lynchlee

    2023-07-06 11:45:44
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
多IO线程优化版 立即下载
低代码开发师(初级)实战教程 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载