在jdbctemplate类的内部,datasourceutils被多次使用。其实,我们还可以在代码中直接使用datasourceuitls来操作jdbc。
datasourceuitls获取connectiongetconnection方法内部实现 public static connection getconnection(datasource datasource) throws cannotgetjdbcconnectionexception { try { return dogetconnection(datasource); } catch (sqlexception ex) { throw new cannotgetjdbcconnectionexception(failed to obtain jdbc connection, ex); } catch (illegalstateexception ex) { throw new cannotgetjdbcconnectionexception(failed to obtain jdbc connection: + ex.getmessage()); } }
可以看出,通过传入一个指定的datasource,可以获取一个connection,获取过程由dogetconnection方法实现。如果抛出sqlexception和illegalstateexception,则将其包装成cannotgetjdbcconnectionexception,事实上也只能抛出sqlexception和illegalstateexception这两种异常。通过查看cannotgetjdbcconnectionexception的源代码,我们可以发现cannotgetjdbcconnectionexception实际上是dataaccessexception的子类,因此可以说,getconnection会将抛出的异常统一封装成spring的dataaccessexception。
dogetconnection方法内部实现 public static connection dogetconnection(datasource datasource) throws sqlexception { assert.notnull(datasource, no datasource specified); 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(fetchconnection(datasource)); } return conholder.getconnection(); } // else we either got no holder or an empty thread-bound holder here. logger.debug(fetching jdbc connection from datasource); connection con = fetchconnection(datasource); 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; }
dogetconnection方法是用于实际操作获取connection的核心方法。从源代码中可以得出,如果不存在与当前线程绑定的connection,则新建一个全新的connection,如果当前线程的事务同步处于活动状态,那么为刚刚创建的connection添加spring事务管理的支持;如果当前线程存在一个相应的connection,那么则有当前的事务管理分配。
fetchconnection方法fetchconnection是一个private方法,不对外公开,实际上是做了一个简单的功能:从当前的dastasource新建一个connection,如果新建失败,那么抛出illegalstateexception,提示不能获取一个新的connection。
datasourceuitls释放connectionreleaseconnection方法内部实现 public static void releaseconnection(@nullable connection con, @nullable datasource datasource) { try { doreleaseconnection(con, datasource); } catch (sqlexception ex) { logger.debug(could not close jdbc connection, ex); } catch (throwable ex) { logger.debug(unexpected exception on closing jdbc connection, ex); } }
releaseconnection方法的具体实现由doreleaseconnection处理。如果抛出异常,仅仅是在日志中做debug处理,不会对外抛出。该方法的两个参数均存在null的情况,
如果con为null,则忽略本次调用;而另一个参数则被允许为null。
doreleaseconnection方法内部实现 public static void doreleaseconnection(@nullable connection con, @nullable datasource datasource) throws sqlexception { if (con == null) { return; } if (datasource != null) { connectionholder conholder = (connectionholder) transactionsynchronizationmanager.getresource(datasource); if (conholder != null && connectionequals(conholder, con)) { // it's the transactional connection: don't close it. conholder.released(); return; } } logger.debug(returning jdbc connection to datasource); docloseconnection(con, datasource); }
doreleaseconnection方法是真正释放了connection的方法,与releaseconnection方法相比,则完成了对传入的两个参数的校验和抛出更底层的异常。在datasource不为null的情况下,释放此connectionholder保留的当前连接,使得该当前的connection可以得到复用,对提供jdbc操作的性能很有帮助。如果datasource为null的情况下则选择直接关闭连接。
datasourceuitls关闭connectiondocloseconnection方法内部实现 public static void docloseconnection(connection con, @nullable datasource datasource) throws sqlexception { if (!(datasource instanceof smartdatasource) || ((smartdatasource) datasource).shouldclose(con)) { con.close(); } }
在doreleaseconnection方法中,我们已经得知当datasource为null的时候会执行docloseconnection方法。事实上,只有datasource没有实现org.springframework.jdbc.datasource.smartdatasource接口的时候或者datasource实现了org.springframework.jdbc.datasource.smartdatasource接口且允许关闭的时候,在真正关闭了connection。
org.springframework.jdbc.datasource.smartdatasource接口是 javax.sql.datasource接口的一个扩展,用一种未包装的形式返回jdbc的连接。实现该接口的类可以查询connection在完成操作之后是否应该关闭。在srping和datasourceuitls和jdbctemplate中会自动执行这样的检查。
以上就是datasourceuitls的介绍及方法的详细内容。
