Java 如何让正在读取的行等待使用JDBC和MySQL释放锁?

Java 如何让正在读取的行等待使用JDBC和MySQL释放锁?,java,mysql,jdbc,transactions,Java,Mysql,Jdbc,Transactions,我举了一个小例子 import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import static java.sql.DriverManager.getConnection; public class Bar { public static void main(String[] args) throws SQLException, InterruptedExceptio

我举了一个小例子

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import static java.sql.DriverManager.getConnection;

public class Bar {
    public static void main(String[] args) throws SQLException, InterruptedException {
        final long start = System.currentTimeMillis();
        final Connection connection = getConnection("jdbc:mysql://localhost:3306/sakila", "root", "root");
        final Statement statement = connection.createStatement();
        statement.executeUpdate("UPDATE actor SET first_name = 'bar' WHERE last_name = 'tugay'");
        statement.close();
        connection.close();
        final long end = System.currentTimeMillis();
        System.out.println("Took: " + (end - start)); // Will print around 350ms
    }
}
当我执行这段小代码时,它会打印出大约350~400毫秒的值,这很好

现在,当我第一次启动以下代码时

import java.sql.*;

import static java.sql.DriverManager.*;

public class Foo {

    public static void main(String[] args) {
        final Connection connection;
        try {
            connection = getConnection("jdbc:mysql://localhost:3306/sakila", "root", "root");
            connection.setAutoCommit(false);

            final Statement statement = connection.createStatement();
            statement.executeUpdate("UPDATE actor SET first_name = 'foo' WHERE last_name = 'tugay'");

            System.out.println("Sleeping!");
            Thread.sleep(15000); // Sleep for 15 seconds..

            connection.commit();
            connection.close();
        } catch (SQLException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
然后运行Bar.java,我将得到大约12-13秒的值,这意味着当Foo.java“锁定”lastname='tugay'的行时,Bar.java只是等待,然后将第一个_名称设置为'Bar'

如果Bar.java试图读取last_name='tugay'的行,我希望得到相同的行为。这就是我的代码:

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import static java.sql.DriverManager.getConnection;

public class Bar {
    public static void main(String[] args) throws SQLException, InterruptedException {
        final long start = System.currentTimeMillis();
        final Connection connection = getConnection("jdbc:mysql://localhost:3306/sakila", "root", "root");
        final Statement statement = connection.createStatement();
        final ResultSet resultSet = statement.executeQuery("SELECT first_name FROM actor WHERE last_name = 'tugay'");
        resultSet.next();
        System.out.println(resultSet.getString("first_name"));
        statement.close();
        connection.close();
        final long end = System.currentTimeMillis();
        System.out.println("Took: " + (end - start));
    }
}
给定,当我启动Foo.java并在它“休眠”时,当我运行Bar.java时,数据库中的first_name最初的值是“koray”:

koray
Took: 390
有没有一种方法可以让Bar.java在读取时也像在更新时一样等待?

更新: 您可以使用显式启用锁定读或写的方法 您可以使用事务隔离级别-transaction_SERIALIZABLE并禁用自动提交,这将启用隐式锁定读取

使用
Connection.setTransactionIsolation(Connection.TRANSACTION\u SERIALIZABLE)

请参见,您需要一个

如果您不想更新该行,但只想确保该行上没有其他事务,请获取意向共享(
is
)锁:

如果要在结果返回后更新行,请获取意向独占(
IX
)锁:

这两个查询都将被阻止,直到请求的锁可用为止。由于
IS
IX
锁与正在或已在行上执行更新(且尚未提交或回滚)的事务持有的独占
X
锁不兼容,上述任一查询都将被阻塞,直到另一个事务通过提交或回滚释放其
X

只有这样,该事务才能获得锁并接收其结果

最后,该事务通过提交或回滚最终释放它获得的锁


另请参见

MySQL已默认为事务可重复读取。请参阅:@KorayTugay for
derby
TRANSACTION\u READ\u COMMITTED
是事务的默认隔离级别。@Vishrant OK。。与这个答案有什么关系?或者这个问题?哦,我没有看到这个问题是用MySQL标记的,你是对的,默认情况下MySQL使用
TRANSACTION\u REPEATABLE\u READ
SELECT first_name FROM actor WHERE last_name = 'tugay' LOCK IN SHARE MODE
SELECT first_name FROM actor WHERE last_name = 'tugay' FOR UPDATE