• Mybatis如何使用druid数据连接池


    数据库连接池的作用

    学习数据库连接池之前我们也应该听过线程池的,他们虽然技术分支不一样,但是池的思想都是一样的, 用了享元模式,达到复用的思想,即不用每次都去创建连接对象,如果这个对象是一个很重的资源对象, 比如:创建线程,是需要和操作系统申请, 创建数据库连接是要建立网络连接 也是一个复杂的过程, 所以这种重的资源一旦创建最好复用。

    规范接口

    java的JDBC连接规范, 已经制定了数据源接口 javax.sql.DataSource, 所以标准已经制定,任何Java方面的ORM框架都必须遵守这一套规范, 要不然没人想去学。

    在Mybatis的配置文件中,我们的环境配置都是这样

    <!--环境配置-->
      <environments default="development">
        <!--开发环境-->
        <environment id="development">
          <!--事务管理器-->
          <transactionManager type="JDBC"/>
          <!--数据源-->
          <dataSource type="POOLED">
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url"
                      value="jdbc:mysql://localhost:3306/oa_test?useUnicode=true&useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
          </dataSource>
        </environment>
      </environments>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    首先作为一个XML的配置文件, 必须得有代码去解析, 要不然是毫无意义的。
    从配置文件中我们可以知道事务管理器使用的是JDBC事务管理, 数据源采用的池化。

    所以要弄明白如何把内置的池化数据源换成Druid我们得开解析这段配置的源码, 看看Mybatis留给了开发者怎么样的扩展点。

    代码解析XML文件过程

    Mybatis的XML解析技术, 如果只是学API建议,不用学,等需要用到的时候在学, 因为api根本没有意义, 如何解析构建XML解析树原理才是值得花时间去学习。XML解析跳过。

    XMLConfigBuilder.parseConfiguration

    environmentsElement(root.evalNode("environments")); //设置environments
    
    • 1

    解析整体逻辑如下:

    private void environmentsElement(XNode context) throws Exception { //解析environment
        if (context != null) { //判断有没有环境配置存在
          if (environment == null) {
            environment = context.getStringAttribute("default"); //使用默认的
          }
          for (XNode child : context.getChildren()) { //遍历所有的环境
            String id = child.getStringAttribute("id");
            if (isSpecifiedEnvironment(id)) { //判断当前环境是不是指定的
              TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); //事务管理工厂
              DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); //创建数据库连接池工厂
              DataSource dataSource = dsFactory.getDataSource(); //获取数据库连接池
              Environment.Builder environmentBuilder = new Environment.Builder(id)
                  .transactionFactory(txFactory)
                  .dataSource(dataSource); //组装建造者
              configuration.setEnvironment(environmentBuilder.build()); //构建环境对象
              break;/*说明数据源环境在mybatis中只存在一份, 只能使用一套配置*/
            }
          }
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    从上述代码可以看出关键点就是在于事务管理和数据源

    transactionManagerElement 解析事务管理

    private TransactionFactory transactionManagerElement(XNode context) throws Exception {
        if (context != null) {
          String type = context.getStringAttribute("type"); //获取事务管理器类型别名
          Properties props = context.getChildrenAsProperties(); //获取属性配置
          TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance(); //使用构造方法反射进行实例化
          factory.setProperties(props); //设置属性
          return factory;
        }
        throw new BuilderException("Environment declaration requires a TransactionFactory.");
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    整体的代码逻辑还是很简单的,就是读取配置,根据配置的关键字别名找到对应的类, 进行反射实例化对象。

    工厂对象的实现类
    在这里插入图片描述

    2个事务工厂类,分别生产Jdbc事务(JdbcTransaction) 和 被管理的事务(ManagedTransaction)

    区别就是 JDBC事务 commit和rollback都是由自己控制的, 而被管理的事务的提交和回滚的操作是空即自己不做,交给别人去做,例如Spirng

    dataSourceElement 解析数据源

    关键点来了, 看了这里的代码就知道如何替换Driud数据源了

    上代码:

    private DataSourceFactory dataSourceElement(XNode context) throws Exception {
        if (context != null) {
          String type = context.getStringAttribute("type"); //获取类型别名
          Properties props = context.getChildrenAsProperties(); //获取属性配置
          DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance(); //实例化对象
          factory.setProperties(props);
          return factory;
        }
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    代码中读取了别名, 如何去获取对应的类进行反射实例化创建对象即 数据源工厂, 既然工厂,说明就是用来生成数据源的,看看工厂的实现。
    在这里插入图片描述

    可见顶级数据源工厂接口下一共由3个实现,分别是 无池化 、池化、 Jndi 。

    Jdni是说明就不讨论了,感兴趣可以自己学习学习。

    其中池化数据源工厂又是继承的无池化的数据源工厂。

    所以上述代码解析完之后我们得到了一个数据源工厂, 在回来看外面的代码。
    在这里插入图片描述
    是不是就清晰了, 用数据源工厂创建了数据源。 故 如果要用Druid 我们只需要实现数据源工厂接口, 然后把别名和类注册到Mybatis的别名配置上,

    <typeAliases>
        <!--设置druid数据库连接池别名-->
        <typeAlias type="com.learn.mybatis.firstday.druidwapper.DruidTransactionFactory" alias="druid"/>
      </typeAliases>
      <!--环境配置-->
      <environments default="development">
        <!--开发环境-->
        <environment id="development">
          <!--事务管理器-->
          <transactionManager type="JDBC"/>
          <!--数据源-->
          <dataSource type="druid"><!--使用自己的Driud工厂-->
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url"
                      value="jdbc:mysql://localhost:3306/oa_test?useUnicode=true&useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
          </dataSource>
        </environment>
      </environments>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    DriudDataSourceFactory:

    public class DruidTransactionFactory implements DataSourceFactory {
    
      private DruidDataSource dataSource;
    
      @Override
      public void setProperties(Properties props) {
        props.setProperty("driverClassName", props.getProperty("driver"));
        try {
          dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(props);
        } catch (Exception e) {
          e.printStackTrace();
          throw new RuntimeException("we cant config druid");
        }
      }
    
      @Override
      public DataSource getDataSource() {
        return dataSource;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    总结

    一切的真相都逃不过源码。。。。。。。。。。。。。。

  • 相关阅读:
    Python控制结构(空军工程大学)
    回顾方法的定义
    主板知识:了解的PCI Express Gen 5的终极指南
    教程图文详解 - 网络互联与互联网(第六章)
    nginx 代理服务时遇到的问题
    鸿蒙OS应用开发初体验
    HBase1.4.6安装搭建及shell命令使用
    SQL-窗口函数合集
    gorm的使用(持续更新)
    HCIP练习03(重发布)
  • 原文地址:https://blog.csdn.net/nobaldnolove/article/details/127798398