Spirng加只读事务最简捷方式:@Transactional(readOnly = true)
那么,加了这个玩意,到底起了什么作用呢?来看下源码:
Spring里带事务的service方法会先进入org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction方法,
然后看次方法里的doBegin方法
@Overridepublic final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {Object transaction = doGetTransaction();........省略一些代码// No existing transaction found -> check propagation behavior to find out how to proceed.if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");}else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {SuspendedResourcesHolder suspendedResources = suspend(null);try {boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);/*** 看doBegin方法 **/doBegin(transaction, definition);prepareSynchronization(status, definition);return status;}........省略}else {........省略}}
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
@Overrideprotected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {if (txObject.getConnectionHolder() == null ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {Connection newCon = this.dataSource.getConnection();txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}txObject.getConnectionHolder().setSynchronizedWithTransaction(true);con = txObject.getConnectionHolder().getConnection();/*** 看这个 prepareConnectionForTransaction方法: @Transactional(readOnly = true) 执行con.setReadOnly(true);*/Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,// so we don't want to do it unnecessarily (for example if we've explicitly// configured the connection pool to set it already)./*** 看这个 con.setAutoCommit(false);*/if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);con.setAutoCommit(false);}prepareTransactionalConnection(con, definition);txObject.getConnectionHolder().setTransactionActive(true);........省略一些代码}catch (Throwable ex) {........省略一些代码}}
所以,是设置了 con.setReadOnly(true); 而且代码顺序是
先con.setReadOnly(true);
再con.setAutoCommit(false);
加了只读注解后,会有哪些影响呢?
比如做报表或者做统计:
- 只读事务的好处,作为ORM框架优化的暗号,保证读一致性,事务内不允许DML操作,否则报错
- 只读事务的场景,如统计,保证统计结果准确性。
- 只读事务里,也可以在只读事务里使用 select... for update
- 因为只读事务,所有查询都是在一个事务里,所以可以配合mysql的事务隔离级别理解一下(比如,多次查询同一个表)
缺点是:
- 使用事务,动态生成代理类,增加开销。