DuplicateKeyException raised when using Spring JdbcMetadataStore (Oracle)

别来无恙 提交于 2020-05-24 02:05:31

问题


My current configuration of file:inbound-channel-adapter is working fine. I'm running the application in multiple servers and only one is actually processing the file. Database table INT_METADATA_STORE also updated successfully. Issue I'm facing is that one of the servers are still trying to insert the record and below exception is raised:

org.springframework.messaging.MessagingException: nested exception is
org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; 
SQL [INSERT INTO INT_METADATA_STORE(METADATA_KEY, METADATA_VALUE, REGION) SELECT ?, ?, ? FROM INT_METADATA_STORE WHERE METADATA_KEY=? AND REGION=? HAVING COUNT(*)=0];
ORA-00001: unique constraint (SMS_OWNER.INT_METADATA_STORE_PK) violated; 
nested exception is java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (SMS_OWNER.INT_METADATA_STORE_PK) violated

I've tried different flavors of isolation and no luck. Is this something related to the transaction manager used since I'm using XML with Spring Integration + Java? See below some configurations:

<int-file:inbound-channel-adapter directory="file:/tmp/input/" prevent-duplicates="true" filter="compositeFileListFilter">
  <int:poller max-messages-per-poll="1" cron="*/10 * * * * *">
    <int:transactional transaction-manager="transactionManager" isolation="READ_COMMITTED" timeout="5" />
  </int:poller>
</int-file:inbound-channel-adapter>

and

@Configuration
@EnableTransactionManagement
public class MetadataStoreConfiguration {

    @Value("${input.file.pattern:(DUMMY)(_).*\\.(xml)}")
    private String pattern;

    @Bean
    @Qualifier("fileSystemPersistentAcceptOnceFileListFilter")
    public FileSystemPersistentAcceptOnceFileListFilter fileSystemPersistentAcceptOnceFileListFilter(final DataSource dataSource) {
        return new FileSystemPersistentAcceptOnceFileListFilter(metadataStore(dataSource),"");
    }

    @Bean
    @Qualifier("metadataStore")
    public JdbcMetadataStore metadataStore(final DataSource dataSource) {
        JdbcMetadataStore metadataStore = new JdbcMetadataStore(dataSource);
        return metadataStore;
    }

    @Bean 
    public CompositeFileListFilter<File> compositeFileListFilter(FileSystemPersistentAcceptOnceFileListFilter fileSystemPersistentAcceptOnceFileListFilter) {       
        CompositeFileListFilter<File> filter = new CompositeFileListFilter<>(Arrays.asList(fileSystemPersistentAcceptOnceFileListFilter, new RegexPatternFileListFilter(pattern)));
        return filter;
    }

    @Bean
    @Primary
    public PlatformTransactionManager transactionManager(final DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

I'm using Spring Boot 2.2.4.RELEASE, Java 8 and Oracle as database. Any help will be much appreciated.


回答1:


No, your configuration is fully OK. It really doesn't matter because it is read only once at start up. At runtime you have only beans and they are wired properly. So, it's OK to have that PlatformTransactionManager and compositeFileListFilter in Java config and use them as references from XML one.

I think the problem is not about transactions. More over it even looks like they work!

Both of your transactions try to insert and don't see a value. Of course, one of them is OK on commit, but another fails because the value is already inserted. With IINSERT INTO .. SELECT ... HAVING we achieve an atomicity for the current transaction. But it really doesn't give us a chance to avoid conflict on commit...

It looks like our JdbcMetadataStore.putIfAbsent() should be improved to catch this SQLIntegrityConstraintViolationException as a fact of data presence and return the current value.

Please, raise a GH issue and we'll think how to proceed!



来源:https://stackoverflow.com/questions/61747197/duplicatekeyexception-raised-when-using-spring-jdbcmetadatastore-oracle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!