java.sql.Connection 隔离级别

标签 java sql isolation-level

我正在编写一些尖峰代码,但没有给我预期的结果。

我有一个基本上由几行计数器组成的表格。其他表使用这些行来生成应该是唯一 ID 的内容。 当我运行下面的代码时,我异常(exception)的是第一个到达 select 语句的线程将获取对该行或表的锁定,从而停止对唯一 id 值的所有读取或写入。然而,第二个线程总是在第一个线程之前完成,因为它被 hibernate 了 1 秒,因此它们都读取相同的值并写入相同的值,所以它只递增一次而不是我异常(exception)的两次。

是我的代码有什么问题,还是我对隔离级别的理解不正确?

我已经删除了样板代码。使用 MySQL 数据库的标准 sql.Connection。

private void incrementValue() {

        connection
                .setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

        statement = connection.createStatement();

        System.out.println(Thread.currentThread().getName()
                + " doing select");
        resultSet = statement.executeQuery("select * from counter");
        System.out.println(Thread.currentThread().getName()
                + "after select");
        if (counter++ == 0) {
            Thread.sleep(1000);
        }
        String incrementedValue = getIncrementedValue(resultSet);

        statement.executeUpdate("update counter set counter='"
                + incrementedValue + "'");


}

private String getIncrementedValue(ResultSet resultSet) throws SQLException {
    String value = "";
    if (resultSet.next()) {
        System.out.println(Thread.currentThread().getName() + "Value was "
                + resultSet.getString(1));

        value = (new Integer(resultSet.getString(1)) + 1) + "";

    }

    return value;

}

这是从 main 调用的

public static void main(String[] args) {
    DatabaseExample databaseExample = new DatabaseExample();

    Runnable runnable = new Runnable() {

        @Override
        public void run() {
            DatabaseExample databaseExample = new DatabaseExample();
            databaseExample.incrementValue();
        }
    };
    new Thread(runnable).start();

    databaseExample.incrementValue();
}

最佳答案

即使在 SERIALIZABLE 隔离级别中,也可以并行进行多个选择。如果要锁定 select 子句上的行,请使用 select ... for update

引用资料:

http://dev.mysql.com/doc/refman/5.1/en/select.html :

If you use FOR UPDATE with a storage engine that uses page or row locks, rows examined by the query are write-locked until the end of the current transaction. Using LOCK IN SHARE MODE sets a shared lock that permits other transactions to read the examined rows but not to update or delete them.

http://dev.mysql.com/doc/refman/5.1/en/set-transaction.html#isolevel_serializable :

SERIALIZABLE

This level is like REPEATABLE READ, but InnoDB implicitly converts all plain SELECT statements to SELECT ... LOCK IN SHARE MODE if autocommit is disabled.

关于java.sql.Connection 隔离级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14789321/

相关文章:

Java 8 List to EnumMap with sums

mysql - 不同列号的两个 SELECT 的 SQL-UNION 产生空值

mysql - 从我的查询中过滤掉特定的电子邮件域

postgresql - PostgreSQL 隔离级别的行为

java - 捕获身份验证异常

java - 安卓查看错误

php - 如何为此表单编写搜索查询

java - Spring事务并插入数据库

sql-server - 管理 SQL Server 中的并发

c# - 内部IP地址和外部IP地址的区别