Springテクノロジーの内幕-Springアーキテクチャと設計原理を深く解析する(三)データベースの操作実現
最近の事は本当に比较的に多くて、直ちに招待状を更新していないで、またみんなに许してもらいます.今日は、スプリングJDBCの実現について話し合いましょう.
Spring JDBCについて
やはりSpring JDBCから言えば、今ではHibernateや他のORMツールを直接使うアプリケーションが多いですが.しかし、JDBCはやはり基本的で、その中のJdbcTemplateは私たちがよく使っています.例えば、JDBCtempplateのexecute方法は、基本的な方法であり、この方法の実現では、データベース操作の基本的な過程を見ることができます.
データベースを使用する場合、データベース接続の管理が重要なポイントがあります.ここでは、DataSourceUtilsによって行われています.Springはこの補助クラスによってデータのConnectionを管理する.たとえば、接続のオン/オフなどの操作を行います.DataSourceUtilsは、次のコードに示すように、これらのデータベースConnection管理の実装を行います.
データベース操作クラスRDBMSについて
JdbcTemplateから、彼は多くの簡単なクエリーと更新機能を提供していることがわかります.ただし、より高度な抽象化と、よりオブジェクト向けの方法でデータベースにアクセスする必要がある場合は、Springはorg.springframework.jdbc.objectパッケージを提供し、SqlQuery、SqlMappingQuery、SqlUpdate、StoredProcedureなどのクラスが含まれています.これらのクラスはSpring JDBCアプリケーションで使用できます.ただし、これらのクラスを使用する場合は、JdbcTemplateを基本的な操作実装として構成する必要があります.これらの機能実装では、データベース操作の実装の部分は基本的にJdbcTemplateに依存して行われるためです.
例えば、MappingSqlQueryの使用過程は、非常に簡潔である.データのマッピングコードを設計した後、クエリーで得られたレコードはすでに前の設計に従ってオブジェクトリストに変換され、1つのクエリーレコードは1つのデータオブジェクトに対応し、データベースのデータレコードを直接Javaオブジェクトにマッピングしてプログラムで使用することができ、同時に第三者ORMツールの構成を避けることができる.簡単なデータマッピングの場合に便利です.mapRow法の実装で提供されるデータ変換規則は,Hibernateを用いたときにHibernateのhbmファイルが果たす役割と非常に類似している.このMappingSqlQueryでは、以下のコードに示すように、設定をcompileする必要があります.
Spring対JDBCの動作では、基本的にJDBC/HibernateベースのAPIのパッケージである.これらのパッケージは直接使用することもできるし、IoCコンテナで再使用するように構成することもできる.IoCコンテナと組み合わせて使用すると、トランザクション管理に関連する処理部分が多く見られ、非常に学習に値する.そこで、データソースの管理-Hibernateにおけるsessionの管理、スレッドとの結合などを見ることができる.
Spring JDBCについて
やはりSpring JDBCから言えば、今ではHibernateや他のORMツールを直接使うアプリケーションが多いですが.しかし、JDBCはやはり基本的で、その中のJdbcTemplateは私たちがよく使っています.例えば、JDBCtempplateのexecute方法は、基本的な方法であり、この方法の実現では、データベース操作の基本的な過程を見ることができます.
//execute sql
public void execute(final String sql) throws DataAccessException {
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL statement [" + sql + "]");
}
class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
public Object doInStatement(Statement stmt) throws SQLException {
stmt.execute(sql);
return null;
}
public String getSql() {
return sql;
}
}
execute(new ExecuteStatementCallback());
}
// java.sql.Statement SQL
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
// Connection, Connection Spring
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
// Statement
stmt = conToUse.createStatement();
applyStatementSettings(stmt);
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
//
T result = action.doInStatement(stmtToUse);
handleWarnings(stmt);
return result;
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
// , Connection , Spring Spring
//Spring ,
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
}
finally {
JdbcUtils.closeStatement(stmt);
// connection
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
データベースを使用する場合、データベース接続の管理が重要なポイントがあります.ここでは、DataSourceUtilsによって行われています.Springはこの補助クラスによってデータのConnectionを管理する.たとえば、接続のオン/オフなどの操作を行います.DataSourceUtilsは、次のコードに示すように、これらのデータベースConnection管理の実装を行います.
// , doGetConnection ,
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);
}
catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
}
}
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
// Connection , TransactionSynchronizationManager ThreadLocal
// TransactionSynchronizationManager ,
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.
// Connection, Bean ,
// Connection TransactionSynchronizationManager 。
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;
}
データベース操作クラスRDBMSについて
JdbcTemplateから、彼は多くの簡単なクエリーと更新機能を提供していることがわかります.ただし、より高度な抽象化と、よりオブジェクト向けの方法でデータベースにアクセスする必要がある場合は、Springはorg.springframework.jdbc.objectパッケージを提供し、SqlQuery、SqlMappingQuery、SqlUpdate、StoredProcedureなどのクラスが含まれています.これらのクラスはSpring JDBCアプリケーションで使用できます.ただし、これらのクラスを使用する場合は、JdbcTemplateを基本的な操作実装として構成する必要があります.これらの機能実装では、データベース操作の実装の部分は基本的にJdbcTemplateに依存して行われるためです.
例えば、MappingSqlQueryの使用過程は、非常に簡潔である.データのマッピングコードを設計した後、クエリーで得られたレコードはすでに前の設計に従ってオブジェクトリストに変換され、1つのクエリーレコードは1つのデータオブジェクトに対応し、データベースのデータレコードを直接Javaオブジェクトにマッピングしてプログラムで使用することができ、同時に第三者ORMツールの構成を避けることができる.簡単なデータマッピングの場合に便利です.mapRow法の実装で提供されるデータ変換規則は,Hibernateを用いたときにHibernateのhbmファイルが果たす役割と非常に類似している.このMappingSqlQueryでは、以下のコードに示すように、設定をcompileする必要があります.
protected final void compileInternal() {
// compile , getDeclaredParameters , PreparedStatementCreatorFactory
this.preparedStatementFactory = new PreparedStatementCreatorFactory(getSql(), getDeclaredParameters());
this.preparedStatementFactory.setResultSetType(getResultSetType());
this.preparedStatementFactory.setUpdatableResults(isUpdatableResults());
this.preparedStatementFactory.setReturnGeneratedKeys(isReturnGeneratedKeys());
if (getGeneratedKeysColumnNames() != null) {
this.preparedStatementFactory.setGeneratedKeysColumnNames(getGeneratedKeysColumnNames());
}
this.preparedStatementFactory.setNativeJdbcExtractor(getJdbcTemplate().getNativeJdbcExtractor());
onCompileInternal();
}
クエリーを実行する場合、実際にはSqlQueryのexecuteByNamedParamメソッドが実行されます.このメソッドでは、SQL文の構成、データがデータ・オブジェクトに記録された変換のRowMapperの構成、JdbcTemplateを使用してデータのクエリーを完了し、Javaデータ・オブジェクトへのデータ記録の変換を開始します.次のコードに示します. public List<T> executeByNamedParam(Map<String, ?> paramMap, Map context) throws DataAccessException {
validateNamedParameters(paramMap);
// SQL
ParsedSql parsedSql = getParsedSql();
MapSqlParameterSource paramSource = new MapSqlParameterSource(paramMap);
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
// SQL Parameters rowMapper, rowMapper
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, getDeclaredParameters());
RowMapper<T> rowMapper = newRowMapper(params, context);
// JdbcTemplate, JdbcTemplate , JdbcTemplate
return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, params), rowMapper);
}
Spring対JDBCの動作では、基本的にJDBC/HibernateベースのAPIのパッケージである.これらのパッケージは直接使用することもできるし、IoCコンテナで再使用するように構成することもできる.IoCコンテナと組み合わせて使用すると、トランザクション管理に関連する処理部分が多く見られ、非常に学習に値する.そこで、データソースの管理-Hibernateにおけるsessionの管理、スレッドとの結合などを見ることができる.