首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >JDBC使用SELECT FOR UPDATE锁定一行,不起作用?

JDBC使用SELECT FOR UPDATE锁定一行,不起作用?
EN

Stack Overflow用户
提问于 2018-06-25 08:17:00
回答 2查看 0关注 0票数 0

我遇到了MySQL的SELECT .. FOR UPDATE问题,下面是我试图运行的查询:

代码语言:javascript
运行
复制
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已关闭

更好的解决方案?

代码:

代码语言:javascript
运行
复制
public BasicJDBCDemo()
{
    Le_Thread newThread1=new Le_Thread();
    Le_Thread newThread2=new Le_Thread();
    newThread1.start();
    newThread2.start();         
}

主题:

代码语言:javascript
运行
复制
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);        
    }

}

选择 :

代码语言:javascript
运行
复制
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;
  }
EN

回答 2

Stack Overflow用户

发布于 2018-06-25 17:15:23

首先,你需要SELECT ... FOR UPDATEResultSet.CONCUR_UPDATABLE参数来准备你的陈述,如下所示:

代码语言:javascript
运行
复制
ps = conn.prepareStatement(query,
                           ResultSet.TYPE_FORWARD_ONLY,
                           ResultSet.CONCUR_UPDATABLE);

然后,你必须使用ResultSet实际更新表:

代码语言:javascript
运行
复制
if(rs.next())
{
    rs.updateString(columnIndex, "new_hostname");
    rs.updateRow();
}

第三,你可能需要使用一个事务,我可以在你的更新中看到。希望你的DbUtil.close方法不会抛出任何异常,检查null等。另外,如果你的方法变得更复杂,那么你也应该有回滚逻辑。

你不应该my.ini因为任何原因而修改。

票数 0
EN

Stack Overflow用户

发布于 2018-06-25 17:53:20

代码:

代码语言:txt
复制
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;
}

结果:

代码语言:txt
复制
[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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100005511

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档