原文链接http://blog.youkuaiyun.com/chjttony/article/details/6404089
1.Spring中使用JdbcTemplate封装对Jdbc的支持,使用Spring JdbcTeamplate的例子如下:
(1). 假设如下SQL表中有数据username=test1,passwd=test1,address=test1 :
- CREATE TABLE `login` (
- `username` varchar(10) default NULL,
- `passwd` varchar(10) default NULL,
- `address` varchar(10) default NULL
- ) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
(2).在Spring配置文件中添加关于数据源和JdbcTeamplate的配置如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
- <beans>
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName">
- <value>com.mysql.jdbc.Driver</value>
- </property>
- <property name="url">
- <value>jdbc:mysql://localhost:3306/javaee</value>
- </property>
- <property name="username">
- <value>root</value>
- </property>
- <property name="password">
- <value>1234</value>
- </property>
- </bean>
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource">
- <ref local="dataSource"/>
- </property>
- </bean>
- <bean id="personDAO" class="SpringJDBCSupport.ReadData.PersonDAO">
- <property name="jdbcTemplate">
- <ref local="jdbcTemplate"/>
- </property>
- </bean>
- </beans>
(3).Java持久化对象如下:
- package SpringJDBCSupport.ReadData;
- import com.mysql.jdbc.Driver;
- public class Person {
- private String name;
- private String password;
- private String address;
- public Person(){
- }
- public Person(String name,String password,String address){
- this.name=name;
- this.password=password;
- this.address=address;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String toString(){
- return this.getName()+"-"+this.getPassword()+"-"+this.getAddress();
- }
- }
(4).使用JdbcTeamplate的DAO如下:
- package SpringJDBCSupport.ReadData;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Types;
- import java.util.List;
- import org.springframework.jdbc.core.BatchPreparedStatementSetter;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.core.RowCallbackHandler;
- public class PersonDAO {
- private JdbcTemplate jdbcTemplate;
- public JdbcTemplate getJdbcTemplate() {
- return jdbcTemplate;
- }
- public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
- public int insertPersonUseUpdate(Person person){
- String sql="insert into login values(?,?,?)";
- Object[] params=new Object[]{
- person.getName(),
- person.getPassword(),
- person.getAddress()
- };
- return this.getJdbcTemplate().update(sql,params);
- }
- public int insertPersonUseExecute(Person person){
- String sql="insert into login values(?,?,?)";
- Object[] params=new Object[]{
- person.getName(),
- person.getPassword(),
- person.getAddress()
- };
- int[] types=new int[]{
- Types.VARCHAR,
- Types.VARCHAR,
- Types.VARCHAR
- };
- return this.getJdbcTemplate().update(sql,params,types);
- }
- public int[] updatePersonUseBatchUpdate( final List persons){
- String sql="insert into login values(?,?,?)";
- BatchPreparedStatementSetter setter=null;
- //使用匿名内部类,实现BatchPreparedStatementSetter接口,实现批量更新
- setter=new BatchPreparedStatementSetter(){
- public int getBatchSize(){
- return persons.size();
- }
- public void setValues(PreparedStatement ps,int index) throws SQLException{
- Person person=(Person)persons.get(index);
- ps.setString(1,person.getName());
- ps.setString(2,person.getPassword());
- ps.setString(3,person.getAddress());
- }
- };
- return this.getJdbcTemplate().batchUpdate(sql,setter);
- }
- public Person getPersonByRowCallbackHandler(String username){
- String sql="select * from login where username=?";
- final Person person=new Person();
- final Object params[]=new Object[]{username};
- //使用匿名内部类,实现RowCallbackHandler接口,即实现查询结果集的RowMapping
- this.getJdbcTemplate().query(sql,params,new RowCallbackHandler(){
- public void processRow(ResultSet rs)throws SQLException{
- person.setName(rs.getString("username"));
- person.setPassword(rs.getString("passwd"));
- person.setAddress(rs.getString("address"));
- }
- });
- return person;
- }
- }
2.Spring JdbcTemplate的工作流程:
通过1中的小例子,我们可以总结出SpringJdbcTemplate的工作流程如下:
(1).配置数据源:
Spring中,将管理数据库连接的数据源当作普通Java Bean一样在Spring IoC容器中管理,当应用使用数据源时Spring IoC容器负责初始化数据源。
(2).将数据源注入JdbcTemplate:
JdbcTemplate中dataSource属性用于注入配置的数据源,Spring IoC容器通过依赖注入将配置的数据源注入到Spring对Jdbc操作的封装类JdbcTemplate中。
(3).应用中使用JdbcTemplate:
注入了数据源的JdbcTemplate就可以在应用中使用了,应用中对数据源的增删改查等操作都可以使用JdbcTemplate对外提供的方法操作数据库。
3.JdbcTemplate处理Statement的相关方法实现:
JdbcTemplate的execute方法是JdbcTemplate的核心方法,是JdbcTemplate调用jdbc进行查询,添加,删除和更新操作的基础方法,在execute方法中,主要实现对数据库的基本操作,如:获取数据库连接;根据应用对数据库的需要创建数据库的Statement;对数据库操作进行回调;处理数据库异常;关闭数据库连接等等。JdbcTemplate中有真的Jdbc中Statement、PreparedStatement和CallableStatement处理的execute方法,首先我们分析处理Statement的相关方法:
(1).处理Statement的execute方法:
- //execute方法执行的是输入的sql语句,且没有返回值的
- public void execute(final String sql) throws DataAccessException {
- if (logger.isDebugEnabled()) {
- logger.debug("Executing SQL statement [" + sql + "]");
- }
- //内部类,实现类StatementCallback和SqlProvider接口,执行sql语句的回调类
- class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
- //JdbcTemplate中真正执行输入的sql语句的地方
- public Object doInStatement(Statement stmt) throws SQLException {
- stmt.execute(sql);
- return null;
- }
- //获取输入的sql语句
- public String getSql() {
- return sql;
- }
- }
- //调用通用的处理静态sql语句的execute方法
- execute(new ExecuteStatementCallback());
- }
- //通用的处理静态sql语句
- public <T> T execute(StatementCallback<T> action) throws DataAccessException {
- Assert.notNull(action, "Callback object must not be null");
- //根据配置的数据源获取数据库连接
- Connection con = DataSourceUtils.getConnection(getDataSource());
- Statement stmt = null;
- try {
- Connection conToUse = con;
- //如果JdbcTemplate指定了本地连接,则将获取到的数据库连接转换为本地连接
- if (this.nativeJdbcExtractor != null &&
- this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
- conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
- }
- //创建Statement
- stmt = conToUse.createStatement();
- applyStatementSettings(stmt);
- Statement stmtToUse = stmt;
- //如果JdbcTemplate指定了本地连接,则将Statement转换为本地Statement
- if (this.nativeJdbcExtractor != null) {
- stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
- }
- //调用ExecuteStatementCallback类的doInStatement回调方法,执行sql语句
- T result = action.doInStatement(stmtToUse);
- handleWarnings(stmt);
- //返回执行结果
- return result;
- }
- catch (SQLException ex) {
- //产生异常,则关闭Statement
- JdbcUtils.closeStatement(stmt);
- stmt = null;
- //释放数据库连接
- DataSourceUtils.releaseConnection(con, getDataSource());
- con = null;
- //将数据库异常封装为Spring异常向调用者抛出
- throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
- }
- finally {
- //关闭Statement,释放数据库连接
- JdbcUtils.closeStatement(stmt);
- DataSourceUtils.releaseConnection(con, getDataSource());
- }
- }
Execute方法是JdbcTemplate执行jdbc操作的核心,其他的方法都是通过调用execute方法来操作数据库。
(2). Statement的查询方法:
JdbcTemplate处理Statement的查询方法有很多,但是其中最基本的方法源码如下:
- //静态sql的查询方法,第二个参数ResultSetExtractor是查询结果集转换器,用于处理查//询得到的结果集
- public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
- Assert.notNull(sql, "SQL must not be null");
- Assert.notNull(rse, "ResultSetExtractor must not be null");
- if (logger.isDebugEnabled()) {
- logger.debug("Executing SQL query [" + sql + "]");
- }
- //实现了StatementCallback和SqlProvider接口的内部类,用于execute方法回调
- class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
- //execute方法执行查询操作时回调方法,真正执行jdbc操作的方法
- public T doInStatement(Statement stmt) throws SQLException {
- ResultSet rs = null;
- try {
- //调用Statement的查询方法
- rs = stmt.executeQuery(sql);
- ResultSet rsToUse = rs;
- //如果JdbcTemplate指定了本地jdbc提取器,则将查询得到的结果
- //集提取为本地结果集
- if (nativeJdbcExtractor != null) {
- rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
- }
- //使用结果集提取器对查询得到的结果集进行处理
- return rse.extractData(rsToUse);
- }
- finally {
- //关闭结果集
- JdbcUtils.closeResultSet(rs);
- }
- }
- //获取sql
- public String getSql() {
- return sql;
- }
- }
- //调用处理Statement的execute方法
- return execute(new QueryStatementCallback());
- }
(3).Statement的更新方法:
- //静态sql的更新方法
- public int update(final String sql) throws DataAccessException {
- Assert.notNull(sql, "SQL must not be null");
- if (logger.isDebugEnabled()) {
- logger.debug("Executing SQL update [" + sql + "]");
- }
- //实现了StatementCallback和SqlProvider接口的内部类,Statement
- //的execute方法回调
- class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
- //Statement的execute方法更新操作时回调方法,真正执行jdbc操作的方法
- public Integer doInStatement(Statement stmt) throws SQLException {
- //Statement执行jdbc的更新操作,返回影响行数
- int rows = stmt.executeUpdate(sql);
- if (logger.isDebugEnabled()) {
- logger.debug("SQL update affected " + rows + " rows");
- }
- return rows;
- }
- public String getSql() {
- return sql;
- }
- }
- //调用Statement的execute方法
- return execute(new UpdateStatementCallback());
- }
通过对Statement相关处理的方法源码分析,我们可以看出execute方法是核心方法,在execute方法中,主要获取数据库连接和创建Statement,同时当执行完jdbc操作之后释放连接和资源等数据库操作的通用流程,所有的查询,更新等具体操作均是通过向execute方法传递合适的回调参数来使用execute方法中的数据库通用流程和资源,真正执行jdbc操作的方法由具体的回调内部类来实现。
4.JdbcTemplate处理PreparedStatement的相关方法实现:
(1).处理PreparedStatement的execute方法:
- //PreparedStatement处理sql语句的execute方法
- public <T> T execute(String sql, PreparedStatementCallback<T> action) throws DataAccessException {
- //将sql语句封装成为SimplePreparedStatementCreator,调用处理//PreparedStatement的方法
- return execute(new SimplePreparedStatementCreator(sql), action);
- }
- //处理PreparedStatement
- public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
- throws DataAccessException {
- Assert.notNull(psc, "PreparedStatementCreator must not be null");
- Assert.notNull(action, "Callback object must not be null");
- if (logger.isDebugEnabled()) {
- String sql = getSql(psc);
- logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
- }
- //获取数据库连接
- Connection con = DataSourceUtils.getConnection(getDataSource());
- PreparedStatement ps = null;
- try {
- Connection conToUse = con;
- //如果JdbcTemplate指定了jdbc本地提取器,则将获取到的数据库连接转换
- //为本地数据库连接
- if (this.nativeJdbcExtractor != null &&
- this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
- conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
- }
- //根据数据库连接和sql语句创建PreparedStatement
- ps = psc.createPreparedStatement(conToUse);
- applyStatementSettings(ps);
- PreparedStatement psToUse = ps;
- //如果JdbcTemplate指定了jdbc本地提取器,则将PreparedStatement转换
- //为本地PreparedStatement
- if (this.nativeJdbcExtractor != null) {
- psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
- }
- //调用回调处理器,执行相应操作
- T result = action.doInPreparedStatement(psToUse);
- handleWarnings(ps);
- return result;
- }
- catch (SQLException ex) {
- //关闭资源,释放连接
- if (psc instanceof ParameterDisposer) {
- ((ParameterDisposer) psc).cleanupParameters();
- }
- String sql = getSql(psc);
- psc = null;
- JdbcUtils.closeStatement(ps);
- ps = null;
- DataSourceUtils.releaseConnection(con, getDataSource());
- con = null;
- //将jdbc相关异常封装转换为Spring异常向调用者抛出
- throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);
- }
- finally {
- //清除PreparedStatement的参数
- if (psc instanceof ParameterDisposer) {
- ((ParameterDisposer) psc).cleanupParameters();
- }
- //关闭PreparedStatement
- JdbcUtils.closeStatement(ps);
- //释放数据库连接
- DataSourceUtils.releaseConnection(con, getDataSource());
- }
- }
(2). PreparedStatement的查询方法:
和Statement类似,JdbcTemplate中PreparedStatement的查询方法也非常多,我们以最基本的查询方法源码为例分析其处理流程:
- //PreparedStatement查询方法,第一个参数PreparedStatementCreator为封装sql语句的//类,第二个参数PreparedStatementSetter为向PreparedStatement设置参数的类,第三//个参数ResultSetExtractor为处理结果集的类
- public <T> T query(
- PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
- throws DataAccessException {
- Assert.notNull(rse, "ResultSetExtractor must not be null");
- logger.debug("Executing prepared SQL query");
- //调用PreparedStatement的execute方法,第二个参数为一个实现了//PreparedStatementCallback接口的匿名内部类,被execute回调
- return execute(psc, new PreparedStatementCallback<T>() {
- //执行jdbc操作的方法
- public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
- ResultSet rs = null;
- try {
- //如果PreparedStatement参数不为null,则为PreparedStatement设置参数值
- if (pss != null) {
- pss.setValues(ps);
- }
- //执行jdbc查询操作
- rs = ps.executeQuery();
- ResultSet rsToUse = rs;
- //如果JdbcTemplate指定了本地jdbc提取器,则将查询得到的结果
- //集转换为本地jdbc结果集
- if (nativeJdbcExtractor != null) {
- rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
- }
- //使用配置的结果集处理器提取结果集数据
- return rse.extractData(rsToUse);
- }
- finally {
- //关闭结果集
- JdbcUtils.closeResultSet(rs);
- //清除PreparedStatement参数
- if (pss instanceof ParameterDisposer) {
- ((ParameterDisposer) pss).cleanupParameters();
- }
- }
- }
- });
- }
(3). PreparedStatement的更新方法:
- // PreparedStatement更新方法,第二个参数PreparedStatementSetter为向//PreparedStatement设置参数的类
- protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss)
- throws DataAccessException {
- logger.debug("Executing prepared SQL update");
- //调用PreparedStatement的execute方法,第二个参数为实现了//PreparedStatementCallback接口的匿名内部类,由PreparedStatement的
- //execute方法回调
- return execute(psc, new PreparedStatementCallback<Integer>() {
- //真正执行jdbc操作的方法
- public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException {
- try {
- //为PreparedStatement设置参数值
- if (pss != null) {
- pss.setValues(ps);
- }
- //PreparedStatement调用jdbc的更新操作,返回受影响的行数
- int rows = ps.executeUpdate();
- if (logger.isDebugEnabled()) {
- logger.debug("SQL update affected " + rows + " rows");
- }
- return rows;
- }
- finally {
- //清除PreparedStatement参数
- if (pss instanceof ParameterDisposer) {
- ((ParameterDisposer) pss).cleanupParameters();
- }
- }
- }
- });
- }
通过对PreparedStatement相关处理方法的源码分析,我们可以看到PreparedStatement和Statement的处理流程基本是相同的,不同之处在于PreparedStatement需要处理设置参数值的操作。
5.JdbcTemplate处理CallableStatement的相关方法实现:
(1).处理CallableStatement的execute方法:
- //CallableStatement处理给定字符串的
- public <T> T execute(String callString, CallableStatementCallback<T> action) throws DataAccessException {
- //将字符串封装为SimpleCallableStatementCreator类,调用execute方法处//理CallableStatement
- return execute(new SimpleCallableStatementCreator(callString), action);
- }
- //CallableStatement的execute方法,第一个参数CallableStatementCreator是封装调用字//符串的类,封装调用数据库存储过程的语句
- public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action)
- throws DataAccessException {
- Assert.notNull(csc, "CallableStatementCreator must not be null");
- Assert.notNull(action, "Callback object must not be null");
- if (logger.isDebugEnabled()) {
- String sql = getSql(csc);
- logger.debug("Calling stored procedure" + (sql != null ? " [" + sql + "]" : ""));
- }
- //根据数据源获取数据库连接
- Connection con = DataSourceUtils.getConnection(getDataSource());
- CallableStatement cs = null;
- try {
- Connection conToUse = con;
- //如果JdbcTemplate指定了本地jdbc提取器,则将获取到的数据库连接转换为
- //本地数据库连接
- if (this.nativeJdbcExtractor != null) {
- conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
- }
- //根据数据库连接创建CallableStatement
- cs = csc.createCallableStatement(conToUse);
- applyStatementSettings(cs);
- CallableStatement csToUse = cs;
- //如果JdbcTemplate指定了本地jdbc提取器,则将CallableStatement转换为
- //本地CallableStatement
- if (this.nativeJdbcExtractor != null) {
- csToUse = this.nativeJdbcExtractor.getNativeCallableStatement(cs);
- }
- //调用相应回调对象的方法,执行jdbc操作
- T result = action.doInCallableStatement(csToUse);
- handleWarnings(cs);
- return result;
- }
- catch (SQLException ex) {
- //清除CallableStatement参数
- if (csc instanceof ParameterDisposer) {
- ((ParameterDisposer) csc).cleanupParameters();
- }
- String sql = getSql(csc);
- csc = null;
- //关闭CallableStatement
- JdbcUtils.closeStatement(cs);
- cs = null;
- //释放数据库连接
- DataSourceUtils.releaseConnection(con, getDataSource());
- con = null;
- //将jdbc异常封装为Spring异常
- throw getExceptionTranslator().translate("CallableStatementCallback", sql, ex);
- }
- finally {
- //清除CallableStatement参数
- if (csc instanceof ParameterDisposer) {
- ((ParameterDisposer) csc).cleanupParameters();
- }
- //关闭CallableStatement
- JdbcUtils.closeStatement(cs);
- //释放数据库连接
- DataSourceUtils.releaseConnection(con, getDataSource());
- }
- }
(2).CallableStatement的call方法:
- //CallableStatement调用数据库的存储过程
- public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)
- throws DataAccessException {
- final List<SqlParameter> updateCountParameters = new ArrayList<SqlParameter>();
- final List<SqlParameter> resultSetParameters = new ArrayList<SqlParameter>();
- final List<SqlParameter> callParameters = new ArrayList<SqlParameter>();
- //遍历声明的参数
- for (SqlParameter parameter : declaredParameters) {
- //如果参数是结果参数
- if (parameter.isResultsParameter()) {
- //如果参数是返回结果集类型,则将参数添加到结果集参数集合中
- if (parameter instanceof SqlReturnResultSet) {
- resultSetParameters.add(parameter);
- }
- //如果参数不是返回结果集类型,则将参数添加到更新数目参数集合中
- else {
- updateCountParameters.add(parameter);
- }
- }
- //如果参数不是结果参数,则将参数添加到调用参数集合中
- else {
- callParameters.add(parameter);
- }
- }
- //调用CallableStatement的execute方法,第二个参数是实现了//CallableStatementCallback接口的匿名内部类,用于回调
- return execute(csc, new CallableStatementCallback<Map<String, Object>>() {
- //真正调用jdbc操作的方法
- public Map<String, Object> doInCallableStatement(CallableStatement cs) throws SQLException {
- //CallableStatement执行jdbc调用,如果是返回结果为结果集则为//ture,如果执行返回结果不是结果集则返回false
- boolean retVal = cs.execute();
- //获取CallableStatement执行后数据库中被更新的记录数
- int updateCount = cs.getUpdateCount();
- if (logger.isDebugEnabled()) {
- logger.debug("CallableStatement.execute() returned '" + retVal + "'");
- logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
- }
- //创建一个用于返回指向结果的集合
- Map<String, Object> returnedResults = createResultsMap();
- //如果CallableStatement执行的返回结果结果是结果集,或者
- //CallableStatement执行的更新操作,数据库中有记录被更新
- if (retVal || updateCount != -1) {
- //将存储过程调用结果提取成结果集集合
- returnedResults.putAll(extractReturnedResults(cs, updateCountParameters, resultSetParameters, updateCount));
- }
- //如果CallableStatement执行的返回结果不是结果集,且不是更新操作,
- //则将存储过程的输出参数提取为结果集
- returnedResults.putAll(extractOutputParameters(cs, callParameters));
- return returnedResults;
- }
- });
- }
通过上面对CallableStatement相关处理方法的源码分析我们可以看到,execute方法基本和Statement和PreparedStatement是相同的,不同之处在于CallableStatement是通过jdbc调用数据库的存储过程,对于输入输出参数的组装,以及返回结果的处理方面有些特殊处理。
6.JdbcTemplate通过DataSourceUtils获取数据库连接:
JdbcTemplate的execute方法中通过DataSourceUtils.getConnection(getDataSource());获取数据库连接,下面我们就分析DataSourceUtils类获取数据库连接的实现过程:
- //获取数据库连接的入口方法
- public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
- try {
- //通过doGetConnection方法来获取数据库连接
- 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");
- //把数据库连接放到事务管理器中管理
- //通过TransactionSynchronizationManager中定义的线程局部
- //变量(threadlocal)来和线程绑定数据库连接
- ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
- //如果TransactionSynchronizationManager中已有与当前线程绑定的数据库连接
- if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
- //从当前线程线程局部变量中获取数据库连接
- conHolder.requested();
- //如果当前线程局部变量中没有绑定数据库连接,则为当前线程局部变量设置数据库连接
- if (!conHolder.hasConnection()) {
- logger.debug("Fetching resumed JDBC Connection from DataSource");
- conHolder.setConnection(dataSource.getConnection());
- }
- //直接返回TransactionSynchronizationManager线程局部变量中的数据库连接
- return conHolder.getConnection();
- }
- //如果TransactionSynchronizationManager中没有和当前线程绑定的数据
- //库连接,则从Spring配置文件配置的数据源对象中获取数据库连接
- logger.debug("Fetching JDBC Connection from DataSource");
- Connection con = dataSource.getConnection();
- //如果当前线程事务同步是Active的,即在注册之前可以直接使用,避免不必要
- //的实例对象创建
- if (TransactionSynchronizationManager.isSynchronizationActive()) {
- logger.debug("Registering transaction synchronization for JDBC Connection");
- //在事务中使用同一个数据库连接做jdbc操作,当事务结束后,线程绑定对象
- //将被同步移除
- ConnectionHolder holderToUse = conHolder;
- //如果存放数据库连接的线程局部变量为null,则重新创建一个线程局部变量
- if (holderToUse == null) {
- holderToUse = new ConnectionHolder(con);
- }
- //如果存放数据库连接的线程局部变量不为null,则将数据库连接存放到线程
- //局部变量中
- else {
- holderToUse.setConnection(con);
- }
- //请求数据库连接
- holderToUse.requested();
- //为当前线程注册事务同步
- TransactionSynchronizationManager.registerSynchronization(
- new ConnectionSynchronization(holderToUse, dataSource));
- //标记当前数据库连接为事务同步
- holderToUse.setSynchronizedWithTransaction(true);
- if (holderToUse != conHolder) {
- //将数据源绑定到当前线程局部变量
- TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
- }
- }
- return con;
- }
通过对JdbcTemplate的源码分析,我们看到Spring只是将jdbc的一些常用操作封装,将通用的获取数据库连接、创建创建Statement、关闭资源释放连接等操作封装在不同种类的execute方法中,同时调用不同的回调处理Action来具体执行jdbc操作,对jdbc熟悉的人很容易看懂这部分源码,当然Spring还对jdbc进行了一些高级的封装和扩展,例如RowMapper将结果集转换为指定对象等,这部分有兴趣可以自己研究