首先配置sqlsessionFactoryBean
- 首先配置一个sqlSessionFactoryBean,创建的时候会自动生成一个configuration,会把数据库信息赋值给environment里面在dao层取值的时候,会根据这个值取datasource的值,datasource作为key取连接对象
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = this.buildSqlSessionFactory();
}
targetConfiguration.setEnvironment(new Environment(this.environment, (TransactionFactory)(this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory), this.dataSource));
- 生成了SpringManagedTransactionFactory
SpringManagedTransactionFactory来生成springManagedTransaction类
public Connection getConnection() throws SQLException {
if (this.connection == null) {
this.openConnection();
}
return this.connection;
}
private void openConnection() throws SQLException {
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
LOGGER.debug(() -> {
return "JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring";
});
}
如果事物里面没有开启,DataSourceUtils.getConnection拿到的是一个新的连接,否则是一个前面放置的事物连接
事物的Connection对象的绑定到线程的时机
核心code:TransactionSynchronizationManager.bindResource(this.getDataSource(), txObject.getConnectionHolder());
我们注意到ConnectionHolder进行了存储,存储的key是获取的dataSource(),此时的dataSource为我们注入的热库datasource。
接下来我们获取事务,我们通过数据源得到一个ConnectionHolder保存在事务管理器中,获取ConnectionHolder,是通过
DataSourceTransactionManager.get
TransactionSynchronizationManager.getResource获取,这个方法非常重要。
DataSourceTransactionManager
protected Object doGetTransaction() {
DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject();
txObject.setSavepointAllowed(this.isNestedTransactionAllowed());
ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
TransactionSynchronizationManager
@Nullable
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
return value;
}
TransactionSynchronizationManager
@Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = (Map)resources.get();
if (map == null) {
return null;
} else {
Object value = map.get(actualKey);
if (value instanceof ResourceHolder && ((ResourceHolder)value).isVoid()) {
map.remove(actualKey);
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
}
我们看方法都可以猜到,第一次获取链接肯定不存在的,毕竟我们还没有进行存储。
接下来操作肯定是要得到一个连接,从哪里得到,
当然是通过我们注入的dataSource得到链接
首先我们看事务管理器获取Connection,在DataSourceTransactionManager#doGetTransaction中首先获取ConnectionHolder放置在DataSourceTransactionManager.DataSourceTransactionObject中,我们注意到是从TransactionSynchronizationManager.getResource(this.dataSource)通过我们注入的数据源获取holder
别的文档拷贝的
我们看看PlatformTransactionManager子类AbstractPlatformTransactionManager对该方法的实现,这个方法其实不陌生,在《Spring事物03-源码分析TransactionInterceptor》中我们分析的,拦截器的invoke方法最后就是调用这个方法来开启事物,里面会处理传播属性的各种情况。这里只看获取TransactionStatus,实际上获取的是DefaultTransactionStatus实例,这里面首先会获取Object transaction ,然后构造DefaultTransactionStatus对象返回。
AbstractPlatformTransactionManager
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
//省略...
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
//省略...
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.obtainDataSource().getConnection();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
this.prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = this.determineTimeout(definition);
if (timeout != -1) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable var7) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, this.obtainDataSource());
txObject.setConnectionHolder((ConnectionHolder)null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
}
}
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = (Map)resources.get();
if (map == null) {
map = new HashMap();
resources.set(map);
}
Object oldValue = ((Map)map).put(actualKey, value);
if (oldValue instanceof ResourceHolder && ((ResourceHolder)oldValue).isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
} else {
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]");
}
}
}
获取数据源
接下来我们获取事务,我们通过数据源得到一个ConnectionHolder保存在事务管理器中,获取ConnectionHolder,是通过TransactionSynchronizationManager.getResource获取,这个方法非常重要。