一、前言
小demo只是思想的一个简单实现,距离用在生产环境还有一定距离,只是五一劳动节放假宅在家用来锻炼一下思维,不严谨的地方还望见谅。想要看更完整的示例代码,请查看mybatis源码,pooled类的实现。
二、难点分析
JDBC数据源的规范来自java.sql.DataSource接口,里面就一个方法getConnection的两个重载(数据源的思想也已经很普遍了,这里就不再赘述,需要了解的请自行查找),所以数据源的首要任务就是提供数据库连接对象Connection,这个太容易实现了,毫无难点可言,但是获得了连接,使用完之后是需要关闭的,此时连接的关闭不是释放资源,而是将连接对象还回数据库连接池。
难点一:连接对象的关闭不是释放资源,而是将连接对象还回数据库连接池——close方法的改写
上面的描述太过随意浮躁,没有体现难点之所在。java.sql.Connection作为数据库连接的规范接口而存在,他规定了连接对象的两大功能,一是和数据库建立链接,而是为此链接创建执行对象,不同的数据库厂商实现有不同,但是规范都得遵守,无论是mysql还是Oracle,他们提供的数据库驱动包中对java.sql.Connection的实现都要按照规则来,否则程序员们就不乐意了,不好进行开发、不好进行维护啊。那就看一下规范,java.sql.Connection接口中对close方法的描述。
/**
* Releases this <code>Connection</code> object's database and JDBC resources
* immediately instead of waiting for them to be automatically released.
* <P>
* Calling the method <code>close</code> on a <code>Connection</code>
* object that is already closed is a no-op.
* <P>
* It is <b>strongly recommended</b> that an application explicitly
* commits or rolls back an active transaction prior to calling the
* <code>close</code> method. If the <code>close</code> method is called
* and there is an active transaction, the results are implementation-defined.
* <P>
*
* @exception SQLException SQLException if a database access error occurs
*/
void close() throws SQLException;
是不是粗大事了?不是等待啊,是立即释放链接对象和JDBC资源,很强烈的语气助词“immediately”和“strongly”。释放资源,也就是关闭和数据库的链接,不要Connection对象了,口说无凭,直接看mysql驱动包中close方法的实现。
附送更详细的小文链接一枚:点击打开链接
/**
* In some cases, it is desirable to immediately release a Connection's
* database and JDBC resources instead of waiting for them to be
* automatically released (cant think why off the top of my head) <B>Note:</B>
* A Connection is automatically closed when it is garbage collected.
* Certain fatal errors also result in a closed connection.
*
* @exception SQLException
* if a database access error occurs
*/
public void close() throws SQLException {
synchronized (getConnectionMutex()) {
if (this.connectionLifecycleInterceptors != null) {
new IterateBlock<Extension>(this.connectionLifecycleInterceptors.iterator()) {
void forEach(Extension each) throws SQLException {
((ConnectionLifecycleInterceptor)each).close();
}
}.doForAll();
}
realClose(true, true, false, null);
}
}
/**
* Closes connection and frees resources.
*
* @param calledExplicitly
* is this being called from close()
* @param issueRollback
* should a rollback() be issued?
* @throws SQLException
* if an error occurs
*/
public void realClose(boolean calledExplicitly, boolean issueRollback,
boolean skipLocalTeardown, Throwable reason) throws SQLException {
SQLException sqlEx = null;
if (this.isClosed()) {
return;
}
this.forceClosedReason = reason;
try {
if (!skipLocalTeardown) {
if (!getAutoCommit() && issueRollback) {
try {
rollback();
} catch (SQLException ex) {
sqlEx = ex;
}
}
reportMetrics();
if (getUseUsageAdvisor()) {