我正在开发一个Spring Boot web(REST)应用程序,我需要在其中处理许多请求。因此,我希望我的应用程序能够同时处理请求。由于 Spring Boot REST-Services 是开箱即用的并发可用的,我只需要使 (PostgreSQL) 数据库访问并发可访问。为此,我使用的是HikariCP数据源。
因为我的许多语句都是准备好的语句,所以我用一种方法收集它们,在这种方法中,我调用pstmt= connection.prepare语句("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/brettwooldridge/HikariCP
许多连接池,包括Apache DBCP、Vibur、c3p0等都提供了PreparedStatement缓存。HikariCP没有。为什么?
所以它不缓存。如果你读了解释,也许你决定你不需要它。