You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

H2数据库事务隔离级别设置与查询:是否存在显示异常问题?

在H2 2.2.220版本中

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

根据H2教程,存在H2控制台专用语法用于设置或查询事务隔离级别:

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

此处文档需更新,因为未列出级别6(snapshot),实际支持的级别如下:

  • 1: read_uncommitted
  • 2: read_committed
  • 4: repeatable_read
  • 6: snapshot
  • 8: serializable(可能仅部分支持,暂不确定)

但此处的「事务隔离级别」指代不明:是当前会话级别?全局级别?还是默认级别?继续测试:

查询事务隔离级别:

@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;

查询隔离级别结果#1

执行@命令后,所有会话的隔离级别均被修改(注:仅控制台一个会话处于活跃状态):

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

查询隔离级别结果#2

这似乎合理。

但程序也可通过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;

预期仅当前会话受影响,但实际观察到所有会话均被修改:
查询隔离级别结果#3

该如何解释此现象?

更令人困惑的是:
通过Spring JDBC应用直接查询和设置事务隔离级别(以下为测试代码,正确方式是使用@Transactional注解并设置其isolation属性),数据库显示会话的事务隔离级别已调整,例如INFORMATION_SCHEMA.SESSIONS显示为REPEATABLE_READ。但此时控制台仍显示所有现有会话的隔离级别为通过@命令设置的统一值,且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));
}

不依赖H2代码的IsolationLevel枚举:

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";
        };
    }
}

内容的提问来源于stack exchange,提问作者David Tonhofer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 14:16:28