SpringBoot项目使用jdbcTemplate访问数据库源代码分析
测试类:
public class DbTest {
private JdbcTemplate jdbcTemplate;
private DataSourceTransactionManager txManager;
private DefaultTransactionDefinition txDefinition;
private String insert_sql = "insert into account (balance) values ('100')";
public void save() {
// 1、初始化jdbcTemplate
DataSource dataSource = getDataSource();
jdbcTemplate = new JdbcTemplate(dataSource);
// 2、创建物管理器
txManager = new DataSourceTransactionManager();
txManager.setDataSource(dataSource);
// 3、定义事物属性
txDefinition = new DefaultTransactionDefinition();
txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 3、开启事物
TransactionStatus txStatus = txManager.getTransaction(txDefinition);
// 4、执行业务逻辑
try {
jdbcTemplate.execute(insert_sql);
//int i = 1/0;
jdbcTemplate.execute(insert_sql);
txManager.commit(txStatus);
} catch (DataAccessException e) {
txManager.rollback(txStatus);
e.printStackTrace();
}
}
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3307/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("");
return dataSource;
}
}
这个封装很简单,运行也没问题,源代码到底何时何地建立与数据库server的连接的呢? 其实背后内部是一个庞大复杂的令人叹为观止的java工程。
单步跟踪记录:
txManager = new DataSourceTransactionManager();
TransactionStatus txStatus = txManager.getTransaction(txDefinition);
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
Connection newCon = this.dataSource.getConnection();
createDataSource().getConnection(); // 创建一个对象就完事,对象里面有connection和getConnection()方法,下面的过程都是为了构造连接对象,最终返回一个连接对象(省略return)
createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,connectionPool,
validateConnectionFactory(connectionFactory);
conn = (Connection) connectionFactory.makeObject();
Connection conn = _connFactory.createConnection();
_driver.connect(_connectUri,_props);
Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(host(props), port(props), props, database(props), url);
(Connection) Util.handleNewInstance(JDBC_4_CONNECTION_CTOR, new Object[] { hostToConnectTo, Integer.valueOf(portToConnectTo), info, databaseToConnectTo, url }, null);
ctor.newInstance(args);
newInstanceWithCaller(initargs, !override, caller);
T inst = (T) ca.newInstance(args);
delegate.newInstance(args);
newInstance0(c, args); //执行jdbc connection类构造函数
public class JDBC4Connection extends ConnectionImpl implements JDBC4MySQLConnection {
public JDBC4Connection(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url) throws SQLException {
super(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url); //执行类构造函数
}
public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLConnection {
public ConnectionImpl(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url)
createNewIO(false);
connectOneTryOnly(isForReconnect, mergedProps);
coreConnect(mergedProps);
this.io = new MysqlIO(newHost, newPort, mergedProps, getSocketFactoryClassName(), getProxy(), getSocketTimeout(),this.largeRowSizeThreshold.getValueAsInt());//执行类构造函数
public class MysqlIO {
public MysqlIO(String host, int port, Properties props, String socketFactoryClassName, MySQLConnection conn, int socketTimeout,int useBufferRowSizeThreshold) throws IOException, SQLException {
this.mysqlConnection = this.socketFactory.connect(this.host, this.port, props);
this.rawSocket = createSocket(props);
this.rawSocket.connect(sockAddr, getRealTimeout(connectTimeout));
impl.connect(epoint, timeout); // impl-socket实现类java.net.SocksSocketImpl
delegate.connect(epoint, remainingMillis(deadlineMillis)); // delegate是系统默认的socket实现类sun.nio.ch.NioSocketImpl
int n = Net.connect(fd, address, port);
connect(UNSPEC, fd, remote, remotePort);
connect0(preferIPv6, fd, remote, remotePort); // 最底层代码来自java jdk,调用系统api,回过头来看所有其它的代码都只是处理流程封装,源代码到此为止
代码封装涉及到dataSource,driver,connection,pool,manager,holder,connection/socket实现类,代理类,工厂,等等概念,封装层次之多之恐怖和有些概念逻辑远远超出一般人的编程思维范围,
涉及到jdk,spring,mysql-connector,dbcp好几家几百个类文件代码配合协作,细想有点恐怖...,好比一个大楼的几万个部分是由好几家建筑公司分工合作完成的,每家公司完成几千个部分,但是没有总设计师没有总指挥,只有一些接口标准。
这个例子也证明了不管源代码设计有多复杂,单步跟踪可以看到每一步,可以看到它内部封装的把戏,有些细节流程已经是匪夷所思,通用软件的设计思维与编程技术与应用软件设计思维和编程技术不在一个档次上。