简体   繁体   English

java.sql.SQLException: ORA-01002: 乱序获取

[英]java.sql.SQLException: ORA-01002: fetch out of sequence

I have one demo application to check select for update query我有一个演示应用程序来检查 select 以进行更新查询

public class Test implements Runnable{

    public Test() {
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Test());
        Thread t2 = new Thread(new Test());

        t1.start();
        t2.start();
    }

    public void run() {
        // TODO Auto-generated method stub
        try{
            String updateWith = "";
            String sel = "SELECT SIDNUMBERTO FROM tblmserialbatchdetail WHERE sidnumberto = ("+
            "SELECT max(sidnumberto) FROM tblmserialbatchdetail WHERE generationmode='A' and nvl(serialprefix,' ') = nvl('',' ') " +
            "and sidlengthwithoutprefix =12) FOR UPDATE";
            //System.out.println("SELECT QUERY ===: "+sel);
            String updatequery = "update tblmserialbatchdetail set sidnumberto = ? where serialbatchid = ?";
            System.out.println();
            Connection connection = Conn.getDBConnection();
            PreparedStatement pStatement = connection.prepareStatement(sel);

            ResultSet rSet = pStatement.executeQuery();

            while(rSet.next()){

                updateWith = rSet.getString(1);
                long value = Long.parseLong(updateWith)+1;
                updateWith = String.valueOf(value);
                System.out.println("resulet To be Updated ===> "+value);
            }
            connection.commit();
            connection.close();



        }catch (Exception e) {
            e.printStackTrace();
        }
    }

}

This works fine if i remove For update from select query otherwise give me error如果我从 select 查询中删除 For update 则这很好用否则会给我错误

java.sql.SQLException: ORA-01002: fetch out of sequence

    at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:180)
    at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:208)
    at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:543)
    at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1451)
    at oracle.jdbc.ttc7.TTC7Protocol.fetch(TTC7Protocol.java:943)
    at oracle.jdbc.driver.OracleStatement.doExecuteQuery(OracleStatement.java:2119)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2324)
    at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:421)
    at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:365)
    at com.response.Test.run(Test.java:47)
    at java.lang.Thread.run(Thread.java:595)

SELCT ... FOR UPDATE only makes sense in the context of a managed transaction, since it requires locks to be taken out on the selected rows. SELCT ... FOR UPDATE仅在托管事务的上下文中才有意义,因为它要求对选定的行进行锁定。

By default, JDBC does not use a managed transaction, it uses an implicitly created one that commits as soon as the query is executed. 默认情况下,JDBC不使用托管事务,而是使用隐式创建的事务,该事务在查询执行后立即提交。 This will break the semantics of SELECT ... FOR UPDATE , and the JDBC driver complains. 这将破坏SELECT ... FOR UPDATE的语义,并且JDBC驱动程序会抱怨。

In order to use a managed transaction, add 为了使用托管交易,请添加

connection.setAutoCommit(false); 

before you execute the query. 在执行查询之前。 Afterwards, execute connection.commit() . 然后,执行connection.commit()

I got the ORA-01002: fetch out of sequence issue with Spring JPA- Native SQL, for ORACLE MERGE statement. 我得到了ORA-01002:对于Oracle ORACLE MERGE语句,Spring JPA-Native SQL无法按顺序获取问题。

Issue is with hibernate session, I fixed it passing my datasource to jdbctemplate. 休眠会话的问题是,我修复了将数据源传递给jdbctemplate的问题。 Excluding Spring JPA native SQL and migrating to JDBC template resolved issue for me. 不包括Spring JPA本机SQL并迁移到JDBC模板对我来说解决了问题。 I got issue only for ORACLE Merge statement and not for other SQL queries. 我只有ORACLE Merge语句有问题,而其他SQL查询没有问题。

@Bean public JdbcTemplate getJdbcTemplate() throws Exception{ Map dataSources = applicationContext.getBeansOfType(DataSource.class); @Bean public JdbcTemplate getJdbcTemplate()引发异常{地图dataSources = applicationContext.getBeansOfType(DataSource.class); Objects.requireNonNull(dataSources, "Data Source is required"); Objects.requireNonNull(dataSources,“需要数据源”);

    DataSource dataSource = dataSources.entrySet().stream()
            .filter(entry->entry.getKey().startsWith("abc"))
            .map(Map.Entry::getValue)
            .findAny().orElseThrow(()-> new Exception("DataSource ABC is required."));

    return new JdbcTemplate(dataSource);
}

instead of using executeQuery, you can use executeUpdate function. 代替使用executeQuery,可以使用executeUpdate函数。 Do not use "select for update" instead directly try to update the rows in one transaction, This will give you the updated rows count. 不要使用“选择更新”,而是直接尝试在一个事务中更新行,这将为您提供更新的行数。 This way for example when two transaction tries to update a row , first one wins other returns zero and you know that first succeeds to update since it will return updated rowcount. 这样,例如,当两个事务尝试更新一行时,第一个事务赢得另一个则返回零,并且您知道第一个事务成功更新,因为它将返回更新的行数。

You might need to use @Modifying for DDL queries when using @Query在使用 @Query 时,您可能需要对 DDL 查询使用 @Modifying

Try: 尝试:

connection.setAutoCommit(false); 

As a general note, 'select ... for update' is not the best locking strategy. 作为一般说明,“选择...进行更新”不是最佳的锁定策略。

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

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