从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,readOnly; ''
Bean 2处于其中。
31 09:39:44.230 [pool-1-thread-1]调试osorm.jpa.JpaTransactionManager-参与现有交易
什么都没有提交给数据库。
现在更改Bean2@Transactional
批注以添加propagation=Propagation.REQUIRES_NEW
Bean1启动只读tx。
31 09:31:36.418 [pool-1-thread-1] DEBUG 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);
}
}