简体   繁体   English

PLSQL JDBC:如何获取最后一行 ID?

[英]PLSQL JDBC: How to get last row ID?

What's PLSQL (Oracle) equivalent of this SQL server snippet?这个 SQL 服务器片段的 PLSQL (Oracle) 等价物是什么?

BEGIN TRAN
INSERT INTO mytable(content) VALUES ("test") -- assume there's an ID column that is autoincrement
SELECT @@IDENTITY
COMMIT TRAN

In C#, you can call myCommand.ExecuteScalar() to retrieve the ID of the new row.在 C# 中,您可以调用 myCommand.ExecuteScalar() 来检索新行的 ID。

How can I insert a new row in Oracle, and have JDBC get a copy of the new id?如何在 Oracle 中插入新行,并让 JDBC 获取新 ID 的副本?

EDIT: BalusC provided a very good starting point.编辑: BalusC 提供了一个很好的起点。 For some reason JDBC doesn't like named parameter binding.出于某种原因,JDBC 不喜欢命名参数绑定。 This gives "Incorrectly set or registered parameters" SQLException.这给出了“错误设置或注册的参数”SQLException。 Why is this happening?为什么会这样?

        OracleConnection conn = getAppConnection();
        String q = "BEGIN INSERT INTO tb (id) values (claim_seq.nextval) returning id into :newId; end;" ;
        CallableStatement cs = (OracleCallableStatement) conn.prepareCall(q);
        cs.registerOutParameter("newId", OracleTypes.NUMBER);
        cs.execute();
        int newId = cs.getInt("newId");

Normally you would use Statement#getGeneratedKeys() for this (see also this answer for an example), but this is as far (still) not supported by the Oracle JDBC driver.通常,您会为此使用Statement#getGeneratedKeys() (另请参阅此答案的示例),但 Oracle JDBC 驱动程序目前(仍然)不支持此功能。

Your best bet is to either make use of CallableStatement with a RETURNING clause:最好的办法使用CallableStatementRETURNING子句:

String sql = "BEGIN INSERT INTO mytable(id, content) VALUES (seq_mytable.NEXTVAL(), ?) RETURNING id INTO ?; END;";

Connection connection = null;
CallableStatement statement = null;

try {
    connection = database.getConnection();
    statement = connection.prepareCall(sql);
    statement.setString(1, "test");
    statement.registerOutParameter(2, Types.NUMERIC);
    statement.execute();
    int id = statement.getInt(2);
    // ...

Or fire SELECT sequencename.CURRVAL after INSERT in the same transaction:或者在同一个事务中的INSERT之后触发SELECT sequencename.CURRVAL

String sql_insert = "INSERT INTO mytable(content) VALUES (?)";
String sql_currval = "SELECT seq_mytable.CURRVAL FROM dual";

Connection connection = null;
PreparedStatement statement = null;
Statement currvalStatement = null;
ResultSet currvalResultSet = null;

try {
    connection = database.getConnection();
    connection.setAutoCommit(false);
    statement = connection.prepareStatement(sql_insert);
    statement.setString(1, "test");
    statement.executeUpdate();
    currvalStatement = connection.createStatement();
    currvalResultSet = currvalStatement.executeQuery(sql_currval);
    if (currvalResultSet.next()) {
        int id = currvalResultSet.getInt(1);
    }
    connection.commit();
    // ...

You can use Oracle's returning clause.您可以使用 Oracle 的返回子句。

insert into mytable(content) values ('test') returning your_id into :var;

Check out this link for a code sample.查看 此链接以获取代码示例。 You need Oracle 10g or later, and a new version of JDBC driver.您需要 Oracle 10g 或更高版本,以及新版本的 JDBC 驱动程序。

You can use getGeneratedKeys(), By explicitly selecting key field.您可以使用 getGeneratedKeys(),通过显式选择键字段。 Here is a snippet:这是一个片段:

    // change the string to your connection string
    Connection connection = DriverManager.getConnection("connection string");

    // assume that the field "id" is PK, and PK-trigger exists 
    String sql = "insert into my_table(id) values (default)";
    // you can select key field by field index
    int[] colIdxes = { 1 };
    // or by field name
    String[] colNames = { "id" };

    // Java 1.7 syntax; try-finally for older versions
    try (PreparedStatement preparedStatement = connection.prepareStatement(sql, colNames))
    {
        // note: oracle JDBC driver do not support auto-generated key feature with batch update
        //          // insert 5 rows
        //          for (int i = 0; i < 5; i++)
        //          {
        //              preparedStatement.addBatch();
        //          }
        //          
        //          int[] batch = preparedStatement.executeBatch();
        preparedStatement.executeUpdate();

        // get generated keys
        try (ResultSet resultSet = preparedStatement.getGeneratedKeys())
        {
            while (resultSet.next())
            {
                // assume that the key's type is BIGINT
                long id = resultSet.getLong(1);
                assertTrue(id != 0);

                System.out.println(id);
            }
        }
    }

refer for details: http://docs.oracle.com/cd/E16655_01/java.121/e17657/jdbcvers.htm#CHDEGDHJ详情请参考: http : //docs.oracle.com/cd/E16655_01/java.121/e17657/jdbcvers.htm#CHDEGDHJ

In case if you use spring-jdbc for database you can consider neat wrappers from morejdbc , it will look like this:如果您将spring-jdbc用于数据库,您可以考虑使用morejdbc 的整洁包装器,它将如下所示:

import static org.morejdbc.SqlTypes.BIGINT;
import static org.morejdbc.JdbcCall.callSql;
import static org.morejdbc.*;
...

Out<Long> idOut = Out.of(BIGINT);
jdbcTemplate.execute(callSql("BEGIN INSERT INTO mytable(id, content) VALUES (seq_mytable.NEXTVAL(), ?) "
        + "RETURNING id INTO ?; END;")
        .in(content)
        .out(BIGINT, idOut));
System.out.println("Id is " + idOut.get());

If you have a pojo like如果你有一个喜欢的 pojo

@lombok.Data
public class Entity {
    private long id;
    private String content;
}

it can be even more laconic:它可以更简洁:

Entity entity = ;

jdbcTemplate.execute(callSql("BEGIN INSERT INTO mytable(id, content) VALUES (seq_mytable.NEXTVAL(), ?) "
        + "RETURNING id INTO ?; END;")
        .in(entity.getContent())
        .out(BIGINT, entity::setId));
System.out.println("Id is " + entity.get());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM