为什么JpaTransactionManager在提交时重置只读标志?

时间:2018-02-12 16:05:13

标签: java spring transactions spring-data-jpa

我正在尝试在只读数据源之上建立一个带有JPA存储库的简单Spring Boot项目,我想将只读标志作为提示传播到底层JDBC驱动程序以进行性能优化,根据Spring Data JPA Reference

存储库实现如下所示:

public interface MyReadOnlyRepository extends JpaRepository<String, String> {}

这是配置类:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  entityManagerFactoryRef = "readOnlyEntityManagerFactory",
  transactionManagerRef = "readOnlyTransactionManager",
  basePackageClasses = ReadOnlyDbConfig.class)
public class ReadOnlyDbConfig {

  @Bean(name = "readOnlyDataSource")
  @ConfigurationProperties(prefix = "spring.datasource.ro")
  public DataSource dataSource() {

    return DataSourceBuilder.create().build();
  }

  @Bean(name = "readOnlyEntityManagerFactory")
  public LocalContainerEntityManagerFactoryBean entityManagerFactory(
    EntityManagerFactoryBuilder builder,
    @Qualifier("readOnlyDataSource") DataSource dataSource) {

    return builder
            .dataSource(dataSource)
            .packages(MyEntity.class)
            .persistenceUnit("readOnly")
            .build();
  }

  @Bean(name = "readOnlyTransactionManager")
  public PlatformTransactionManager transactionManager(
        @Qualifier("readOnlyEntityManagerFactory") EntityManagerFactory entityManagerFactory) {

    return new JpaTransactionManager(entityManagerFactory);
  }

}

以及相关的YML属性:

spring:
  datasource:
    ro:
      url: jdbc:postgresql://...
      username: ...
      password: ...
      driver-class-name: org.postgresql.Driver
      default-read-only: true

为了测试它,我编写了一个针对dockerres的PostgresSQL实例运行的简单测试:

@SpringBootTest(classes = TestApplication.class)
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = { PostgresInDockerInitializer.class })
public class MyReadOnlyStoreTest {

  @Inject
  private MyReadOnlyRepository repo;

  @Test(expected = RuntimeException.class)
  public void testIsReadOnly() {

    repo.save("test");
  }

}

我只是为了测试标志是否设置而调用了 save :我很欣赏只读标志只是作为JDBC驱动程序的提示,而不是作为保护机制反对写操作。正如预期的那样,测试抛出异常(“无法在只读事务中执行INSERT”)。

我的问题是,只要事务成功完成,JPA事务管理器就会将连接只读标志重置为false。因此,例如,此测试失败:

@Test(expected = RuntimeException.class)
public void testIsReadOnly() {

  repo.findAll(); // <-- on commit, the transaction manager resets the read-only flag to false
  repo.save("test"); 
}

请注意,如果根据Spring Data JPA Reference使用 @Transactional(readOnly = true)注释存储库,则会发生同样的情况。

有人可以解释为什么交易经理会这样做吗?除了将事务状态设置为仅回滚之外,是否有一种简单/更好的方法可以避免重置标志?

感谢您的帮助。

0 个答案:

没有答案