如果遇到瞬态异常,我可以重新使用PreparedStatement吗?

Dav*_*ave 5 java mysql innodb jdbc

我有一段代码来更新数据库中的记录.减少的例子:

...
statement = connection.prepareStatement(
    "INSERT INTO thistable (name) VALUES (?)",
    PreparedStatement.RETURN_GENERATED_KEYS
);
statement.setString( 1, "Fred" );
statement.addBatch( );
statement.setString( 2, "Joe" );
statement.addBatch( );
statement.executeBatch( );
...
Run Code Online (Sandbox Code Playgroud)

这是处理大量记录的一些代码的一部分,代码运行了很多线程以提高速度.这一切都很好,但随着现场环境的负载增加,我一直注意到有几个SQLTransientException被抛出.除了重试交易之外,似乎我无法做任何事情.

我的问题是:即使声明失败,批次是否已被清除?我可以简单地重试该executeBatch行,还是需要重新创建整批产品?对于非批处理语句,这是一样的吗?


简而言之,更一般地说,这是处理瞬态异常的好方法吗?

statement.setString( 1, "Fred" );
statement.addBatch( );
statement.setString( 2, "Joe" );
statement.addBatch( );
for( int attempt = 0; ; attempt ++ ) {
    try {
        statement.executeBatch( );
        break;
    } catch( SQLTransientException ex ) {
        if( attempt >= 3 ) {
            throw ex;
        }
        try {
            Thread.sleep( attempt * attempt * 100 );
        } catch( InterruptedException ex2 ) {
            throw ex;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Man*_*ani 2

由于除了下面的内容之外, API没有提供有关 SQLTransientException 发生时的行为的太多信息

\n\n
 when the driver has determined that the timeout value that was specified by the \n setQueryTimeout method has been exceeded and has at least attempted\n to cancel the currently running Statement\n
Run Code Online (Sandbox Code Playgroud)\n\n

验证了 Mysql JDBC4 实现。

\n\n

根据我的观察,我可以看到如果超时,可能会发生一种情况SQLTimeoutException(即)。SQLTransientException

\n\n

当超时时,它不仅仅是清除最后的语句,而是清除整个Batch(至少在MYSQL实现中)

\n\n
// we timeout the entire batch, not individual statements\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以这部分很清楚。

\n\n

并根据 JDBC 规范

\n\n
The statement\xe2\x80\x99s batch is reset to empty once executeBatch returns\n
Run Code Online (Sandbox Code Playgroud)\n\n

无论executeBatch是否抛出异常/成功,它都会清除 Batch 。

\n\n

具体来说,MysqlPrepared Statement 在executeBatch()方法中清除finaly块中的批处理

\n\n
finally {\n        this.statementExecuting.set(false);\n        clearBatch();\n        }\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以你的逻辑将不起作用,因为你没有再次将语句添加到批处理中。

\n\n

因此,将语句添加回批处理并重新执行。您很有可能再次超时。所以首先要抽出时间。如果可能的话,在执行日志中写入一些有关原因/状态的信息。

\n