table 使用 jpa 分区抛出 OptimisticLockException
table partitioning with jpa throws OptimisticLockException
我的数据库中有一个 log_table
根据 partitioning docs 分区。我有一个根据日期将记录插入分区 table 的函数和一个调用该函数的触发器,如文档中所述。
触发器示例
CREATE TRIGGER insert_measurement_trigger
BEFORE INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger();
函数示例
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.logdate >= DATE '2006-02-01' AND
NEW.logdate < DATE '2006-03-01' ) THEN
INSERT INTO measurement_y2006m02 VALUES (NEW.*);
ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
NEW.logdate < DATE '2006-04-01' ) THEN
INSERT INTO measurement_y2006m03 VALUES (NEW.*);
...
ELSIF ( NEW.logdate >= DATE '2008-01-01' AND
NEW.logdate < DATE '2008-02-01' ) THEN
INSERT INTO measurement_y2008m01 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
我正在使用 openjpa 2.3.0 作为 JPA 实现。
在 table
上触发
When i try to persist new entity in transaction to this log_table
with trigger, I get an exception on commiting:
Caused by: <openjpa-2.3.0-r422266:1540826 nonfatal store error> org.apache.openjpa.persistence.OptimisticLockException:
An optimistic lock violation was detected when flushing object instance "...entities.LogTable@67ec8ef4" to the data store.
This indicates that the object was concurrently modified in another transaction.
When I insert one record manualy using INSERT
it works, but returns
Query returned successfully: 0 rows affected, 54 ms execution time.
table
没有触发器
It works OK using the same java code that throwed the exception, so the code should be ok. I do nothing exceptional for persisting the entity.
The manual INSERT
command returns
Query returned successfully: one row affected, 51 ms execution time.
受影响行数的差异是否是 openjpa 无法正确处理的原因?在异常中提到的代码上,我发现了这个
try {
int count = executeUpdate(stmnt, sql, row);
if (count != 1) {
logSQLWarnings(stmnt);
Object failed = row.getFailedObject();
if (failed != null)
_exceptions.add(new OptimisticException(failed));
...
似乎因为使用触发器插入 return 0 个受影响的行而不是 1 个,代码将其评估为异常。
子问题
有没有办法使触发结果表现相同?我的意思是 return 1 行受到影响?以某种方式传播内部函数的结果?
我在使用 Java Ebean ORM 时遇到了同样的问题。由于 rowCount 失败,在 java 侧插入导致优化锁定错误。
我对这个问题的研究没有提供解决方案,即从插入到子项中传播行数 table 或破解行数功能。
我的解决方案(根据您的条件,将 NEW.id 更改为 table 和 RETURN NEW 中的下一个序列,这将导致插入到父 table 中)并为您提供您需要影响 row_count.
的元组响应
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.logdate >= DATE '2006-02-01' AND
NEW.logdate < DATE '2006-03-01' ) THEN
INSERT INTO measurement_y2006m02 VALUES (NEW.*);
ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
NEW.logdate < DATE '2006-04-01' ) THEN
INSERT INTO measurement_y2006m03 VALUES (NEW.*);
...
ELSIF ( NEW.logdate >= DATE '2008-01-01' AND
NEW.logdate < DATE '2008-02-01' ) THEN
INSERT INTO measurement_y2008m01 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
END IF;
--ORIGINAL CODE
--RETURN NULL
------------------NEW CODE-----------------
NEW.id = nextval('table_id_seq');
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
是的,暂时我们确实有具有 2 个不同 ID 的重复条目。所以希望不存在对父 table 的唯一约束。如果他们这样做,您可能必须删除它们。我们需要删除父 table.
上的重复项
创建将 return 触发以在插入后使用的函数。触发器将删除插入父 table 测量的新行。
CREATE OR REPLACE FUNCTION measurement_after_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
EXECUTE 'DELETE FROM measurement where measurement.id = ' || NEW.id;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
最后
添加 After INSERT Trigger to parent table measurement
CREATE TRIGGER measurement_after_insert_trigger_delete_entry
AFTER INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_after_insert_trigger();
我确实考虑过另一种可能的解决方案是只使用原始 sql 由于插入。只是不喜欢这种方法,因为我必须确保所有未来的构造函数都路由到原始 sql。上面的方法将允许代码按预期运行,就好像这只是我们插入的常规 table。
我的数据库中有一个 log_table
根据 partitioning docs 分区。我有一个根据日期将记录插入分区 table 的函数和一个调用该函数的触发器,如文档中所述。
触发器示例
CREATE TRIGGER insert_measurement_trigger
BEFORE INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger();
函数示例
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.logdate >= DATE '2006-02-01' AND
NEW.logdate < DATE '2006-03-01' ) THEN
INSERT INTO measurement_y2006m02 VALUES (NEW.*);
ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
NEW.logdate < DATE '2006-04-01' ) THEN
INSERT INTO measurement_y2006m03 VALUES (NEW.*);
...
ELSIF ( NEW.logdate >= DATE '2008-01-01' AND
NEW.logdate < DATE '2008-02-01' ) THEN
INSERT INTO measurement_y2008m01 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
我正在使用 openjpa 2.3.0 作为 JPA 实现。
在 table
上触发When i try to persist new entity in transaction to this
log_table
with trigger, I get an exception on commiting:Caused by: <openjpa-2.3.0-r422266:1540826 nonfatal store error> org.apache.openjpa.persistence.OptimisticLockException: An optimistic lock violation was detected when flushing object instance "...entities.LogTable@67ec8ef4" to the data store. This indicates that the object was concurrently modified in another transaction.
When I insert one record manualy using
INSERT
it works, but returnsQuery returned successfully: 0 rows affected, 54 ms execution time.
table
没有触发器It works OK using the same java code that throwed the exception, so the code should be ok. I do nothing exceptional for persisting the entity. The manual
INSERT
command returnsQuery returned successfully: one row affected, 51 ms execution time.
受影响行数的差异是否是 openjpa 无法正确处理的原因?在异常中提到的代码上,我发现了这个
try {
int count = executeUpdate(stmnt, sql, row);
if (count != 1) {
logSQLWarnings(stmnt);
Object failed = row.getFailedObject();
if (failed != null)
_exceptions.add(new OptimisticException(failed));
...
似乎因为使用触发器插入 return 0 个受影响的行而不是 1 个,代码将其评估为异常。
子问题
有没有办法使触发结果表现相同?我的意思是 return 1 行受到影响?以某种方式传播内部函数的结果?
我在使用 Java Ebean ORM 时遇到了同样的问题。由于 rowCount 失败,在 java 侧插入导致优化锁定错误。
我对这个问题的研究没有提供解决方案,即从插入到子项中传播行数 table 或破解行数功能。
我的解决方案(根据您的条件,将 NEW.id 更改为 table 和 RETURN NEW 中的下一个序列,这将导致插入到父 table 中)并为您提供您需要影响 row_count.
的元组响应CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.logdate >= DATE '2006-02-01' AND
NEW.logdate < DATE '2006-03-01' ) THEN
INSERT INTO measurement_y2006m02 VALUES (NEW.*);
ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
NEW.logdate < DATE '2006-04-01' ) THEN
INSERT INTO measurement_y2006m03 VALUES (NEW.*);
...
ELSIF ( NEW.logdate >= DATE '2008-01-01' AND
NEW.logdate < DATE '2008-02-01' ) THEN
INSERT INTO measurement_y2008m01 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
END IF;
--ORIGINAL CODE
--RETURN NULL
------------------NEW CODE-----------------
NEW.id = nextval('table_id_seq');
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
是的,暂时我们确实有具有 2 个不同 ID 的重复条目。所以希望不存在对父 table 的唯一约束。如果他们这样做,您可能必须删除它们。我们需要删除父 table.
上的重复项创建将 return 触发以在插入后使用的函数。触发器将删除插入父 table 测量的新行。
CREATE OR REPLACE FUNCTION measurement_after_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
EXECUTE 'DELETE FROM measurement where measurement.id = ' || NEW.id;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
最后 添加 After INSERT Trigger to parent table measurement
CREATE TRIGGER measurement_after_insert_trigger_delete_entry
AFTER INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_after_insert_trigger();
我确实考虑过另一种可能的解决方案是只使用原始 sql 由于插入。只是不喜欢这种方法,因为我必须确保所有未来的构造函数都路由到原始 sql。上面的方法将允许代码按预期运行,就好像这只是我们插入的常规 table。