繁体   English   中英

如何使用带有准备好的语句的 HikariCP 连接池?

[英]How to use a HikariCP connection pool with prepared statements?

我正在开发一个 Spring Boot web (REST) 应用程序,我需要在其中处理许多请求。 因此我希望我的应用程序能够同时处理请求。 由于 Spring 引导 REST 服务是开箱即用的并发可用,我只需要使 (PostgreSQL) 数据库访问并发访问。 为此,我正在使用 HikariCP 数据源。

由于我的很多语句都是准备好的语句,因此我将它们收集在一种调用pstmt = connection.prepareStatement("SQLCODE");的方法中。 每个语句一次。 当处理来自 REST 服务的用户交互时,这些准备好的语句将用于各种方法。

现在,当我使用 HikariCP 时,我不能再这样做了,可以吗? 当我准备一个语句时,这个语句绑定到一个连接。 如果我然后尝试同时访问它,我不能,因为连接未共享。

我错过了什么吗? 我该如何解决这个问题? 我是否需要从池中检索连接、在本地准备语句、执行查询并关闭连接? 如果是这样,那么使用准备好的语句有什么意义(除了防止 SQL 注入)?

我知道这些语句是在 PostreSQL 端缓存的。 那么保留所有准备好的语句都准备好的方法是个好主意吗? 将它们发送到数据库缓存。 然后再次在本地创建相同的语句。 这样,人们仍然可以利用数据库的缓存可能性。 但另一方面,这将是非常丑陋的代码。

我正在使用 Spring:5.3.10、Java:11、PostgreSQL:14.0

@RestController
public class RESTController {
    
    /** The database controller. */
    private DBController dbc;
    
    /** The data source object serving as a connection pool. */
    private HikariDataSource ds;
    
    /** The logger object for this class. */
    private static Logger logger = LoggerFactory.getLogger(RESTController.class);
    
    public RESTController(DBController dbc, Config config) {
        this.dbc = dbc;

        // Create the database
        if (!this.dbc.createDB(config)) {
            logger.error("Couldn't create the database. The service will now exit.");
            Runtime.getRuntime().halt(1);
        }
        
        // Create a connection pool
        ds = new HikariDataSource();
        ds.setJdbcUrl(config.getUrl());
        ds.setUsername(config.getUser());
        ds.setPassword(config.getPassword());
        ds.addDataSourceProperty("cachePrepStmts", "true");
        ds.addDataSourceProperty("prepStmtCacheSize", "250");
        ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        
        // Create the necessary tables
        if (!this.dbc.createTables(ds)) {
            logger.error("Couldn't create the tables. The service will now exit.");
            ds.close();
            Runtime.getRuntime().halt(1);
        }
        
        // Prepare SQL statements
        if (!this.dbc.prepareStatements(ds)) {
            logger.error("Couldn't prepare the SQL statements. The service will now exit.");
            ds.close();
            Runtime.getRuntime().halt(1);
        }
    }
    
    @PostMapping("/ID")
    public ResponseEntity<String> createNewDomain(@RequestParam(name = "name", required = true) String name) {
        // Do stuff ...
    }

    // [...]
}
@Component
public class DBController {

    /** The logger object for this class. */
    private static Logger logger = LoggerFactory.getLogger(DBController.class);
    
    // Prepared Statements
    private PreparedStatement stmt1, stmt2, stmt3;

    public boolean prepareStatements(HikariDataSource ds) {
        try {
            // Get connection from the pool
            Connection c = ds.getConnection();
            
            // Prepare all the statements
            stmt1 = c.prepareStatement("SQLCODE");
            stmt2 = c.prepareStatement("SQLCODE1");
            stmt2 = c.prepareStatement("SQLCODE1");
            // [...]
            
        } catch (SQLException e) {
            logger.debug("Could not prepare the SQL statements: " + e.getMessage());
            return false;
        }
        
        logger.debug("Successfully prepared the SQL statements.");
        return true;
    }

    public boolean m1(int i) {
        stmt1.setInt(i);
        ResultSet rs = stmt1.executeQuery();
    }

    public boolean m2(int j) {
        stmt1.setInt(j);
        ResultSet rs = stmt1.executeQuery();
    }

    public boolean m3(String a) {
        stmt2.setString(a);
        ResultSet rs = stmt2.executeQuery();
    }

    // [...]

}

提前致谢。

请阅读 https 上的声明缓存部分://github.com/brettwoldridge/HikariCP

许多连接池,包括 Apache DBCP、Vibur、c3p0 等都提供 PreparedStatement 缓存。 HikariCP 没有。 为什么?

所以它不缓存。 如果您阅读了解释,也许您会决定不需要它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM