通过OrderDAO对象将订单插入HSQL数据库后,我希望能够检索在插入时分配给订单的序列号。
我有PreparedStatement
这个东西:
public long saveOrder(Order order) {
long orderId = 0;
try (Connection conn = MyDataSource.getDataSource().getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO orders(id, order_number) VALUES (NEXT VALUE FOR seq1, ?)",
PreparedStatement.RETURN_GENERATED_KEYS)) {
ps.setString(1, order.getOrderNumber());
ps.execute();
ResultSet rs = ps.getResultSet();
if (rs.next()) {
orderId = rs.getLong(1);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return orderId;
}
我会假设在执行查询并询问其结果集之后,结果集中的第一列将是序列号。但是看来我不是那样工作的。
我在哪里错了?
答案 0 :(得分:3)
您的代码有两个问题:
您使用了错误的方法来检索生成的键结果集。只能使用getGeneratedKeys()
(或至少是JDBC规范要求的)来检索生成的键结果集。
您需要更改代码以使用ps.getGeneratedKeys()
代替ps.getResultSet()
另一个问题是您的代码采用了非标准的生成键行为:您的插入实际上并没有按照JDBC规范的意图使用生成的键,因为您自己在insert语句中生成标识符(使用NEXT VALUE FOR seq1
),而不是作为插入语句的副作用(例如,通过标识列或触发器)生成密钥。
在这种情况下,HSQLDB不返回生成的键,因为它不将id
视为生成的列。取而代之的是,您需要将该列定义为一个标识列(并且不要在您的插入内容中显式指定它),或者显式指定要返回的列。
有关创建标识列的信息,请参阅HSQLDB文档。要明确指定要返回的列,请替换
conn.prepareStatement("<query>", PreparedStatement.RETURN_GENERATED_KEYS)
,其中包含要返回的列的索引说明(即1
是第一列):
conn.prepareStatement("<query>", new int[] { 1 })
或要返回的列的列名说明
conn.prepareStatement("<query>", new String[] { "id" })
您的最终代码应类似于:
try (PreparedStatement ps = conn.prepareStatement(
"INSERT INTO orders(id, order_number) VALUES (NEXT VALUE FOR seq1, ?)",
new String[] { "id" })) {
ps.setString(1, order.getOrderNumber());
ps.execute();
try (ResultSet rs = stmt.getGeneratedKeys()) {
if (rs.next()) {
return rs.getLong(1);
}
}
}
答案 1 :(得分:1)
基于this SO question and answer,您的语法应如下所示:
Connection conn = MyDataSource.getDataSource().getConnection();
long orderId = 0;
String sql = "INSERT INTO orders (id, order_number) VALUES (NEXT VALUE FOR seq1, ?)";
PreparedStatement ps = conn.prepareStatement(sql, RETURN_GENERATED_KEYS);
ps.setString(1, order.getOrderNumber());
int numAffected = ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
orderId = rs.getLong(1);
}