H2:设置和查询隔离级别 - H2 报告它们的方式是否存在问题?

问题描述 投票:0回答:1

H2 2.2.220

假设我从H2控制台设置事务隔离级别:

根据H2教程,有一个特殊的H2控制台语法来设置或查询事务隔离级别:

  • @transaction_isolation;
    :显示(不带参数)事务隔离级别。
  • @transaction_isolation <levelAsInt>;
    更改事务隔离级别。

此处的文档需要进行一些更新,因为它没有列出级别 6“快照”,但级别如下:

  • 1:读未提交
  • 2:已提交读
  • 4:可重复读取
  • 6:快照
  • 8:可序列化(可能仅部分支持,不确定)

然而,尚不清楚“事务隔离级别”在这里指的是什么。是当前会话中的一个吗?单一的全球性的吗?默认的?但我们继续吧...

查询“事务隔离级别”则:

@transaction_isolation;

Transaction Isolation: 2
1: read_uncommitted
2: read_committed
4: repeatable_read
6: snapshot
8: serializable?: @transaction_isolation 

所以看起来“我们处于水平

read_committed
”...

“隔离级别”实际上是“会话”的一个属性,它应该是这样。

H2的信息模式允许我们查询当前所有会话的级别:

SELECT SESSION_ID, ISOLATION_LEVEL, 
       SESSION_ID = SESSION_ID() AS "IS_MY_SESSION" 
FROM INFORMATION_SCHEMA.SESSIONS;

应用

@
命令显然会更改所有会话的隔离级别(请注意,只有一个控制台会话处于活动状态):

@transaction_isolation 8;
SELECT SESSION_ID, ISOLATION_LEVEL, 
       SESSION_ID = SESSION_ID() AS "IS_MY_SESSION" 
FROM INFORMATION_SCHEMA.SESSIONS;

有人可能会说,这是有道理的。

但是,程序也可以通过 SQL 命令设置事务隔离级别

SET SESSION CHARACTERISTICS

更改当前会话的事务隔离级别。隔离级别的实际支持取决于数据库引擎。

具有可接受的值(如H2 javadoc中所定义):

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE
  • SNAPSHOT
    (也可以,但手册中没有)

如果现在运行

SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL
    READ COMMITTED;
SELECT SESSION_ID, ISOLATION_LEVEL, 
       SESSION_ID = SESSION_ID() AS "IS_MY_SESSION" 
FROM INFORMATION_SCHEMA.SESSIONS;

人们期望当前会话受到影响,但这不是观察到的情况,所有会话似乎都受到影响:

这是怎么回事?

更麻烦的是:

如果我使用简单的代码直接从 Spring JDBC 应用程序查询和设置事务隔离级别(如下添加,这只是为了测试,正确的方法是使用

@Transactional
注解并设置其
isolation
属性) ),那么数据库报告确实该会话的事务隔离级别已经调整,即根据
INFORMATION_SCHEMA.SESSIONS
,事务隔离级别例如为
REPEATABLE_READ
。但在此过程中,控制台still报告事务隔离级别统一为所有现有会话上使用
@
命令设置的任何级别,一旦Java程序运行,数量就会更多。

是显示问题吗?或者会话是否立即返回到

@
命令设置的默认值?

我还没有尝试查看隔离级别是否真正应用。很快!

用于设置和查询隔离级别的Java代码

一条记录:

public record AboutSession(int sessionId, IsolationLevel isolationLevel) {}

查询事务隔离级别(

IsolationLevel
枚举的代码已省略):

public static AboutSession getAboutSession (@NotNull JdbcTemplate jdbcTemplate) {
   return (jdbcTemplate.query("SELECT SESSION_ID, ISOLATION_LEVEL FROM "
              + " INFORMATION_SCHEMA.SESSIONS WHERE SESSION_ID = SESSION_ID()",
              (ResultSet row, int rowNum) ->
                  new AboutSession(
                     row.getInt(1),
                     IsolationLevel.fromString(row.getString(2))))
          ).get(0);
}

设置事务隔离级别

public static void setSessionIsolationLevel(
   @NotNull JdbcTemplate jdbcTemplate, 
   @NotNull IsolationLevel level) {
      jdbcTemplate.execute("SET SESSION CHARACTERISTICS AS "
         + " TRANSACTION ISOLATION LEVEL " + level.toSql(level));
}

IsolationLevel
枚举,不依赖于H2代码:

public enum IsolationLevel {

    READ_UNCOMMITTED,
    READ_COMMITTED,
    REPEATABLE_READ,
    SERIALIZABLE,
    SNAPSHOT;

    public static IsolationLevel fromString(@NotNull String x) {
        String xx = x.toUpperCase();
        switch (xx) {
            case "READ UNCOMMITTED" -> {
                return READ_UNCOMMITTED;
            }
            case "READ COMMITTED" -> {
                return READ_COMMITTED;
            }
            case "REPEATABLE READ" -> {
                return REPEATABLE_READ;
            }
            case "SERIALIZABLE" -> {
                return SERIALIZABLE;
            }
            case "SNAPSHOT" -> {
                return SNAPSHOT;
            }
            default -> throw new IllegalArgumentException("Cannot map string " + x + " to a valid " + IsolationLevel.class.getName());
        }
    }

    public static String toSql (@NotNull IsolationLevel isolationLevel) {
        return switch (isolationLevel) {
            case READ_UNCOMMITTED -> "READ UNCOMMITTED";
            case READ_COMMITTED -> "READ COMMITTED";
            case REPEATABLE_READ -> "REPEATABLE READ";
            case SERIALIZABLE -> "SERIALIZABLE";
            case SNAPSHOT -> "SNAPSHOT";
        };
    }
}
transactions h2
1个回答
0
投票

是的,

INFORMATION_SCHEMA
有一个错误。

所有行中返回当前会话的隔离级别,而不是这些行中描述的会话的实际隔离级别。

我针对这个bug补了一个新问题: https://github.com/h2database/h2database/issues/3868

© www.soinside.com 2019 - 2024. All rights reserved.