用 H2 数据库理解 JdbcConnectionPool

Posted

技术标签:

【中文标题】用 H2 数据库理解 JdbcConnectionPool【英文标题】:Understanding JdbcConnectionPool with H2 database 【发布时间】:2014-11-21 19:44:08 【问题描述】:

我的主服务器机器上运行着一个 H2 服务器进程,允许 TCP 连接。

假设我要执行 100 个 SQL 查询:

SELECT * FROM TEST

而且,出于我自己的目的,我想对每个线程进行一次查询。让我们在线程之间共享一个且只有一个 Connection 对象:

创建一个Connection 对象。 创建 100 个线程。 在每个线程中,使用共享的Connection 对象调用SQL 查询。

上述方法可行,但会有点慢。当然,毕竟如果有人用Connection,那其他人就得等了。

那么,让我们为每个线程创建一个Connection

创建 100 个线程。 在每个线程中,创建一个新的Connection 对象并调用SQL 查询。

快得多。但我觉得 100 个连接有点浪费。也许 50 个连接就可以了。听说这种事情可以用JdbcConnectionPool

创建一个最多有 50 个连接的 JdbcConnectionPool。 创建 100 个线程。 在每个线程中,使用pool.getConnection(),然后调用SQL查询。

嗯。它很慢。如果有的话,它和第一种方法一样慢。也许,出于好奇,我应该将最大连接数设置为100...

...它仍然很慢。奇怪的。我的理解是,一个有 100 个连接的池相当于为我的 100 个线程中的每个线程建立一个连接。

可能是什么问题?这是最后一次测试的代码:

import java.sql.Connection;
import java.sql.ResultSet;

import org.h2.jdbcx.JdbcConnectionPool;

public class App 

    public static void main(String[] args) throws Exception 
        Class.forName("org.h2.Driver");
        JdbcConnectionPool pool = JdbcConnectionPool.create("url", "user", "password");
        pool.setMaxConnections(100);
        for (int i = 0; i < 100; ++i) 
            Thread t = new Thread(new Client(i, pool));
            t.start();
        
    


class Client implements Runnable 
    int id;
    JdbcConnectionPool pool;
    public Client(int id, JdbcConnectionPool pool) 
        this.id = id;
        this.pool = pool;
    
    public void run() 
        try 
            Connection conn = pool.getConnection();
            ResultSet set = conn.createStatement().executeQuery("SELECT * FROM TEST");
            if (set.next()) 
                System.out.println("Finished " + id);
            
            set.close();
            conn.close();
        catch (Exception e) 

        
    


我正在使用H2 1.4.182

【问题讨论】:

最后你变成用什么连接池了,可以看看例子吗? @user2602807 我相信当时的这个项目是一样的 - JdbcConnectionPool。答案是正确的:由于初始化,它很慢,但之后它就像预期的那样快。所以基本上我在问题中发布的示例很好 - 它只需要预热。 【参考方案1】:

JdbcConnectionPool#getConnection()的源码

  public Connection getConnection() throws SQLException 
        long max = System.currentTimeMillis() + timeout * 1000;
        do 
              synchronized (this)
                if (activeConnections < maxConnections) 
                    return getConnectionNow();
                
                try 
                    wait(1000);
                 catch (InterruptedException e) 
                    // ignore
                
            
         while (System.currentTimeMillis() <= max);
        throw new SQLException("Login timeout", "08001", 8001);
    

您的示例中最昂贵的操作之一是创建连接。如您所见,方法getConnection() 具有锁同步(this),因此只有一个线程可以同时创建连接,所有其他线程都在等待。

我相信内置的 h2 连接池非常简单。如果你想拥有高性能的连接池,你可以看看 C3P0 或 BoneCP。

【讨论】:

以上是关于用 H2 数据库理解 JdbcConnectionPool的主要内容,如果未能解决你的问题,请参考以下文章

如何将 NewProxyConnection 类型转换为 AS400JDBCConnection

如何使用嵌入式数据库 H2 创建 jar 文件?

如何使用 HSQLDB API 的 org.hsqldb.jdbc.JDBCConnection 类

用 H2 测试 Spring Boot 数据库的正确方法是啥?

h2o二分类,理解p0和p1

h2 sql,用多列主键创建表?