从 readOnly=true 调用 readOnly=false 不起作用,因为上一个事务仍在继续。
在您的示例中,服务层上的 handle() 方法正在启动新的读写事务。如果handle方法又调用了注解为只读的服务方法,则只读将不起作用,因为它们将参与现有的读写事务。
如果这些方法必须是只读的,那么您可以使用 Propagation.REQUIRES_NEW 对其进行注释,然后它们将启动新的只读事务,而不是参与现有的读写事务。
这是一个工作示例,CircuitStateRepository 是一个 spring-data JPA 存储库。
BeanS 调用 transactional=read-only Bean1,后者进行查找并调用 transactional=read-write Bean2,后者保存一个新对象。
31 09:39:44.199 [pool-1-thread-1] 调试 osorm.jpa.JpaTransactionManager - 使用名称 [nz.co.vodafone.wcim.business.Bean1.startSomething] 创建新事务:PROPAGATION_REQUIRED,ISOLATION_DEFAULT ,只读; ''
-
Bean 2 参与其中。
31 09:39:44.230 [pool-1-thread-1] 调试 o.s.orm.jpa.JpaTransactionManager - 参与现有事务
没有向数据库提交任何内容。
现在将 Bean2 @Transactional 注解改为添加propagation=Propagation.REQUIRES_NEW
-
Bean1 启动一个只读 tx。
31 09:31:36.418 [pool-1-thread-1] 调试 osorm.jpa.JpaTransactionManager - 使用名称 [nz.co.vodafone.wcim.business.Bean1.startSomething] 创建新事务:PROPAGATION_REQUIRED,ISOLATION_DEFAULT ,只读; ''
-
Bean2 开始一个新的读写 tx
31 09:31:36.449 [pool-1-thread-1] 调试 osorm.jpa.JpaTransactionManager - 暂停当前事务,创建名为 [nz.co.vodafone.wcim.business.Bean2.createSomething] 的新事务
Bean2 所做的更改现在已提交到数据库。
这是示例,使用 spring-data、hibernate 和 oracle 测试。
@Named
public class BeanS {
@Inject
Bean1 bean1;
@Scheduled(fixedRate = 20000)
public void runSomething() {
bean1.startSomething();
}
}
@Named
@Transactional(readOnly = true)
public class Bean1 {
Logger log = LoggerFactory.getLogger(Bean1.class);
@Inject
private CircuitStateRepository csr;
@Inject
private Bean2 bean2;
public void startSomething() {
Iterable<CircuitState> s = csr.findAll();
CircuitState c = s.iterator().next();
log.info("GOT CIRCUIT {}", c.getCircuitId());
bean2.createSomething(c.getCircuitId());
}
}
@Named
@Transactional(readOnly = false)
public class Bean2 {
@Inject
CircuitStateRepository csr;
public void createSomething(String circuitId) {
CircuitState c = new CircuitState(circuitId + "-New-" + new DateTime().toString("hhmmss"), new DateTime());
csr.save(c);
}
}