java
@Test public void testJDBC(){ String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; //1.加载驱动程序 Class.forName("com.mysql.jdbc.Driver"); //2.获取链接 Connection conn = DriverManager.getConnection(url, username, password); Statement stmt = conn.createStatement(); //3.执行SQL,获取结果 ResultSet rs = stmt.executeQuery("select * from user"); while(rs.next()){ System.out.println("username="+rs.getStriing("username")+" age="+rs.getInt("age")); } //关闭资源 rs.close(); stmt.close(); conn.close(); }
execute有不少重载方法,看void execute(final String sql)方法mysql
//执行SQL语句 @Override public void execute(final String sql) throws DataAccessException { if (logger.isDebugEnabled()) { logger.debug("Executing SQL statement [" + sql + "]"); } //回调类 class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider { @Override public Object doInStatement(Statement stmt) throws SQLException { stmt.execute(sql); return null; } @Override public String getSql() { return sql; } } execute(new ExecuteStatementCallback()); }
//静态处理SQL @Override 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; if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) { conToUse = this.nativeJdbcExtractor.getNativeConnection(con); } //建立Statement stmt = conToUse.createStatement(); applyStatementSettings(stmt); Statement stmtToUse = stmt; if (this.nativeJdbcExtractor != null) { stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt); } //回调函数 T result = action.doInStatement(stmtToUse); handleWarnings(stmt); return result; } catch (SQLException ex) { //释放数据库链接,同时抛出一个Spring转换过的Spring数据库异常 // Release Connection early, to avoid potential connection pool deadlock // in the case when the exception translator hasn't been initialized yet. JdbcUtils.closeStatement(stmt); stmt = null; DataSourceUtils.releaseConnection(con, getDataSource()); con = null; throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex); } finally { //释放链接 JdbcUtils.closeStatement(stmt); DataSourceUtils.releaseConnection(con, getDataSource()); } }
execute的流程图以下:spring
sql
@Override public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException { query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch)); } @Override public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException { //建立Statement return query(new SimplePreparedStatementCreator(sql), pss, rse); } 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"); return execute(psc, new PreparedStatementCallback<T>() { @Override public T doInPreparedStatement(PreparedStatement ps) throws SQLException { ResultSet rs = null; try { if (pss != null) { pss.setValues(ps); } //执行查询SQL 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(); } } } }); }
主要来看一下RowCallbackHandlerResultSetExtractor类数据库
private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> { private final RowCallbackHandler rch; public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) { this.rch = rch; } @Override public Object extractData(ResultSet rs) throws SQLException { //循环获取每一行数据 while (rs.next()) { this.rch.processRow(rs); } return null; } }
经过processRow获取每行中的每一列的数据安全
@Override public final void processRow(ResultSet rs) throws SQLException { if (this.rowCount == 0) { ResultSetMetaData rsmd = rs.getMetaData(); this.columnCount = rsmd.getColumnCount(); this.columnTypes = new int[this.columnCount]; this.columnNames = new String[this.columnCount]; for (int i = 0; i < this.columnCount; i++) { this.columnTypes[i] = rsmd.getColumnType(i + 1); this.columnNames[i] = JdbcUtils.lookupColumnName(rsmd, i + 1); } // could also get column names } //由子类来实现 processRow(rs, this.rowCount++); }
流程图以下:app
ide
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { try { return doGetConnection(dataSource); } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex); } }
doGetConnection方法函数
public static Connection doGetConnection(DataSource dataSource) throws SQLException { Assert.notNull(dataSource, "No DataSource specified"); /*把数据库的Connection放到事务管理中进行管理,这里采用是TransactionSynchronizationManager 中的ThreadLocal变量和线程绑定数据库链接 */ 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. //若是从holder中没有获取链接,那就从数据源中获取链接 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; }
继续来看一下TransactionSynchronizationManager是如何返回ConnectionHolder,最终的方法是在源码分析
private static Object doGetResource(Object actualKey) { Map<Object, Object> map = (Map)resources.get(); if(map == null) { return null; } else { Object value = map.get(actualKey); if(value instanceof ResourceHolder && ((ResourceHolder)value).isVoid()) { map.remove(actualKey); if(map.isEmpty()) { resources.remove(); } value = null; } return value; } }
是从resource中获取一个Map,这个Map中的key就是dataSource,value为ConnectionHolder,而Connection就是包装在里面,resource又是什么类型的?
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");
最后问dataSource(数据源)又是从哪里来的?dataSource做为JdbcTemplate的基类JdbcAccessor的属性是经过Ioc容器注入,能够看一下项目数据源都须要在spring.xml或配置类中进行配置,由spring容器来管理。对于dataSource也能够使用链接池,这里就须要采用第三方dbcp或者c3p0来完成,而后又容器将dataSource交给JdbcTemplate使用。