在DefaultLockRegistry#acquire期间org.postgresql.util.PSQLException“违反唯一约束”

问题描述

我正在使用spring-integration创建分布式锁。像在org.springframework.integration.jdbc.lock.DefaultLockRepository#acquire中一样,拥有DuplicateKeyExceptions是正常的,我认为当另一个节点已经持有该锁时,这种情况将被显式处理。

但是,在违反唯一约束的情况下,使用Postgres时,我没有得到DuplicateKeyException,而是本地org.postgresql.util.PsqlException

Caused by: org.postgresql.util.PsqlException: ERROR: duplicate key value violates unique constraint "int_lock_pk"
  Detail: Key (lock_key,region)=(2c294c0e-ff49-4e14-8d3e-d5c04ef269d8,DEFAULT) already exists.
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2477)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2190)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:300)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:428)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:354)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:169)
    at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:136)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
    at org.springframework.jdbc.core.JdbcTemplate.lambda$update$0(JdbcTemplate.java:867)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:862)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:917)
    at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:927)
    at org.springframework.integration.jdbc.lock.DefaultLockRepository.acquire(DefaultLockRepository.java:163)

此情况不是 处理,并且锁获取中止。我该如何应对?

干杯, 斯蒂芬

编辑:异常包装在

Caused by: org.springframework.jdbc.UncategorizedsqlException: PreparedStatementCallback; uncategorized sqlException for sql [DELETE FROM INT_LOCK WHERE REGION=? AND LOCK_KEY=? AND CREATED_DATE<?]; sql state [25P02]; error code [0]; ERROR: current transaction is aborted,commands ignored until end of transaction block; nested exception is org.postgresql.util.PsqlException: ERROR: current transaction is aborted,commands ignored until end of transaction block

解决方法

您可以在自己的扩展名中覆盖DefaultLockRepository.acquire()来捕获该异常并分别执行逻辑。

另一方面,不清楚SQLErrorCodeSQLExceptionTranslator为什么不能正确处理此类异常。

根据现成的配置,Postgres编码如下:

<bean id="PostgreSQL" name="Postgres" class="org.springframework.jdbc.support.SQLErrorCodes">
    <property name="useSqlStateForTranslation">
        <value>true</value>
    </property>
    <property name="badSqlGrammarCodes">
        <value>03000,42000,42601,42602,42622,42804,42P01</value>
    </property>
    <property name="duplicateKeyCodes">
        <value>23505</value>
    </property>

因此,没有显示25P02。不知道发生了什么。

我们可能可以提供一个覆盖的DefaultLockRepository指针来注入一个JdbcTemplate,以便您提供自定义的SQLErrorCodeSQLExceptionTranslator来处理这种异常。

但这太多了:我想说重写该方法并捕获这样的异常将是更简单的解决方案。