【README】
本文总结自《spring揭秘》,作者王福强,非常棒的一本书,墙裂推荐;
【1】spring集成数据访问技术总结
【1.1】解耦数据访问资源与业务逻辑
1)数据访问资源管理,通过模版方法模式来建模(如JdbcTemplate,HibernateTemplate模版类);而具体的数据访问逻辑统一由回调接口提供(策略模式,如PreparedStatementCallback,HibernateCallback回调接口);从而将数据访问资源管理和具体数据访问逻辑解耦开;
【JdbcTemplate#execute()】管理数据访问资源
private <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action, boolean closeResources) throws DataAccessException {
// .......
Connection con = DataSourceUtils.getConnection(this.obtainDataSource()); // 获取连接
PreparedStatement ps = null;
boolean var13 = false;
Object var18;
try {
var13 = true;
ps = psc.createPreparedStatement(con); // 创建预编译语句
this.applyStatementSettings(ps); // 设置配置
T result = action.doInPreparedStatement(ps); // *重要: 执行回调(具体数据访问逻辑)
this.handleWarnings((Statement)ps);
// ......
} catch (SQLException var14) {
// ......
String sql = getSql(psc);
psc = null;
JdbcUtils.closeStatement(ps); // 关闭语句
ps = null;
DataSourceUtils.releaseConnection(con, this.getDataSource()); // 释放连接
con = null;
throw this.translateException("PreparedStatementCallback", sql, var14);
} finally {
if (var13) {
if (closeResources) {
if (psc instanceof ParameterDisposer) {
ParameterDisposer parameterDisposer = (ParameterDisposer)psc;
parameterDisposer.cleanupParameters();
}
JdbcUtils.closeStatement(ps);// 关闭语句
DataSourceUtils.releaseConnection(con, this.getDataSource()); // 释放连接
}
}
}
if (closeResources) {
if (psc instanceof ParameterDisposer) {
ParameterDisposer parameterDisposer = (ParameterDisposer)psc;
parameterDisposer.cleanupParameters();
}
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con, this.getDataSource());// 释放连接
}
return var18;
}
【JdbcTemplate#getPreparedStatementCallback()方法】回调接口实现示例
private PreparedStatementCallback<int[]> getPreparedStatementCallback(BatchPreparedStatementSetter pss, @Nullable KeyHolder generatedKeyHolder) {
return (ps) -> {
boolean var13 = false;
int[] rowsAffectedArray;
label192: {
int[] var19;
try {
var13 = true;
int batchSize = pss.getBatchSize();
InterruptibleBatchPreparedStatementSetter var10000;
if (pss instanceof InterruptibleBatchPreparedStatementSetter ibpss) {
var10000 = ibpss;
} else {
var10000 = null;
}
InterruptibleBatchPreparedStatementSetter ipss = var10000;
if (generatedKeyHolder != null) {
generatedKeyHolder.getKeyList().clear();
}
if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
for(int i = 0; i < batchSize; ++i) {
pss.setValues(ps, i);
if (ipss != null && ipss.isBatchExhausted(i)) {
break;
}
ps.addBatch();
}
int[] results = ps.executeBatch();
if (generatedKeyHolder != null) {
this.storeGeneratedKeys(generatedKeyHolder, ps, batchSize);
}
rowsAffectedArray = results;
var13 = false;
break label192;
}
List<Integer> rowsAffected = new ArrayList();
int ix = 0;
while(true) {
if (ix < batchSize) {
pss.setValues(ps, ix);
if (ipss == null || !ipss.isBatchExhausted(ix)) {
rowsAffected.add(ps.executeUpdate());
if (generatedKeyHolder != null) {
this.storeGeneratedKeys(generatedKeyHolder, ps, 1);
}
++ix;
continue;
}
}
rowsAffectedArray = new int[rowsAffected.size()];
for(int ixx = 0; ixx < rowsAffectedArray.length; ++ixx) {
rowsAffectedArray[ixx] = (Integer)rowsAffected.get(ixx);
}
var19 = rowsAffectedArray;
var13 = false;
break;
}
} finally {
// ......
}
// ......
return var19;
}
// ......
return rowsAffectedArray;
};
}
【1.2】集成数据访问技术
1)spring对数据访问技术的集成总结为以下3点:
- 数据访问资源管理:spring通过FactoryBean管理连接工厂,而由模板方法类管理连接(如JdbcTemplate);
- 数据访问异常转译*:spring对不同数据访问技术的异常进行转译,形成统一数据访问异常体系,使得客户端可以以统一的方式处理异常 ;
- 事务管理抽象*:spring对不同数据访问技术的事务管理进行抽象,形成事务管理抽象层,使得客户端可以以统一方式管理事务 ;
【1.2.1】数据访问资源管理
1)数据访问资源,主要涉及2种资源:连接与连接工厂。通常spring通过FactoryBean管理连接工厂,连接管理由具体的模版方法类来处理;
- 连接或者说会话资源: 指的是客户端与数据媒介进行通信的通道,每次数据访问都是通过连接访问,操作完成后关闭当前连接;
- 如JDBC技术的连接使用Connection抽象,Hibernate技术的连接使用Session抽象;
- 连接工厂(ConnectionFactory):创建连接的工厂对象;
- 如JDBC技术的连接工厂使用DataSource抽象,Hibernate技术的连接使用SessionFactory抽象;