我在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
具有与第一个相同的结果。
请给我建议解决此问题的任何方法,哪种隔离级别适合这种情况??
答案 0 :(得分:0)
“ yymmdd是记录插入DB的日期,xxxx是该日期的记录数”-没有冒犯,但这是一个可怕的设计。
您应该有两个单独的列,一个public function __construct(AWSTranslationService $awsTranslator)
{
$this->awsTranslator = $awsTranslator;
}
列和一个date
列。如果要在插入过程中增加计数器,请将该日期列作为主键并使用integer
。您可以摆脱那些效率低下的触发器,更重要的是,即使提交了读操作,对于并行修改也是安全的。
类似的东西:
insert on conflict
然后使用以下内容插入行:
create table error_case
(
error_date date not null primary key,
counter integer not null default 1
);
不需要触发器,并且对于并发插入是安全的。
如果您确实需要文本列作为“案例ID”,请创建一个返回该格式的视图:
insert into error_case (error_date)
values (date '2019-08-01')
on conflict (error_date) do update
set counter = counter + 1;