`
韩悠悠
  • 浏览: 839979 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

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

分享到:
评论
1 楼 wenchang520 2011-02-23  

相关推荐

    spring-jdbcTemplate实例工程

    在这个实例工程中,我们将深入探讨Spring JdbcTemplate的基本使用、优势以及常见操作。 一、Spring JdbcTemplate简介 Spring JdbcTemplate的出现是为了弥补原生JDBC在编码上的繁琐,它通过模板方法模式,将SQL执行...

    使用Spring的JdbcTemplate调用Oracle的存储过程

    使用Spring的JdbcTemplate调用Oracle的存储过程

    使用Spring的JdbcTemplate实现分页功能

    使用Spring的JdbcTemplate实现分页功能

    spring的jdbcTemplate小案例

    2. **创建JdbcTemplate Bean**:接下来,我们需要创建一个JdbcTemplate的实例,并将其注入到我们的应用中。这通常在Spring配置文件中完成,通过`@Bean`注解创建一个JdbcTemplate实例,并将DataSource注入其中。 ```...

    Spring 学习 JdbcTemplate,模板模式,回调

    在Spring中,JdbcTemplate就是一个典型的模板类,它实现了数据库操作的基本流程,如创建Connection、PreparedStatement、处理结果集等。用户可以通过扩展或自定义模板方法来实现特定的数据库操作逻辑。 **3. 回调...

    SpringJdbcTemplate封装工具类

    SpringJdbcTemplate是Spring框架中用于简化Java数据库访问的工具,它是Spring JDBC模块的核心。这个封装工具类的出现是为了提供一种更简洁、易于使用的接口来执行SQL操作,减轻开发者处理数据库连接、事务管理以及...

    strut2+spring+springjdbctemplate做的简易登录系统

    Struts2、Spring和Spring JDBC Template是Java Web开发中常用的三个框架,它们分别负责不同的职责。Struts2作为MVC(Model-View-Controller)框架,主要处理前端请求和业务逻辑;Spring则是一个全面的后端框架,提供...

    4.Spring中的JdbcTemplate,Spring中的的事务,

    ### Spring中的JdbcTemplate #### JdbcTemplate概述 JdbcTemplate是Spring框架提供的一种用于简化JDBC编程的对象。通过封装原生的JDBC API,JdbcTemplate不仅提高了代码的可读性和可维护性,还帮助开发者避免了...

    利用spring的jdbcTemplate处理blob、clob

    spring 中对大数据的处理,包括clob,blob的数据。比之jdbc下简便很多。

    struts+spring +jdbctemplate demo

    Struts、Spring 和 JDBCTemplate 是三个在 Java Web 开发中常用的框架和技术,它们结合使用可以构建出高效且灵活的企业级应用程序。在这个“Struts+Spring+JdbcTemplate Demo”中,我们将探讨这三个组件如何协同工作...

    基于注解的Spring JdbcTemplate

    在Spring配置文件中,我们需要定义一个`JdbcTemplate` bean,如下所示: ```xml <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> ``` 其中,`dataSource`是指向数据库连接池的...

    Spring-JdbcTemplate

    `Spring-JdbcTemplate` 是 Spring 框架中的一个核心模块,主要用于简化数据库操作,提供了强大的数据访问功能。它通过模板方法设计模式封装了 SQL 的执行,使得开发者无需直接与 JDBC API 打交道,从而降低了数据库...

    Spring JdbcTemplate 常用方法整理

    Spring的JdbcTemplate是Spring框架中用于简化数据库操作的工具类,它是基于JDBC但又抽象出了一层,避免了直接与数据库驱动API交互,从而提高了代码的可读性和可维护性。本文将深入探讨Spring JdbcTemplate的常用方法...

    配制Spring事务和JdbcTemplate使用

    配制Spring事务和JdbcTemplate使用 配制Spring事务和JdbcTemplate使用

    一个简单的spring-jdbctemplate扩展

    Spring的JdbcTemplate是Spring框架中的一个核心组件,用于简化数据库操作。它提供了一种模板方法模式,抽象出常见的JDBC代码,使得开发者可以避免编写大量的重复性代码,从而更加专注于业务逻辑。本项目是对Spring ...

    spring jdbctemplate实例

    Spring的JdbcTemplate是Spring框架中的一个核心组件,用于简化数据库操作。它提供了一种模板方法模式,抽象出了一些常见的数据库访问任务,使得开发者无需关注低级的JDBC细节,如打开和关闭连接、处理结果集等,从而...

    Spring框架JdbcTemplate类中查询方法介绍

    Spring 框架 JdbcTemplate 类中查询方法介绍 JdbcTemplate 是 Spring 框架中 org.springframework.jdbc.core 包提供的 JDBC 模板类,它是核心类,其他模板类都是基于它封装完成的。JdbcTemplate 类主要提供四类方法...

    使用Spring的JdbcTemplate和BeanPropertyRowMapper完成的JDBC

    使用Spring的JdbcTemplate和BeanPropertyRowMapper完成的JDBC我的实例 博文链接:https://zmx.iteye.com/blog/373454

    Spring Security 3.1 +Spring +Servlet+JdbcTemplate

    在提供的压缩包中,`securitydb_2.sql`很可能包含了预设的数据库结构和初始数据,这些数据可能是为了设置Spring Security的安全配置,如用户角色、权限等。这通常涉及创建用户表、角色表以及它们之间的关联。执行这...

Global site tag (gtag.js) - Google Analytics