Wenn mehrere gleichzeitige Anfragen mit demselben zusammengesetzten Primärschlüssel die API erreichen, schlägt die MERGE-Anweisung gelegentlich mit folgendem Fehler fehl:
Code: Select all
ORA-00001: unique constraint violated
Code: Select all
org.springframework.dao.DuplicateKeyException:
PreparedStatementCallback; SQL [MERGE INTO USER_ACTIONS USING (
SELECT ? AS SESSION_ID, ? AS ITEM_ID, ? AS USER_ID, ? AS ACTION_ID,
? AS PAYLOAD, ? AS CREATED_AT, ? AS UPDATED_AT FROM dual
) s
ON (t.SESSION_ID = s.SESSION_ID
AND t.ITEM_ID = s.ITEM_ID
AND t.USER_ID = s.USER_ID
AND t.ACTION_ID = s.ACTION_ID)
WHEN MATCHED THEN UPDATE SET
t.PAYLOAD = s.PAYLOAD,
t.UPDATED_AT = s.UPDATED_AT
WHEN NOT MATCHED THEN INSERT (
SESSION_ID, ITEM_ID, USER_ID, ACTION_ID, PAYLOAD, CREATED_AT, UPDATED_AT
) VALUES (
s.SESSION_ID, s.ITEM_ID, s.USER_ID, s.ACTION_ID, s.PAYLOAD, s.CREATED_AT, s.UPDATED_AT
)]; ORA-00001: unique constraint (DUMMY_SCHEMA.USER_ACTIONS_PK) violated
nested exception is java.sql.SQLIntegrityConstraintViolationException:
ORA-00001: unique constraint (DUMMY_SCHEMA.USER_ACTIONS_PK) violated
at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(
SQLExceptionSubclassTranslator.java:89
)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(
AbstractFallbackSQLExceptionTranslator.java:70
)
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1541)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:667)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:960)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:1015)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(
NamedParameterJdbcTemplate.java:321
)
at com.example.demo.dao.UserActionDaoImpl.mergeAction(UserActionDaoImpl.java:45)
(rest of stack trace)
Caused by: java.sql.SQLIntegrityConstraintViolationException:
ORA-00001: unique constraint (DUMMY_SCHEMA.USER_ACTIONS_PK) violated
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:494)
(rest of stack trace)
Umgebung
- Spring Boot REST API
- Oracle-Datenbank
- 4 Anwendungsinstanzen
- Lasttest: ~1100 gleichzeitige Benutzer, 1 Minute Hochlauf
Zusammengesetzter Primärschlüssel:
Code: Select all
(USER_ID, ITEM_ID, VERSION_ID, ACTION_ID)
Code: Select all
MERGE INTO user_actions t
USING (
SELECT
:sessionId AS session_id,
:itemId AS item_id,
:userId AS user_id,
:versionId AS version_id,
:actionId AS action_id
FROM dual
) s
ON (
t.session_id = s.session_id
AND t.item_id = s.item_id
AND t.user_id = s.user_id
AND t.action_id = s.action_id
)
WHEN MATCHED THEN UPDATE
SET t.updated_at = :updatedAt
WHEN NOT MATCHED THEN INSERT (...);
Alle Erkenntnisse von Leuten, die sich mit dieser Art von Upsert-Szenario mit hoher Parallelität befasst haben, wären wirklich hilfreich.
Mobile version