所以我有这个小例子..
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等待的行,然后将first_name设置为' 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));
}
}
鉴于,初始值first_name是" koray"在数据库中,当我启动Foo.java并且它正在睡觉时#34;当我运行Bar.java时,我会得到:
koray
Took: 390
有没有办法让Bar.java在阅读时等待,就像它在更新时等待一样?
答案 0 :(得分:1)
您需要locking read。
如果您不打算更新该行但只想确保该行上没有其他事务处理,请获取Intention Shared(IS
)锁:
SELECT first_name FROM actor WHERE last_name = 'tugay' LOCK IN SHARE MODE
如果您打算在结果返回后更新该行,请获取Intention eXclusive(IX
)锁:
SELECT first_name FROM actor WHERE last_name = 'tugay' FOR UPDATE
这两个查询都会阻塞,直到请求的锁定可用。由于IS
和IX
锁与正在执行或已对行执行更新(并且尚未提交或回滚)的事务所持有的独占X
锁不兼容,上述任何一个查询都会阻塞,直到其他事务通过提交或回滚来释放其X
锁。
此事务才会获得锁并接收其结果。
最后,此事务最终通过提交或回滚来释放它获得的锁。
另见https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-shared-exclusive-locks
答案 1 :(得分:0)
您应该使用事务隔离级别 - TRANSACTION_REPEATABLE_READ。
使用Connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ)
请参阅here