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