首页 > 解决方案 > 跨 JPA 和 JDBC 的 Spring @Transactional

问题描述

设置:

描述:

我有一个使用JdbcOperations( JdbcTemplate) 将值插入表的方法。该表对另一个由 JPA 管理的表具有外键约束CrudRepository

有问题的方法如下所示:

    private static final String SAVE_SQL = "INSERT INTO table (entity_id, value) VALUES (?, ?) ON CONFLICT (entity_id, value) DO UPDATE SET value = EXCLUDED.value";

    @Transactional
    public void save(long id, String value) {
        this.otherService.getOrCreateEntity(id);
        
        this.jdbcOperations.update(SAVE_SQL, (ps) -> {
            ps.setLong(id);// this is a foreign key to the JPA managed table
            ps.setString(value);
        });
    }

的方法otherService如下所示:

    @Transactional
    public Entity getOrCreateEntity(long id) {
        final Optional<Entity> optionalEntity = this.crudRepository.findById(id);
        Entity entity;
        
        if (optionalEntity.isEmpty()) {
            entity = new Entity();
            entity.setId(id);
            entity = this.crudRepository.save(entity);
        } else {
            entity = optionalEntity.get();
        }
        
        return entity;
    }

我添加了以下日志记录设置以查看正在使用哪些事务:

logging:
  level:
    org.springframework.orm.jpa: DEBUG
    org.springframework.transaction: DEBUG

调用该save(long, String)方法时,我可以看到创建了一个新事务。otherService.getOrCreateEntity(long)-Method 插入一个新的Entity并将其返回给相关方法。

当有问题的方法尝试使用 插入自己的值JdbcOperations时,我得到一个DataIntegrityViolationException: violates foreign key constraint

这是事务日志:

2021-09-09 21:42:29.704 DEBUG 16077 --- [nio-9000-exec-7] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [TheJdbcOperationsUsingService.save]: PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED
2021-09-09 21:42:29.704 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:42:29.704 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@1e809ae2]

-- Call to otherService.getOrCreateEntity(long) start
2021-09-09 21:43:17.710 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:43:17.711 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
2021-09-09 21:43:17.712 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:43:17.713 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
2021-09-09 21:43:17.719 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:43:17.720 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
-- Call to otherService.getOrCreateEntity(long) finished

2021-09-09 21:43:51.374 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction rollback
2021-09-09 21:43:51.374 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Rolling back JPA transaction on EntityManager [SessionImpl(2113410426<open>)]
2021-09-09 21:43:51.376 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(2113410426<open>)] after transaction

我在两边都尝试了不同Propagation的设置,但没有运气。Isolation

标签: javaspringspring-data-jpaspring-jdbc

解决方案


您遇到的问题是,EntityManager在事务关闭之前,会在内存中保留未保存的更改缓存,因此当您尝试直接通过 JDBC 插入数据时,数据库仍然没有看到它。

要解决这个问题,您可以使用更具体的接口JpaRespository,它有一个saveAndFlush方法指示EntityManager立即写出插入,而不是稍后批量写入。


推荐阅读