问题摘要:
我有一个 case class Test04(...)
将来自移动客户端的值更新到数据库中。表格用途 tSt
类型字段 timestamptz
对于乐观锁定和 tSt
值是db中的当前值。所以我有唯一的身份证和最新信息 tSt
. 所以应该可以更新数据库中的值。
case类被转换为 RecordTest04
要缩短数据库操作,请执行以下操作: record.update()
而不是dsl语句,每次在表中添加/删除新字段时,我都必须手动修改该语句。
由于某种原因 record.update()
投掷 org.jooq.exception.DataChangedException: Database record has been changed
细节:
我有以下sql:
-- for table04
create or replace function createUuid() returns uuid
as 'SELECT md5(random()::text || clock_timestamp()::text)::uuid;'
language sql
stable;
create or replace function insertUuidT()
returns trigger as
$BODY$
begin
if new.id is null then
new.id = createUuid();
end if;
new.tSt = now();
return new;
end
$BODY$
language 'plpgsql';
create or replace function updatePreventT()
returns trigger as
$BODY$
begin
if new.id <> old.id then
raise exception 'You cannot modify id. Current id: % Proposed id: %', OLD.id, NEW.id; -- USING ERRCODE='123';
end if;
new.tSt = now();
return new;
end
$BODY$
language 'plpgsql';
drop table if exists test04 cascade;
create table test04 (
id uuid not null, -- Unique, link to other tables
intNotNull int not null,
dateNotNull date not null,
dateNull date,
timestamptzNotNull timestamptz not null,
timestamptzNull timestamptz,
tSt timestamptz not null, -- timestamp for optimistic locking support
primary key ( id )
);
create unique index test04_id on test04( id );
drop trigger if exists test04_insert ON test04;
create trigger test04_insert before insert on test04 for each row execute procedure insertUuidT(); --setUuid();
drop trigger if exists test04_update ON test04;
create trigger test04_update before update on test04 for each row execute procedure updatePreventT(); --preventIdChange();
db设置为:
val settings = new Settings()
.withExecuteWithOptimisticLocking(true) // Defaults to false
.withUpdatablePrimaryKeys(true) // Defaults to false, primary keys are not always internal
.withReturnAllOnUpdatableRecord(true) // Defaults to false, return all db/JOOQ generated values.
.withMapJPAAnnotations(false) // Defaults to true, annotations are not used
//.withExecuteWithOptimisticLockingExcludeUnversioned(true) // Defaults to false
val sqlDialect = SQLDialect.POSTGRES
val jdbcDriverClass = Class.forName("org.postgresql.Driver")
代码是:
val connection = JooqTestConnectionPool.dataSource.getConnection
val db = DBSettings.getDSLContext(connection) // Using Conf to create DSL.
val uuid1 = UUID.fromString("0c6e629b-aa0c-43eb-82fd-645c565a689a")
val t04_1 = Test04(uuid1, 1230, LocalDate.now(), Some(LocalDate.now().minusDays(100)), OffsetDateTime.now(), Some(OffsetDateTime.now().minusMinutes(10)),OffsetDateTime.now())
db.deleteFrom(TEST04).where(TEST04.ID.eq(uuid1)).execute()
val t04_1RecA = db.newRecord(TEST04, t04_1)
val t04_1RecB = db.newRecord(TEST04, t04_1)
println(s"t04_1RecA before insert\n${t04_1RecA}")
val iResA = t04_1RecA.insert()
println(s"t04_1RecA after insert\n${t04_1RecA}")
if (iResA != 1) throw new RuntimeException(s"Invalid insert res A: ${iResA}")
t04_1RecB.changed("id",false)
t04_1RecB.setIntnotnull(800)
t04_1RecB.setTst(t04_1RecA.getTst)
println(s"t04_1RecB before update\n${t04_1RecB}")
t04_1RecB.update() // -> This will cause org.jooq.exception.DataChangedException: Database record has been changed
println(s"t04_1RecB after update\n${t04_1RecB}")
connection.close()
运行时输出为:
Thank you for using jOOQ 3.12.4
Executing query : delete from "public"."test04" where "public"."test04"."id" = cast(? as uuid)
-> with bind values : delete from "public"."test04" where "public"."test04"."id" = '0c6e629b-aa0c-43eb-82fd-645c565a689a'
Affected row(s) : 1
t04_1RecA before insert
+-------------------------------------+----------+-----------+-----------------+---------------------------------+---------------------------------------+---------------------------------+
|id |intnotnull|datenotnull|datenull |timestamptznotnull |timestamptznull |tst |
+-------------------------------------+----------+-----------+-----------------+---------------------------------+---------------------------------------+---------------------------------+
|*0c6e629b-aa0c-43eb-82fd-645c565a689a| *1230|*2020-06-12|*Some(2020-03-04)|*2020-06-12T15:59:39.655505+03:00|*Some(2020-06-12T15:49:39.655508+03:00)|*2020-06-12T15:59:39.655514+03:00|
+-------------------------------------+----------+-----------+-----------------+---------------------------------+---------------------------------------+---------------------------------+
Executing query : insert into "public"."test04" ("id", "intnotnull", "datenotnull", "datenull", "timestamptznotnull", "timestamptznull", "tst") values (cast(? as uuid), ?, cast(? as date), cast(? as date), cast(? as timestamp with time zone), cast(? as timestamp with time zone), cast(? as timestamp with time zone)) returning "public"."test04"."id", "public"."test04"."intnotnull", "public"."test04"."datenotnull", "public"."test04"."datenull", "public"."test04"."timestamptznotnull", "public"."test04"."timestamptznull", "public"."test04"."tst"
-> with bind values : insert into "public"."test04" ("id", "intnotnull", "datenotnull", "datenull", "timestamptznotnull", "timestamptznull", "tst") values ('0c6e629b-aa0c-43eb-82fd-645c565a689a', 1230, date '2020-06-12', date '2020-03-04', timestamp with time zone '2020-06-12 15:59:39.655505+03:00', timestamp with time zone '2020-06-12 15:49:39.655508+03:00', timestamp with time zone '2020-06-12 15:59:39.655514+03:00') returning "public"."test04"."id", "public"."test04"."intnotnull", "public"."test04"."datenotnull", "public"."test04"."datenull", "public"."test04"."timestamptznotnull", "public"."test04"."timestamptznull", "public"."test04"."tst"
Fetched result : +------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
: |id |intnotnull|datenotnull|datenull |timestamptznotnull |timestamptznull |tst |
: +------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
: |0c6e629b-aa0c-43eb-82fd-645c565a689a| 1230|2020-06-12 |Some(2020-03-04)|2020-06-12T15:59:39.655505+03:00|Some(2020-06-12T15:49:39.655508+03:00)|2020-06-12T15:59:40.181434+03:00|
: +------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
Fetched row(s) : 1
t04_1RecA after insert
+------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
|id |intnotnull|datenotnull|datenull |timestamptznotnull |timestamptznull |tst |
+------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
|0c6e629b-aa0c-43eb-82fd-645c565a689a| 1230|2020-06-12 |Some(2020-03-04)|2020-06-12T15:59:39.655505+03:00|Some(2020-06-12T15:49:39.655508+03:00)|2020-06-12T15:59:40.181434+03:00|
+------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
t04_1RecB before update
+------------------------------------+----------+-----------+-----------------+---------------------------------+---------------------------------------+---------------------------------+
|id |intnotnull|datenotnull|datenull |timestamptznotnull |timestamptznull |tst |
+------------------------------------+----------+-----------+-----------------+---------------------------------+---------------------------------------+---------------------------------+
|0c6e629b-aa0c-43eb-82fd-645c565a689a| *800|*2020-06-12|*Some(2020-03-04)|*2020-06-12T15:59:39.655505+03:00|*Some(2020-06-12T15:49:39.655508+03:00)|*2020-06-12T15:59:40.181434+03:00|
+------------------------------------+----------+-----------+-----------------+---------------------------------+---------------------------------------+---------------------------------+
Executing query : select "public"."test04"."id", "public"."test04"."intnotnull", "public"."test04"."datenotnull", "public"."test04"."datenull", "public"."test04"."timestamptznotnull", "public"."test04"."timestamptznull", "public"."test04"."tst" from "public"."test04" where "public"."test04"."id" = cast(? as uuid) for update
-> with bind values : select "public"."test04"."id", "public"."test04"."intnotnull", "public"."test04"."datenotnull", "public"."test04"."datenull", "public"."test04"."timestamptznotnull", "public"."test04"."timestamptznull", "public"."test04"."tst" from "public"."test04" where "public"."test04"."id" = '0c6e629b-aa0c-43eb-82fd-645c565a689a' for update
Fetched result : +------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
: |id |intnotnull|datenotnull|datenull |timestamptznotnull |timestamptznull |tst |
: +------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
: |0c6e629b-aa0c-43eb-82fd-645c565a689a| 1230|2020-06-12 |Some(2020-03-04)|2020-06-12T15:59:39.655505+03:00|Some(2020-06-12T15:49:39.655508+03:00)|2020-06-12T15:59:40.181434+03:00|
: +------------------------------------+----------+-----------+----------------+--------------------------------+--------------------------------------+--------------------------------+
Fetched row(s) : 1
Concurrent update 1 1677ms
org.jooq.exception.DataChangedException: Database record has been changed
org.jooq.impl.UpdatableRecordImpl.checkIfChanged(UpdatableRecordImpl.java:427)
org.jooq.impl.UpdatableRecordImpl.storeUpdate0(UpdatableRecordImpl.java:247)
问题是 t04_1RecB.update()
尽管 tst
用于乐观锁定的字段在更新之前立即从db复制。
如果我使用 .withExecuteWithOptimisticLockingExcludeUnversioned(true)
然后更新不会失败,但是更新不会使用 tst
列以检测过期更新。
2条答案
按热度按时间jfgube3f1#
我用两个表进一步测试了这个问题。第一个表(test07)有
timestamp
键入用于乐观锁定的列。jooq文件提到int
以及timestamp
乐观锁定字段的类型。在我最初的环境中,乐观的锁定列是timestamptz
. 然而,这并没有解决问题。会引发完全相同的异常。第二个表(test03)有
int
乐观锁定列:jooq设置与前面相同,scala代码是:
运行时输出:
所以在使用
int
键入乐观锁定字段此异常不会发生,但如果使用timestamptz
或者timestamp
因为某些原因它会发生。更换
timestamptz
与int
这是一个解决方案,但我仍然想了解的问题是什么timestamptz
.g9icjywg2#
伟大的调查!不确定这是否是预期的语义-对于
timestampz
数据类型。你能为这个打开一个github问题,我们来看看吗?