Return 插入序列号
Return sequence number on insert
通过我的 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;
}
我假设,在执行查询并请求其结果集之后,结果集中的第一列将是序列号。不过我好像不是这样的
我哪里出错了?
基于 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);
}
您的代码有两个问题:
您使用了错误的方法来检索生成的键结果集。生成的键结果集只能使用 getGeneratedKeys()
检索(或者至少,这是 JDBC 规范所要求的)。
您需要更改代码以使用 ps.getGeneratedKeys()
而不是 ps.getResultSet()
另一个问题是您的代码假设了非标准的生成键行为:您的插入实际上并没有使用 JDBC 规范预期的生成键,因为您正在生成自己在插入语句中的标识符(使用 NEXT VALUE FOR seq1
),而不是作为插入语句的副作用生成的键(例如,通过标识列或触发器)。
HSQLDB 在这种情况下不会 return 生成键,因为它不会将 id
视为生成列。相反,您需要将该列定义为标识列(并且不要在您的插入中明确指定它),或者明确地将列指定为 return.
要创建标识列,请参阅 HSQLDB 文档。要明确指定要 return 的列,请替换
conn.prepareStatement("<query>", PreparedStatement.RETURN_GENERATED_KEYS)
将列的索引指定为 return(即 1
是第一列):
conn.prepareStatement("<query>", new int[] { 1 })
或列的列名规范 return
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);
}
}
}
通过我的 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;
}
我假设,在执行查询并请求其结果集之后,结果集中的第一列将是序列号。不过我好像不是这样的
我哪里出错了?
基于 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);
}
您的代码有两个问题:
您使用了错误的方法来检索生成的键结果集。生成的键结果集只能使用
getGeneratedKeys()
检索(或者至少,这是 JDBC 规范所要求的)。您需要更改代码以使用
ps.getGeneratedKeys()
而不是ps.getResultSet()
另一个问题是您的代码假设了非标准的生成键行为:您的插入实际上并没有使用 JDBC 规范预期的生成键,因为您正在生成自己在插入语句中的标识符(使用
NEXT VALUE FOR seq1
),而不是作为插入语句的副作用生成的键(例如,通过标识列或触发器)。HSQLDB 在这种情况下不会 return 生成键,因为它不会将
id
视为生成列。相反,您需要将该列定义为标识列(并且不要在您的插入中明确指定它),或者明确地将列指定为 return.要创建标识列,请参阅 HSQLDB 文档。要明确指定要 return 的列,请替换
conn.prepareStatement("<query>", PreparedStatement.RETURN_GENERATED_KEYS)
将列的索引指定为 return(即
1
是第一列):conn.prepareStatement("<query>", new int[] { 1 })
或列的列名规范 return
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);
}
}
}