首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

spring中jdbcTemplate归结2

2012-08-28 
spring中jdbcTemplate归纳2用语句创建器更新数据库第一个回调接口是PerparedStatementCreator,实现这个接

spring中jdbcTemplate归纳2


用语句创建器更新数据库
第一个回调接口是PerparedStatementCreator,实现这个接口来覆盖整个更新过程的语句创建任务。我们先看下源代码中的PerparedStatementCreator接口,然后实现我们自己的接

口。

?

public interface PreparedStatementCreator {/**  * Create a statement in this connection. Allows implementations to use * PreparedStatements. The JdbcTemplate will close the created statement. * @param con Connection to use to create statement * @return a prepared statement * @throws SQLException there is no need to catch SQLExceptions * that may be thrown in the implementation of this method. * The JdbcTemplate class will handle them. */PreparedStatement createPreparedStatement(Connection con) throws SQLException;}

?

源代码中只定义了一个方法createPreparedStatement,在connection连接的基础上创建statement,使我们可以使用PreparedStatements实例,创建完,jdbcTemplate会自动关闭

Connection连接,下面我们实现这个接口。

public class InsertPreparedStatementCreator implements PreparedStatementCreator{private User user;public InsertPreparedStatementCreator(User user){this.user = user;}public PreparedStatement createPreparedStatement(Connection conn)throws Exception{String sql = "insert into user value(?,?);PreparedStatement ps  = conn.prepareStatement(sql);ps.setString(user.getUsername());ps.setString(user.getPassword());return ps;}}

?

我们实现后,只需要创建PreparedStatement ,并且把参数绑定上去,然后返回,在处理过程中不需要进行异常处理,因为方法签名中已经给我们抛出了异常,也不用关闭数据库

连接或者打开数据库连接,这些spring都给我们做好了,然后调用jdbcTemplate中的update方法即可。
jdbcTemplate.update(new InsertPreparedStatementCreator(user));
当然也可以用另一种方式。

?

jdbcTemplate.update(new PreparedStatementCreator(){String sql = "insert into user value(?,?);PreparedStatement ps  = conn.prepareStatement(sql);ps.setString(user.getUsername());ps.setString(user.getPassword());return ps;});

?

这里其实是个回调函数,在设计模式中是模板方法模式。
模板方法使用继承机制实现。在父类中定义不变的,然后把变化的定义成一个抽象方法,供子类实现。因此模板方法的 父类一般也是一个抽象类。
在jdbcTemplate中的执行:
我们的update方法调用了jdbcTemplate方法中的

?

public int update(PreparedStatementCreator psc) throws DataAccessException {return update(psc, (PreparedStatementSetter) null);}

?

接着调用

protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss)throws DataAccessException {if (logger.isDebugEnabled()) {String sql = getSql(psc);logger.debug("Executing SQL update" + (sql != null ? " [" + sql  + "]" : ""));}Integer result = (Integer) execute(psc, new PreparedStatementCallback() {public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {try {if (pss != null) {pss.setValues(ps);}int rows = ps.executeUpdate();if (logger.isDebugEnabled()) {logger.debug("SQL update affected " + rows + " rows");}return new Integer(rows);}finally {if (pss instanceof ParameterDisposer) {((ParameterDisposer) pss).cleanupParameters();}}}});return result.intValue();}

?

?

方法的关键:
int rows = ps.executeUpdate();
return new Integer(rows);
执行了preparedStatement.executeUpdate().然后返回执行后的值,和我们自己写是一样。在这里还是没有看到spring是如何打开数据库连接的。继续看,注意到一个方法的调用

Integer result = (Integer) execute(psc, new PreparedStatementCallback() 。。。。。。
我们找到这个方法

?

public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)throws DataAccessException {Assert.notNull(psc, "PreparedStatementCreator must not be null");Assert.notNull(action, "Callback object must not be null");Connection con = DataSourceUtils.getConnection(getDataSource());PreparedStatement ps = null;try {Connection conToUse = con;if (this.nativeJdbcExtractor != null &&this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {conToUse = this.nativeJdbcExtractor.getNativeConnection(con);}ps = psc.createPreparedStatement(conToUse);applyStatementSettings(ps);PreparedStatement psToUse = ps;if (this.nativeJdbcExtractor != null) {psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);}Object result = action.doInPreparedStatement(psToUse);SQLWarning warning = ps.getWarnings();throwExceptionOnWarningIfNotIgnoringWarnings(warning);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.if (psc instanceof ParameterDisposer) {((ParameterDisposer) psc).cleanupParameters();}String sql = getSql(psc);psc = null;JdbcUtils.closeStatement(ps);ps = null;DataSourceUtils.releaseConnection(con, getDataSource());con = null;throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);}finally {if (psc instanceof ParameterDisposer) {((ParameterDisposer) psc).cleanupParameters();}JdbcUtils.closeStatement(ps);DataSourceUtils.releaseConnection(con, getDataSource());}}

?

?

里面有这么一句Connection con = DataSourceUtils.getConnection(getDataSource());
这里获取数据库数据库连接。我们看看他是怎么获取的数据库连接。
进入DataSourceUtils这个类中

?

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");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;}

?

?

spring会先去ConnectionHolder 中获取Connection,如果有直接从ConnectionHolder 获取conennction. conHolder.getConnection();如果没有则conHolder.setConnection

(dataSource.getConnection());,然后继续conennction. conHolder.getConnection(),说白了Connection是从ConnectionHolder 中获取的。
我们继续往深处看看,ConnectionHolder 是怎么把Connection给我们的。我们进入ConnectionHolder这个类中
public class ConnectionHolder extends ResourceHolderSupport,ConnectionHolder继承自抽象类 ResourceHolderSupport,我们暂时先不讨论这个类,主要看

ConnectionHolder.

?

public Connection getConnection() {Assert.notNull(this.connectionHandle, "Active Connection is required");if (this.currentConnection == null) {this.currentConnection = this.connectionHandle.getConnection();}return this.currentConnection;}

?

?

原来ConnectionHolder也不是现实取得Connection真正的类,它是从connectionHandle中获取的,
我们在进入ConnectionHandle这个处理类中,

public interface ConnectionHandle {/** * Fetch the JDBC Connection that this handle refers to. */Connection getConnection();/** * Release the JDBC Connection that this handle refers to. * @param con the JDBC Connection to release */void releaseConnection(Connection con);}

?

发现什么也没有,只是一个接口,定义了一个标准。既然是一个接口,就一定有实现类,我们继续往下找。
public class SimpleConnectionHandle implements ConnectionHandle 仅有一个实现类,还是一个simple的,晕吧,spring文档竟然说是一个简单的实现。那复杂的实现在哪呢

?找了半天就找到这个一个简单的实现,有点郁闷。看看在说。

public class SimpleConnectionHandle implements ConnectionHandle {private final Connection connection;/** * Create a new SimpleConnectionHandle for the given Connection. * @param connection the JDBC Connection */public SimpleConnectionHandle(Connection connection) {Assert.notNull(connection, "Connection must not be null");this.connection = connection;}/** * Return the specified Connection as-is. */public Connection getConnection() {return connection;}/** * This implementation is empty, as we're using a standard * Connection handle that does not have to be released. */public void releaseConnection(Connection con) {}public String toString() {return "SimpleConnectionHandle: " + this.connection;}}

?

?

这里也没有我们想要的connection连接,只是一个保存connnection的地方,我们要的是DriverManager.getConnection()的地方,在哪呢?继续找吧!返回到抽象类

DataSourceUtils中,继续看。Connection con = dataSource.getConnection();看到了吧,其实spring也没有提供如何获取,是在sun的包中实现了DriverManager.getConnection
spring给我们提供了多种获取connnection的途径,还有

ConnectionHolder holderToUse = conHolder;   if (holderToUse == null) {    holderToUse = new ConnectionHolder(con);   }   public ConnectionHolder(Connection connection) {    this.connectionHandle = new SimpleConnectionHandle(connection);   }

?

?

???在我们第一次连接后,以后就吧connnection保存了,下次用的时候就直接存spring中拿就OK了。返回到我们的jdbcTemplate继续看我们刚才的代码,注意如下代码。
??

