使用JDBC和Oracle时,SELECT FOR UPDATE不起作用

4
我已经写了一个简单的Java程序,它打开一个事务,选择一些记录,执行一些逻辑然后更新它们。我希望这些记录被锁定,因此使用了SELECT...FOR UPDATE。
这个程序在MS SQL Server 2005上运行得非常好,但是在Oracle 10g中,记录没有被锁定!
有任何想法为什么会这样吗?
我按照以下方式创建连接:
Connection connection = DriverManager.getConnection(URL, User, Password);
connection.setAutoCommit(false);

如果我从Oracle SQL Developer客户端执行SELECT..FOR UPDATE,我可以看到记录被锁定,因此我认为这可能是JDBC驱动程序的问题,而不是数据库问题,但我在网上找不到任何有用的信息。
这是我使用的JDBC驱动程序的详细信息:
Manifest-Version: 1.0
Implementation-Vendor:  Oracle Corporation
Implementation-Title:   ojdbc14.jar
Implementation-Version: Oracle JDBC Driver version - "10.2.0.2.0"
Implementation-Time:    Tue Jan 24 08:55:21 2006
Specification-Vendor:   Oracle Corporation
Sealed: true
Created-By: 1.4.2_08 (Sun Microsystems Inc.)
Specification-Title:    Oracle JDBC driver classes for use with JDK14
Specification-Version:  Oracle JDBC Driver version - "10.2.0.2.0"

2
请更具体地描述您遇到的问题:哪些方面出现了问题? - Mark Rotteveel
SELECT...FOR UPDATE不会锁定记录。如果我尝试从另一个程序同时更新相同的记录,则更新将成功,而我的理解是这些记录应该在我提交或回滚事务之前被锁定(这实际上是SQL Server的情况)。 - Gep
1个回答

4

抱歉,我无法重现这个行为。你在JDBC中如何运行SELECT ... FOR UPDATE查询?

我有一张名为locktest的表,其中包含以下数据:

SQL> select * from locktest;
A B ---------- ---------- 1 0 2 0 3 0 4 0 5 0

我还有这个Java类:

import oracle.jdbc.OracleDriver;
import java.sql.*;

public class LockTest {

    public static void main(String[] args) throws Exception {
        DriverManager.registerDriver(new OracleDriver());
        Connection c  = DriverManager.getConnection(
            "jdbc:oracle:thin:@localhost:1521:XE", "user", "password");

        c.setAutoCommit(false);
        Statement stmt = c.createStatement(
            ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

        ResultSet rSet = stmt.executeQuery(
            "SELECT a, b FROM locktest FOR UPDATE");

        while (rSet.next()) {
            if (rSet.getInt(1) <= 3) {
                rSet.updateInt(2, 1);
            }
        }

        System.out.println("Sleeping...");
        Thread.sleep(Long.MAX_VALUE);
    }
}

当我运行这个Java类时,它会对表进行一些更新,然后开始睡眠。它睡眠是为了保持事务的开放状态,从而保留锁定状态。
 
C:\Users\Luke\stuff>java LockTest
Sleeping...
当程序在睡眠时,我尝试在SQL*Plus中并发更新表:
SQL> update locktest set b = 1 where a <= 3;
此时,SQL*Plus会挂起直到我杀死Java程序。

1
我还需要在updateInt之后加上rSet.updateRow()才能使更新生效。 - Codemwnci
我修改了上面的代码,选择了一个TYPE_FORWARD_ONLY、CONCUR_READ_ONLY结果集,但是查询仍然锁定了其他客户端在同一行上执行SELECT ... FOR UPDATE的操作。 - Andrew Swan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接