Spirng加只读事务最简捷方式:@Transactional(readOnly = true)
那么,加了这个玩意,到底起了什么作用呢?来看下源码:
Spring里带事务的service方法会先进入org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction方法,
然后看次方法里的doBegin方法
@Override
public 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
@Override
protected 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);
加了只读注解后,会有哪些影响呢?
比如做报表或者做统计:
缺点是:
另记录一篇事务隔离级别的文章:
https://www.cnblogs.com/wyaokai/p/10921323.html
1.不可重复读(读已提交RC): 开启RC事务,A在事务里查询User表(id=1),然后B去更新事务(id=1)并提交,A再查询是可以看到B提交后的数据的,这就造成了同一个事务里,A看到的数据是不一样的,即不可重复读
2.可重复读(RR): 开启RR事务, A在事务里查询User表(id=1),然后B开启事务并提交User表(id=1)的更新,A再次查询是查不到B提交的数据的, 这就是A在同一个事务里对数据的读取是一致的