【发布时间】:2016-11-27 09:37:00
【问题描述】:
我有一个名为 PRODUCTS 的 H2 数据库,每行有 5000 行和 55 列。我目前正在使用PreparedStatement 将值行添加到数据库中,但它不会检查该行是否已经存在。相反,如果列名“id”(VARCHAR 类型)不包含某个字母数字字符串,并且列名“id2”(VARCHAR 类型)不某个字母数字字符串,如果列名“raw_yn”(BOOLEAN 类型)包含false。我在准备好的语句中输入的值是通过方法提供的。
here 的问题与我要问的问题非常接近,不同之处在于solution 是基于向空数据库添加行,并确保数据库为空。 H2的创造者评论说:
然后“不存在的地方”确保仅在以下情况下插入此行 表 [TABLE] 为空。
如果满足我的上述 3 个要求(无论 DB 是否为空),我如何调整此代码使其仅执行 INSERT 查询?
目前我有:
import java.sql. *;
static final String JDBC_DRIVER = "org.h2.Driver";
static final String DB_URL = "jdbc:h2:~/myDB";
static final String USER = "test";
static final String PASS = "test";
static final Connection conn = null;
static final Statement stmt = null;
public class DataBaseManager {
public void insertIntoDB(String id1val, String id2val, Boolean raw_yn_val, ...,...) {
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USER, PASS);
myStatement = "INSERT INTO PRODUCTS VALUES(?,?,?,..,...)";
stmt = conn.prepareStatement(myStatement);
stmt.setString(1, id1val);
stmt.setString(2, id2val);
stmt.setBoolean(3, raw_yn_val);
stmt.setString(4,....);
// Continue up to 55
stmt.executeUpdate();
}
[catch&finally blocks]
}
}
myStatement 应该改成什么?我很困惑,因为如果我像下面这样使用select 0, 'id1' union,它如何适合我的PreparedStatement 或stmt.setString(1, id1val); ??。感谢您的帮助。
INSERT INTO PRODUCTS SELECT * FROM(
select 0, 'id1' union // <--- How does this fit into Prepared Statement?
select 1, 'id2' union
select 2, 'raw_yn' union
) x where not exists(SELECT * FROM PRODUCTS); // <--- Ensures only works when empty
更新:
按照 Gord 的建议,我整理了以下代码。如果数据库为空,n 将返回 0。这大约需要 1 分钟才能将 5000 行添加到空数据库。但是,如果有匹配项,则需要将近 5 倍的时间,即使我只是使用 return 而不是使用额外的 INSERT 代码。所以不应该更快吗?
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USER, PASS);
statement = conn.createStatement();
String sql = "SELECT COUNT(*) AS n FROM PROPERTIES WHERE id1='" + id1 + "' AND id2='" + id2 + "' AND raw_yn='true'";
rs = statement.executeQuery(sql);
rs.next();
if (rs.getInt("n") == 0) {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USER, PASS);
myStatement = "INSERT INTO PROPERTIES VALUES(?,?,?,...)";
stmt = conn.prepareStatement(myStatement);
stmt.setString(1, id1);
stmt.setString(2, id2);
stmt.setBoolean(3, raw_yn);
stmt.executeUpdate();
} else {
return; // <-- Takes 5x longer to go through ???
}
}
[catch & finally blocks]
【问题讨论】:
-
由于看起来您将一次插入一行,也许您的
insertIntoDB方法可以执行SELECT COUNT(*) AS n FROM PRODUCTS WHERE ...来确定所需的行是否已经存在,然后只执行@ 987654340@ 如果不是(即,如果来自SELECT的行数为零)。 -
考虑使用暂存临时表 ProductsTemp,然后迁移到每个行检查的最终 Products。但是,检查 55 个值可能很乏味,还是您只想检查 id、id2 和 raw_yn?
-
"但是如何访问 n 来获取计数?" - 你需要做
rs.next();然后你可以使用rs.getInt("n")或rs.getInt(1)跨度> -
第二次通过不必执行 INSERT 来节省时间,但 SELECT 将花费更长的时间,因为表包含更多行。您的表是否在
id1、id2和raw_yn列上有索引? -
我指的是在 H2 表本身的结构中定义的索引。也就是说,如果在 H2 控制台中执行
SCRIPT NODATA TABLE "PROPERTIES",输出是否包含id1、id2和raw_yn列的CREATE INDEX语句(或类似语句)?如果没有,您可以使用CREATE INDEX 语句添加它们。