java.sql.Connection隔离级别

时间:2013-02-09 14:54:39

标签: java sql isolation-level

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

我有一个基本上是计数器行的表。其他表使用这些行来生成应该是唯一ID的。 当我运行下面的代码时,我除外的是第一个到达select语句的线程将获取该行或表的锁定,停止对唯一id值的所有读取或写入。然而,第二个线程总是在第一个线程之前完成,因为它已经被置于休眠1秒,因此它们都读取相同的值并写入相同的值,因此它只增加一次,而不是我除外的两倍。

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

我删除了锅炉板代码。使用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;

}

这是从主

调用的
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();
}

1 个答案:

答案 0 :(得分:3)

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

参考文献:

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

  

如果对使用页锁或行锁的存储引擎使用FOR UPDATE,则查询检查的行将被写入锁定,直到当前事务结束。使用LOCK IN SHARE MODE设置一个共享锁,允许其他事务读取已检查的行,但不允许更新或删除它们。

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

  

SERIALIZABLE

     

此级别与REPEATABLE READ类似,但InnoDB隐式将所有普通SELECT语句转换为SELECT ...如果禁用自动提交,则锁定共享模式。