DataSourceUitls介绍

DataSourceUitls类位于org.springframework.jdbc.datasource包下,提供了很多的静态方法去从一个javax.sql.DataSource下获取JDBC Connection,并且提供了对Spring 事务管理的支持。

在JdbcTemplate类的内部,DataSourceUtils被多次使用。其实,我们还可以在代码中直接使用DataSourceUitls来操作Jdbc。

DataSourceUitls获取Connection

getConnection方法

内部实现

  1. public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
  2. try {
  3. return doGetConnection(dataSource);
  4. }
  5. catch (SQLException ex) {
  6. throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
  7. }
  8. catch (IllegalStateException ex) {
  9. throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage());
  10. }
  11. }

可以看出,通过传入一个指定的DataSource,可以获取一个Connection,获取过程由doGetConnection方法实现。如果抛出SQLException和IllegalStateException,则将其包装成CannotGetJdbcConnectionException,事实上也只能抛出SQLException和IllegalStateException这两种异常。通过查看CannotGetJdbcConnectionException的源代码,我们可以发现CannotGetJdbcConnectionException实际上是DataAccessException的子类,因此可以说,getConnection会将抛出的异常统一封装成Spring的DataAccessException。

doGetConnection方法

内部实现

  1. public static Connection doGetConnection(DataSource dataSource) throws SQLException {
  2. Assert.notNull(dataSource, "No DataSource specified");
  3. ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
  4. if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
  5. conHolder.requested();
  6. if (!conHolder.hasConnection()) {
  7. logger.debug("Fetching resumed JDBC Connection from DataSource");
  8. conHolder.setConnection(fetchConnection(dataSource));
  9. }
  10. return conHolder.getConnection();
  11. }
  12. // Else we either got no holder or an empty thread-bound holder here.
  13. logger.debug("Fetching JDBC Connection from DataSource");
  14. Connection con = fetchConnection(dataSource);
  15. if (TransactionSynchronizationManager.isSynchronizationActive()) {
  16. logger.debug("Registering transaction synchronization for JDBC Connection");
  17. // Use same Connection for further JDBC actions within the transaction.
  18. // Thread-bound object will get removed by synchronization at transaction completion.
  19. ConnectionHolder holderToUse = conHolder;
  20. if (holderToUse == null) {
  21. holderToUse = new ConnectionHolder(con);
  22. }
  23. else {
  24. holderToUse.setConnection(con);
  25. }
  26. holderToUse.requested();
  27. TransactionSynchronizationManager.registerSynchronization(
  28. new ConnectionSynchronization(holderToUse, dataSource));
  29. holderToUse.setSynchronizedWithTransaction(true);
  30. if (holderToUse != conHolder) {
  31. TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
  32. }
  33. }
  34. return con;
  35. }

doGetConnection方法是用于实际操作获取Connection的核心方法。从源代码中可以得出,如果不存在与当前线程绑定的Connection,则新建一个全新的Connection,如果当前线程的事务同步处于活动状态,那么为刚刚创建的Connection添加Spring事务管理的支持;如果当前线程存在一个相应的Connection,那么则有当前的事务管理分配。

fetchConnection方法

fetchConnection是一个private方法,不对外公开,实际上是做了一个简单的功能:从当前的DastaSource新建一个Connection,如果新建失败,那么抛出IllegalStateException,提示不能获取一个新的Connection。

DataSourceUitls释放Connection

releaseConnection方法

内部实现

  1. public static void releaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) {
  2. try {
  3. doReleaseConnection(con, dataSource);
  4. }
  5. catch (SQLException ex) {
  6. logger.debug("Could not close JDBC Connection", ex);
  7. }
  8. catch (Throwable ex) {
  9. logger.debug("Unexpected exception on closing JDBC Connection", ex);
  10. }
  11. }

releaseConnection方法的具体实现由doReleaseConnection处理。如果抛出异常,仅仅是在日志中做debug处理,不会对外抛出。该方法的两个参数均存在NULL的情况,

如果con为NULL,则忽略本次调用;而另一个参数则被允许为NULL。

doReleaseConnection方法

内部实现

  1. public static void doReleaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) throws SQLException {
  2. if (con == null) {
  3. return;
  4. }
  5. if (dataSource != null) {
  6. ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
  7. if (conHolder != null && connectionEquals(conHolder, con)) {
  8. // It's the transactional Connection: Don't close it.
  9. conHolder.released();
  10. return;
  11. }
  12. }
  13. logger.debug("Returning JDBC Connection to DataSource");
  14. doCloseConnection(con, dataSource);
  15. }

doReleaseConnection方法是真正释放了Connection的方法,与releaseConnection方法相比,则完成了对传入的两个参数的校验和抛出更底层的异常。在dataSource不为NULL的情况下,释放此ConnectionHolder保留的当前连接,使得该当前的Connection可以得到复用,对提供Jdbc操作的性能很有帮助。如果dataSource为null的情况下则选择直接关闭连接。

DataSourceUitls关闭Connection

doCloseConnection方法

