我遇到了MySQL的SELECT .. FOR UPDATE问题,下面是我试图运行的查询:
SELECT * FROM tableName WHERE HostName='UnknownHost'
ORDER BY UpdateTimestamp asc limit 1 FOR UPDATE
之后,相关线程将执行UPDATE并更改HostName,然后它应该解锁该行。
我正在运行一个多线程的java应用程序,所以3个线程正在运行这个SQL语句,但是当线程1运行这个时,它不会锁定线程2和3的结果。因此线程2和3获得相同的结果,他们可以更新同一行。
另外每个线程都在它自己的mysql连接上。
我正在使用Innodb,事务隔离= READ-COMMITTED,并且在执行select for update之前Autocommit已关闭
更好的解决方案?
代码:
public BasicJDBCDemo()
{
Le_Thread newThread1=new Le_Thread();
Le_Thread newThread2=new Le_Thread();
newThread1.start();
newThread2.start();
}
主题:
class Le_Thread extends Thread
{
public void run()
{
tring name = Thread.currentThread().getName();
System.out.println( name+": Debut.");
long oid=Util.doSelectLockTest(name);
Util.doUpdateTest(oid,name);
}
}
选择 :
public static long doSelectLockTest(String threadName)
{
System.out.println("[OUTPUT FROM SELECT Lock ]...threadName="+threadName);
PreparedStatement pst = null;
ResultSet rs=null;
Connection conn=null;
long oid=0;
try
{
String query = "SELECT * FROM table WHERE Host=?
ORDER BY Timestamp asc limit 1 FOR UPDATE";
conn=getNewConnection();
pst = conn.prepareStatement(query);
pst.setString(1, DbProperties.UnknownHost);
System.out.println("pst="+threadName+"__"+pst);
rs = pst.executeQuery();
if (rs.first())
{
String s = rs.getString("HostName");
oid = rs.getLong("OID");
System.out.println("oid_oldest/host/threadName=="+oid+"/"+s+"/"+threadName);
}
}
catch (SQLException ex)
{
ex.printStackTrace();
}
finally
{
DBUtil.close(pst);
DBUtil.close(rs);
DBUtil.close(conn);
}
return oid;
}
发布于 2018-06-25 17:15:23
首先,你需要SELECT ... FOR UPDATE
用ResultSet.CONCUR_UPDATABLE
参数来准备你的陈述,如下所示:
ps = conn.prepareStatement(query,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
然后,你必须使用ResultSet实际更新表:
if(rs.next())
{
rs.updateString(columnIndex, "new_hostname");
rs.updateRow();
}
第三,你可能需要使用一个事务,我可以在你的更新中看到。希望你的DbUtil.close
方法不会抛出任何异常,检查null等。另外,如果你的方法变得更复杂,那么你也应该有回滚逻辑。
你不应该my.ini
因为任何原因而修改。
发布于 2018-06-25 17:53:20
代码:
public static long doSelectLockTest(String threadName) {
System.out.println("[OUTPUT FROM SELECT Lock ]...threadName=" + threadName);
PreparedStatement pst = null;
ResultSet rs = null;
Connection conn = null;
long oid = 0;
try {
String query = "SELECT * FROM table WHERE Host=? ORDER BY UpdateTime asc limit 1 FOR UPDATE";
conn = getNewConnection();
conn.setAutoCommit(false);
pst = conn.prepareStatement(query);
pst.setString(1, DbProperties.UnknownHost);
rs = pst.executeQuery();
if (rs.first()) {
String s = rs.getString("HostName");
oid = rs.getLong("OID");
//Start update then commit
if (oid != 0) {
query = "UPDATE b2bicheckpoint SET HostName=?,UpdateTimestamp=? where OID = ?";
pst = conn.prepareStatement(query);
pst.setString(1, oid + "_host_" + threadName);
pst.setLong(2, getCurrentLongTime());
pst.setLong(3, oid);
System.out.println("Select_Prestatement=" + threadName + "__" + pst);
int result = pst.executeUpdate();
conn.commit();
conn.setAutoCommit(true);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
DBUtil.close(pst);
DBUtil.close(rs);
DBUtil.close(conn);
}
return oid;
}
结果:
[OUTPUT FROM SELECT Lock ]...threadName=Thread-1
[OUTPUT FROM SELECT Lock ]...threadName=Thread-2
Select_Prestatement=Thread-1_ : SELECT * FROM ..... FOR UPDATE
Select_Prestatement=Thread-2_: SELECT * FROM ...... FOR UPDATE
Select_Prestatement=Thread-1_: UPDATE table SET HostName='host_Thread-1' where OID = 1
https://stackoverflow.com/questions/-100005511
复制相似问题