springソースの勉強シリーズ4.1-spring ibatisの事務管理を実現しました。
9630 ワード
もっと読む
このトランザクションはspringによって管理されており、spring管理データベースに接続されていると理解できる。ibatisがsqlを実行する場合、取得したデータベース接続はspring管理のデータベース接続と同じであることを保証する必要があります。
この文章は主にibatisの角度から分析しています。ibatisはどのようにspringで管理されているデータベース接続を取得しますか?
設定を適用:
ibatisは、プロキシのDataSourceのget Connectionでデータベース接続を取得します。
Transaction AwareData SourceProxyはibatisとspringを接続する鍵です。ibatisデータベース接続はこのspring-jdbcのクラスです。
Transaction AwareData SourceProxy噘get Connection
Transaction AwareInvocationhandler
Transactions SyncronizationManager類では、threadLocal技術を利用してスレッド取得のデータベース接続が同じであることを保証しています。
このトランザクションはspringによって管理されており、spring管理データベースに接続されていると理解できる。ibatisがsqlを実行する場合、取得したデータベース接続はspring管理のデータベース接続と同じであることを保証する必要があります。
この文章は主にibatisの角度から分析しています。ibatisはどのようにspringで管理されているデータベース接続を取得しますか?
設定を適用:
classpath:context/dao/SqlMapConfig.xml
プログラムコール(insertを例に):public class UserDAOImpl extends SqlMapClientDaoSupport implements UserDAO {
public int insertUser(User user) {
int id = (Integer) getSqlMapClientTemplate().insert("insertUser", user);
return id;
}
}
spring-orm((zhi sql MapClient Template)public Object insert(final String statementName, final Object parameterObject)
throws DataAccessException {
return execute(new SqlMapClientCallback
spring-orm菗sql MapClient Templatepublic T execute(SqlMapClientCallback action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
SqlMapSession session = this.sqlMapClient.openSession();
if (logger.isDebugEnabled()) {
logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
}
Connection ibatisCon = null;
try {
Connection springCon = null;
DataSource dataSource = getDataSource();
boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);
// Obtain JDBC Connection to operate on...
try {
ibatisCon = session.getCurrentConnection();
if (ibatisCon == null) {
springCon = (transactionAware ?
dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));
session.setUserConnection(springCon);
if (logger.isDebugEnabled()) {
logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
}
}
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
}
// Execute given callback...
try {
return action.doInSqlMapClient(session);
}
catch (SQLException ex) {
throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
}
finally {
try {
if (springCon != null) {
if (transactionAware) {
springCon.close();
}
else {
DataSourceUtils.doReleaseConnection(springCon, dataSource);
}
}
}
catch (Throwable ex) {
logger.debug("Could not close JDBC Connection", ex);
}
}
// Processing finished - potentially session still to be closed.
}
finally {
// Only close SqlMapSession if we know we've actually opened it
// at the present level.
if (ibatisCon == null) {
session.close();
}
}
}
ポイント:springCon = (transactionAware ?
dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));
Sql MapClient FactoryBen芫after Propertiessetpublic void afterPropertiesSet() throws Exception {
if (this.lobHandler != null) {
// Make given LobHandler available for SqlMapClient configuration.
// Do early because because mapping resource might refer to custom types.
configTimeLobHandlerHolder.set(this.lobHandler);
}
try {
this.sqlMapClient = buildSqlMapClient(this.configLocations, this.mappingLocations, this.sqlMapClientProperties);
// Tell the SqlMapClient to use the given DataSource, if any.
if (this.dataSource != null) {
TransactionConfig transactionConfig = (TransactionConfig) this.transactionConfigClass.newInstance();
DataSource dataSourceToUse = this.dataSource;
if (this.useTransactionAwareDataSource && !(this.dataSource instanceof TransactionAwareDataSourceProxy)) {
dataSourceToUse = new TransactionAwareDataSourceProxy(this.dataSource);
}
transactionConfig.setDataSource(dataSourceToUse);
transactionConfig.initialize(this.transactionConfigProperties);
applyTransactionConfig(this.sqlMapClient, transactionConfig);
}
}
finally {
if (this.lobHandler != null) {
// Reset LobHandler holder.
configTimeLobHandlerHolder.remove();
}
}
}
DataSourceタイプの属性を設定すると、エージェントクラスが生成されます。このプロキシクラスは、spring aopによって実現されるプロキシクラスではなく、DataSourceインターフェースの静的なプロキシクラスを実現するだけである。ibatisは、プロキシのDataSourceのget Connectionでデータベース接続を取得します。
Transaction AwareData SourceProxyはibatisとspringを接続する鍵です。ibatisデータベース接続はこのspring-jdbcのクラスです。
Transaction AwareData SourceProxy噘get Connection
@Override
public Connection getConnection() throws SQLException {
DataSource ds = getTargetDataSource();
Assert.state(ds != null, "'targetDataSource' is required");
return getTransactionAwareConnectionProxy(ds);
}
Transaction AwareData SourceProxyprotected Connection getTransactionAwareConnectionProxy(DataSource targetDataSource) {
return (Connection) Proxy.newProxyInstance(
ConnectionProxy.class.getClassLoader(),
new Class[] {ConnectionProxy.class},
new TransactionAwareInvocationHandler(targetDataSource));
}
springはTransaction AwareData SourceProxyで取得したデータベース接続を代理して、プロキシ類を生成する方式はProxy+InvocationHandlerです。Transaction AwareInvocationhandler
if (this.target == null) {
if (this.closed) {
throw new SQLException("Connection handle already closed");
}
if (shouldObtainFixedConnection(this.targetDataSource)) {
this.target = DataSourceUtils.doGetConnection(this.targetDataSource);
}
}
Connection actualTarget = this.target;
if (actualTarget == null) {
actualTarget = DataSourceUtils.doGetConnection(this.targetDataSource);
}
ここの横断面は主に私達のために作られています。主に同期の接続(スレッド内の)DataSourceUtilspublic static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = dataSource.getConnection();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
}
これらを分析して、ibatisはやはりTransaction SyncronizationManagerにデータベース接続を取得させます。中間の過程の実現については,人によって知見する。Transactions SyncronizationManager類では、threadLocal技術を利用してスレッド取得のデータベース接続が同じであることを保証しています。