内部实现

  1. public static void doCloseConnection(Connection con, @Nullable DataSource dataSource) throws SQLException {
  2. if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
  3. con.close();
  4. }
  5. }

在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是一个强大的工具辅助类,不仅仅是提供了Connection的获取、释放和关闭,其实还提供了为Connection提供Spring事务的支持。a

DataUtils对Connection的获取、释放和关闭的操作学习的更多相关文章

  1. 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 数据库连接不释放测试 连接池 释放连接 关闭连接 有关 redis-py 连接池会导致服务器产生大量 CLOSE_WAIT 的再讨论以及一个解决方案

    import pymysqlfrom redis import Redisimport time h, pt, u, p, db = '192.168.2.210', 3306, 'root', 'n ...

  2. 多个iframe中根据src获取特定iframe并执行操作

    多个iframe中根据src获取特定iframe并执行操作 前言:在项目中做一个批量编辑工单时需要在一大堆的iframe中的某一个iframe里边再用模态框的形式显示编辑区域,然后再在模态框里边加入i ...

  3. 【Python】[技术博客] 一些使用Python编写获取手机App日志的操作

    一些使用Python编写获取手机App日志的操作 如何获取手机当前打开的App的包名 如何获取当前App进程的PID 如何查看当前App的日志 如何将日志保存到文件 如何关闭进程 如何不显示命令行窗口 ...

  4. Js获取当前日期时间及其它操作

    Js获取当前日期时间及其它操作var myDate = new Date();myDate.getYear(); //获取当前年份(2位)myDate.getFullYear(); //获取完整的年份 ...

  5. C#获取窗口,模拟按键操作

    C#获取窗口,模拟按键操作,实现计算器模拟操作.首先引用. using System.Runtime.InteropServices; 使用DllImport引入两个函数: // Get a hand ...

  6. jQuery获取checkbox选中项等操作及注意事项

    jQuery获取checkbox选中项等操作及注意事项 今天在做一个项目功能时需要显示checkbox选项来让用户进行选择,由于前端不是很熟练,所以做了一个简单的Demo,其中遇到一些小问题,特记录下 ...

  7. Linux 开启和关闭 Ping 操作

    Linux 默认是开启 ping 操作的,通过以下两种方式可以开启和关闭 ping 操作 . 1.修改内核参数 通过内核参数设置也有两种方式,一种是临时修改,一种是永久修改. 1.1 临时设置 PIN ...

  8. 【转】Js获取当前日期时间及其它操作

    Js获取当前日期时间及其它操作 原文地址:http://www.cnblogs.com/carekee/articles/1678041.html var myDate = new Date();my ...

  9. [转]Js获取当前日期时间及其它操作

    转载自:http://www.cnblogs.com/carekee/articles/1678041.html Js获取当前日期时间及其它操作 var myDate = new Date();myD ...

随机推荐

  1. Python机器学习笔记:深入理解Keras中序贯模型和函数模型

     先从sklearn说起吧,如果学习了sklearn的话,那么学习Keras相对来说比较容易.为什么这样说呢? 我们首先比较一下sklearn的机器学习大致使用流程和Keras的大致使用流程: skl ...

  2. CEF C++环境搭建

    第一步:下载CEF 到这里下载最新版本的CEF http://cefbuilds.com/ 下载解压之后,大概会看到如下图所示的文件 cefclient:是一个比较复杂的示例代码cefsimple:是 ...

  3. Java关键字(一)——instanceof

    instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为: boolean result = obj instanceof Class 其中 obj 为一 ...

  4. 记一次IDEA编译器调优

    前言: 我们知道,IDEA是用Java写的,那么他肯定也存在虚拟机的调优的问题,那么今天我们就对它进行开刀. 下面是默认参数 位置在:C:\Program Files\JetBrains\Intell ...

  5. 数据分析之pandas模块

    一.Series 类似于一位数组的对象,第一个参数为数据,第二个参数为索引(索引可以不指定,就默认用隐式索引) Series(data=np.random.randint(1,50,(10,))) S ...

  6. 如何将自定义的搜索参数便捷的添加到js方式的bootstrap table的参数中

    页面: <div> <form id="exp_form"> 查询参数... <button type="button" oncl ...

  7. spring cloud config服务器

    Spring Cloud Config提供了一种在分布式系统中外部化配置服务器和客户端的支持.配置服务器有一个中心位置,管理所有环境下的应用的外部属性.客户端和服务器映射到相同Spring Event ...

  8. Select2插件的隐藏、设置宽度

    <select id="selPrinvice" class="Select2 select2-hidden-accessible" style=&quo ...

  9. [PHP] 数据结构-线性表的顺序存储结构PHP实现

    1.PHP中的数组实际上是有序映射,可以当成数组,列表,散列表,字典,集合,栈,队列,不是固定的长度2.数组定义中多个单元都使用了同一个键名,则只使用了最后一个,之前的都被覆盖了3.想要函数的一个参数 ...

  10. How does this enqueue function work?

    Question: I'm having trouble understanding this line: rear->next = temp; in this queue function: ...