【问题标题】:How to config hibernate isolation level for postgres如何为 postgres 配置休眠隔离级别
【发布时间】:2019-12-13 17:19:13
【问题描述】:

我在 postgres 数据库中有一个表 ErrorCase。此表有一个字段case_id,数据类型为文本。其值由格式生成:yymmdd_xxxx。 yymmdd 是记录插入数据库的日期,xxxx 是该日期的记录数。

例如,2019/08/01 的第 3 个错误案例将具有 case_id = 190801_0003。 08/04,如果还有一个案例,它的case_id将是190804_0001,然后继续。

我已经在数据库中使用触发器为该字段生成值:

DECLARE
    total integer;
BEGIN
    SELECT (COUNT(*) + 1) INTO total  FROM public.ErrorCase WHERE create_at = current_date;
    IF (NEW.case_id is null) THEN 
        NEW.case_id = to_char(current_timestamp, 'YYMMDD_') || trim(to_char(total, '0000'));
    END IF;
    RETURN NEW;
END

在 Spring Project 中,我为 jpa/hibernates 配置应用程序属性:

datasource:
        type: com.zaxxer.hikari.HikariDataSource
        url: jdbc:postgresql://localhost:5432/table_name
        username: postgres
        password: postgres
        hikari:
            poolName: Hikari
            auto-commit: false
    jpa:
        database-platform: io.github.jhipster.domain.util.FixedPostgreSQL82Dialect
        database: POSTGRESQL
        show-sql: true
        properties:
            hibernate.id.new_generator_mappings: true
            hibernate.connection.provider_disables_autocommit: true
            hibernate.cache.use_second_level_cache: true
            hibernate.cache.use_query_cache: false
            hibernate.generate_statistics: true

目前,它正确生成了case_id。

但是,当几乎同时插入许多记录时,它会为两条记录生成相同的case_id。我想原因是因为隔离级别。当第一个事务尚未提交时,第二个事务执行 SELECT 查询以构建 case_id。因此,SELECT 查询的结果不包括第一次查询的记录(因为它还没有提交)。因此,第二个case_id 与第一个结果相同。

请建议我解决这个问题,哪种隔离级别适合这种情况???

【问题讨论】:

  • 无关,但是:你为什么要使用这种过时版本的 Hibernate 方言?它真的不支持当前的 Postgres 版本吗? Postgres 8.2 早已被人遗忘。

标签: postgresql hibernate jpa


【解决方案1】:

yymmdd 是记录插入数据库的日期,xxxx 是该日期的记录数” - 没有冒犯,但这是一个可怕的设计。

您应该有两个单独的列,一个date 列和一个integer 列。如果要在插入期间增加计数器,请将该日期列设置为主键并使用insert on conflict。您可以摆脱这种效率极低的触发器,更重要的是,即使已提交读取,并发修改也将是安全的。

类似:

create table error_case
(
  error_date date not null primary key, 
  counter integer not null default 1
);

然后使用以下插入行:

insert into error_case (error_date)
values (date '2019-08-01')
on conflict (error_date) do update 
   set counter = counter + 1;

并发插入不需要触发器并且安全。

如果您确实需要一个文本列作为“案例 ID”,请创建一个返回该格式的视图:

create view v_error_case
as
select concat(to_char(error_date, 'yymmdd'), '_', to_char(counter, '0000')) as case_id,
       ... other columns
from error_case;

【讨论】:

  • 让我试试这个方法。顺便说一句,我们的客户要求设计。
猜你喜欢
  • 2011-11-17
  • 2019-03-16
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
  • 1970-01-01
相关资源
最近更新 更多