你的代码基本上是正确的。发生死锁时引发的异常是SQLException
。例外的getSQLState()
方法提供返回一个错误代码,该代码提供附加信息 http://dev.mysql.com/doc/connector-j/en/connector-j-reference-error-sqlstates.html关于实际的错误。
您还应该在两次尝试之间等待较短的时间,以免服务器负载过多。
正如您巧妙地猜测的那样,设置最大尝试次数,否则您可能会陷入无限循环。
最终代码可能如下所示:
boolean oops;
int retries = 5;
Connection c = null;
Statement s = null;
ResultSet rs = null;
do
{
oops = false;
c = null;
s = null;
rs = null;
try
{
c = openConnection();
s = c.createStatement();
rs = s.executeQuery("SELECT stuff FROM mytable");
fiddleWith(rs);
}
catch (SQLException sqlex)
{
oops = true;
switch(sqlex.getErrorCode()())
{
case MysqlErrorNumbers.ER_LOCK_DEADLOCK:
// deadlock or lock-wait time-out occured
break;
...
}
Thread.sleep(1000); // short delay before retry
}
finally
{
if (rs != null) try {
rs.close();
} catch (SQLException e) {
// some error handler here
}
if (s != null) try {
s.close();
} catch (SQLException e) {
// some error handler here
}
if (c != null) try {
c.close();
} catch (SQLException e) {
// some error handler here
}
}
}
while (oops == true && retries-- > 0);
显然上面的代码不是最优的。您可能希望区分连接时发生的错误和执行时发生的错误。您还可以检测到,在出现一些错误之后,再次尝试成功的希望渺茫(例如,错误的凭据或 SQL 语法错误)。
您问了很多问题,但我会尽力回答所有问题:
是否有需要注意的特定例外情况?
是的,参见上文:SQLException
是那些,更多信息由getErrorCode()
or getSQLState()
.
异常是在我调用connection.commit()之后才抛出的吗?
A SQLException
几乎所有类的所有方法都可以抛出java.sql
包裹。
是否应该在循环中运行并限制循环运行的次数?
是的,见上文。
Do I [需要]重新实例化PreparedStatement
物体?
显然你不能重新创建一个PreparedStatement
两个查询之间。您只需在调用之前为参数设置新值executeQuery()
再次。当然如果你需要执行另一个查询,那么一个新的PreparedStatement
是必须的。
同样适用于ResultSet
物体也是
A (new) ResultSet
对象由返回Statement.executeQuery()
,代表查询的结果。你永远不会自己创建这样的对象。理想情况下你会打电话ResultSet.close()
尽快释放内存。
我强烈建议你阅读第二章本教程 http://docs.oracle.com/javase/tutorial/jdbc/basics/(“处理 SQL 语句”)。