 Connection conToUse = con;   if (this.nativeJdbcExtractor != null &&     this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {    conToUse = this.nativeJdbcExtractor.getNativeConnection(con);   }   ps = psc.createPreparedStatement(conToUse);

?

?

?psc.createPreparedStatement(conToUse);使用的是conToUse的Connection,而这个Connection是通过this.nativeJdbcExtractor.getNativeConnection获取的,我们看

看.nativeJdbcExtractor这个东东。

?

public interface NativeJdbcExtractor {boolean isNativeConnectionNecessaryForNativeStatements();boolean isNativeConnectionNecessaryForNativePreparedStatements();boolean isNativeConnectionNecessaryForNativeCallableStatements();Connection getNativeConnection(Connection con) throws SQLException;Connection getNativeConnectionFromStatement(Statement stmt) throws SQLException;Statement getNativeStatement(Statement stmt) throws SQLException;PreparedStatement getNativePreparedStatement(PreparedStatement ps) throws SQLException;CallableStatement getNativeCallableStatement(CallableStatement cs) throws SQLException;ResultSet getNativeResultSet(ResultSet rs) throws SQLException;}

?

?

NativeJdbcExtractor 是一个接口。有getNativeConnection获取Connection的方法。我们继续看看NativeJdbcExtractor 接口的实现类。就恍然大悟了。
C3P0NativeJdbcExtractor, CommonsDbcpNativeJdbcExtractor, JBossNativeJdbcExtractor, NativeJdbcExtractorAdapter, SimpleNativeJdbcExtractor,

WebLogicNativeJdbcExtractor, WebSphereNativeJdbcExtractor, XAPoolNativeJdbcExtractor有这么多类实现了NativeJdbcExtractor 这个接口,名名字不难看出胡,有通过

jboss获取的,有本地jdbc(NativeJdbcExtractorAdapter)获取的,有weblogic获取的,有websphere获取的,基本上我们常见的服务器都支持。在这里。
我们看一个实现类NativeJdbcExtractorAdapter,

public Connection getNativeConnection(Connection con) throws SQLException {if (con == null) {return null;}Connection targetCon = DataSourceUtils.getTargetConnection(con);Connection nativeCon = doGetNativeConnection(targetCon);if (nativeCon == targetCon) {// We haven't received a different Connection, so we'll assume that there's// some additional proxying going on. Let's check whether we get something// different back from the DatabaseMetaData.getConnection() call.DatabaseMetaData metaData = targetCon.getMetaData();// The following check is only really there for mock Connections// which might not carry a DatabaseMetaData instance.if (metaData != null) {Connection metaCon = metaData.getConnection();if (metaCon != targetCon) {// We've received a different Connection there:// Let's retry the native extraction process with it.nativeCon = doGetNativeConnection(metaCon);}}}return nativeCon;}

?

?

通过这里DatabaseMetaData metaData = targetCon.getMetaData();获取connection,就看到这里,关于更详细的介绍且听下回分解。


2010年9月7日22:02:47

热点排行