我正在尝试在只读数据源之上建立一个带有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)注释存储库,则会发生同样的情况。
有人可以解释为什么交易经理会这样做吗?除了将事务状态设置为仅回滚之外,是否有一种简单/更好的方法可以避免重置标志?
感谢您的帮助。