package jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
public class JDBCTest {
public static void main(String[] args) {
//加载spring
ClassPathResource resource = new ClassPathResource(
"applicationContext-common2.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader bdf = new XmlBeanDefinitionReader(factory);
bdf.loadBeanDefinitions(resource);
//获得jdbctemplate
JdbcTemplate jt = (JdbcTemplate) factory.getBean("jdbcTemplate");
String sql = "select * from dream where personid=?";
final List
我们能追踪到JDBCTemplate的query方法,如下:
//JDBCTemplate.java
public void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException {
query(sql, newArgPreparedStatementSetter(args), rch);
}
关于statement与preparedstatement的区别,我默认大家都明白。
public interface PreparedStatementSetter {
/**
* Set parameter values on the given PreparedStatement.
* @param ps the PreparedStatement to invoke setter methods on
* @throws SQLException if a SQLException is encountered
* (i.e. there is no need to catch SQLException)
*/
void setValues(PreparedStatement ps) throws SQLException;
}
/**
* Adapter to enable use of a RowCallbackHandler inside a ResultSetExtractor.
* Uses a regular ResultSet, so we have to be careful when using it:
* We don't use it for navigating since this could lead to unpredictable consequences.
*/
private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor
public T query(String sql, PreparedStatementSetter pss, ResultSetExtractor rse) throws DataAccessException {
return query(new SimplePreparedStatementCreator(sql), pss, rse);
}
SimplePreparedStatementCreator又是什么鬼?
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;
}
现在明白了吧,SimplePreparedStatementCreator就是生成PreparedStatement的呗
public T query(
PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)
throws DataAccessException {
Assert.notNull(rse, "ResultSetExtractor must not be null");
logger.debug("Executing prepared SQL query");
//注意匿名类
//execute一共两个参数 一个是PreparedStatementCreator 一个是PreparedStatementCallback
//***************3
return execute(psc, new PreparedStatementCallback() {
public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
ResultSet rs = null;
try {
if (pss != null) {
pss.setValues(ps);
}
rs = ps.executeQuery(); //最最核心的一步 调用jdk的接口
ResultSet rsToUse = rs;
if (nativeJdbcExtractor != null) {
rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
}
return rse.extractData(rsToUse);
}
finally {
JdbcUtils.closeResultSet(rs);
if (pss instanceof ParameterDisposer) {
((ParameterDisposer) pss).cleanupParameters();
}
}
}
});
}
下面看execute呗:
public T execute(PreparedStatementCreator psc, PreparedStatementCallback action)
throws DataAccessException {
//检测参数不为null
Connection con = DataSourceUtils.getConnection(getDataSource());
PreparedStatement ps = null;
try {
Connection conToUse = con;
//说实话 下面的代码 我也不知道是干什么的
//不过我在测试的时候
//nativeJdbcExtractor为null
//我们暂且不管这块
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
//*******1 获得PreparedStatement
ps = psc.createPreparedStatement(conToUse);
//这里是给PreparedStatement设置一些参数 基本不怎么用 不用深究
applyStatementSettings(ps);
PreparedStatement psToUse = ps;
//跟上面的conToUse一样 暂且不管
if (this.nativeJdbcExtractor != null) {
psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);
}
//************2 回调方法 我们得回到代码3处
T result = action.doInPreparedStatement(psToUse);
handleWarnings(ps);
return result;
}
catch (SQLException ex) {
//
}
finally {
//
}
}
那代码1处具体是怎么获得PreparedStatement的呢?
/**
* Simple adapter for PreparedStatementCreator, allowing to use a plain SQL statement.
*/
private static class SimplePreparedStatementCreator implements PreparedStatementCreator, SqlProvider {
private final String sql;
public SimplePreparedStatementCreator(String sql) {
Assert.notNull(sql, "SQL must not be null");
this.sql = sql;
}
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
return con.prepareStatement(this.sql);
}
public String getSql() {
return this.sql;
}
}
new PreparedStatementCallback() {
public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
ResultSet rs = null;
try {
if (pss != null) {
pss.setValues(ps); //给PreparedStatement 插入值
}
rs = ps.executeQuery(); //进行最和谐的查询
ResultSet rsToUse = rs;
if (nativeJdbcExtractor != null) {
rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
}
return rse.extractData(rsToUse); //数据的最后整理
}
finally {
JdbcUtils.closeResultSet(rs);
if (pss instanceof ParameterDisposer) {
((ParameterDisposer) pss).cleanupParameters();
}
}
}
}
String sql = "select * from dream where personid=?";
final List> list = new ArrayList>(); // 一定要用final定义
Object[] params = new Object[] { 1 };
jt.query(sql, params, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
Map u = new HashMap();
u.put("id", rs.getString("id"));
u.put("description", rs.getString("description"));
list.add(u);
}
});
类似上面的调用方式,在Spring的JDBCTemplate中处理过程是这样的
sql = "select description from dream where personid=?";
String description= jt.queryForObject(sql, new Object[] { 8 },String.class);
System.out.println(description);
上面的查询方式,只能查询出表中的
一条记录的一个字段
public List extractData(ResultSet rs) throws SQLException {
List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList());
int rowNum = 0;
while (rs.next()) {
results.add(this.rowMapper.mapRow(rs, rowNum++));
}
return results;
}
另外 我得说明一下
public T queryForObject(String sql, RowMapper rowMapper) throws DataAccessException {
List results = query(sql, rowMapper);
return DataAccessUtils.requiredSingleResult(results);
}
public T queryForObject(String sql, Class requiredType) throws DataAccessException {
return queryForObject(sql, getSingleColumnRowMapper(requiredType));
}
至于别的queryForList,跳到第一个queryForObject里。queryForObject(String sql, RowMapper