7

假设我有三张表:team、player、team_player。表 team_player 是一个允许“多对多”关系的桥接表。

当有人想要创建一个新团队时,他们会指定该团队的初始玩家。

如何在同一事务中同时插入 team 和 team_player 行?也就是说,我想在提交到新的团队行之前插入所有 team_player 记录。我正在使用 JDBC 和 Oracle。

当我尝试下面的代码时,即使 team.id 是一个数字(由触发器递增),teamId 也会填充一串字母。因此,这似乎不是我刚刚尝试插入的记录的 ID(但尚未提交)。

c = DB.getConnection();
c.setAutoCommit(false);

sql = "INSERT INTO team (name) values (?)";
myInsert = c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
myInsert.setString(1, "cougars");
int affectedRows = memoInsert.executeUpdate();

String teamId;
ResultSet generatedKeys = myInsert.getGeneratedKeys();
if (generatedKeys.next()) {
    teamId = generatedKeys.getString(1);
}

// ...loop through players inserting each player and team.id into team_player

// c.commit();

这是我阅读 RETURN_GENERATED_KEYS 的地方: 如何在 JDBC 中获取插入 ID?

4

3 回答 3

11

Oracle JDBC 驱动程序不支持getGeneratedKeys()- 您在触发器中手动生成键,可能来自SEQUENCE.

您可以使用 Oracle 的返回子句:

String query = "BEGIN INSERT INTO team (name) values (?) returning id into ?; END;";
CallableStatement cs = conn.prepareCall(query);
cs.setString(1, "cougars");
cs.registerOutParameter(2, OracleTypes.NUMBER);
cs.execute();
System.out.println(cs.getInt(2));

或者使用第二个 SQL 查询获取最后一个序列号:

SELECT mysequence.CURRVAL FROM dual
于 2013-07-03T23:06:28.630 回答
3

您需要告诉驱动程序返回哪一列。

如果您的 ID 由触发器填充,则以下内容将起作用:

sql = "INSERT INTO team (name) values (?)";

// pass an array of column names to be returned by the driver instead of the int value
// this assumes the column is named ID (I think it has to be all uppercase)

myInsert = c.prepareStatement(sql, new String[]{"ID"});

myInsert.setString(1, "cougars");
int affectedRows = memoInsert.executeUpdate();

String teamId;
ResultSet generatedKeys = myInsert.getGeneratedKeys();
if (generatedKeys.next()) {
    teamId = generatedKeys.getString(1);
}
于 2013-07-04T06:41:06.817 回答
1

请参阅Statement.getGeneratedKeys() - 它为您返回生成密钥的结果集。我相信这就是您所寻求的。

基本上,Spring jdbc 使用这种方法来检索生成的 id(来自 JdbcTemplate 类的示例

一个不太优雅的解决方案是使用 Oracle 的RETURNING 子句,但是您必须将插入包装到存储过程中才能取回 id

于 2013-07-03T23:04:48.127 回答