Data Source与数据库链接池简介 JDBC简介(八)

DataSource是做为DriverManager的替代品而推出的,DataSource 对象是获取链接的首选方法。

起源

为什么放弃DriverManager

DriverManager负责管理驱动程序,而且使用已注册的驱动程序进行链接。
//一、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//数据库链接所需参数
String user = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/sampledb?useUnicode=true&characterEncoding=utf-8";
//二、获取链接对象
Connection conn = DriverManager.getConnection(url, user, password);

 

使用DriverManager的通常形式如上面代码所示
直接使用DriverManager的这种形式,一般须要将驱动程序硬编码到项目中(JDBC4.0后能够自动注册驱动程序)
并且最重要的是DriverManager的getConnection方法获取的链接,是创建与数据库的链接,是创建与数据库的链接,是创建与数据库的链接。
可是创建与数据库的链接是一项较耗资源的工做,频繁的进行数据库链接创建操做会产生较大的系统开销。
随着企业级应用复杂度的提高以及对性能要求的提升,这一点是难以接受的。

链接池

既然每次使用时都从新创建与数据库之间的链接,会产生较大的系统开销
是否能够事先建立一些链接备用,当须要时,从这些链接中选择一个提供出去;当链接使用完毕后,并非真正的关闭,而是将这些数据状态还原,而后继续等待下一我的使用?
好比滑雪场会租赁雪具滑雪服等,若是你不是资深玩家,你没有必要浪费钱买,即便你不差钱,每次去滑雪场都不能轻装上阵,每次都要携带不少装备,也是一件麻烦事。
这种不必的花费或者麻烦其实都是一种开销。
链接池的核心与租用的理念有相似的点,重复使用能够提升链接的利用率,减小开销(固然链接池的使用并不须要你花费一笔租金)
链接的持有是消耗空间的,可是如今绝大多数场景下,磁盘空间并无那么金贵,咱们更关心的是性能,因此 空间换取时间,链接池的逻辑被普遍应用。

数据源

DriverManager只是创建与数据库之间的链接,如何才能将链接池的概念应用其中?
一种很天然的方式就是提供一个薄层的封装,创建一个中间层,这个中间层将DriverManager生成的链接,组织到链接池中,而后从池中提供链接。
image_5c4aa662_951
 
Data Source就是DriverManager的一种替代角色,对外呈现就相似于一个DriverManager,拥有对外提供链接的能力
直接使用DriverManager,驱动程序与管理器是“服务者---管理者”的形式,借助于管理者才能提供服务。
Data Source将驱动程序的概念淡化了,突出驱动程序可以提供的服务与能力,将驱动程序提供的服务与能力抽象为Data Source数据源这一角色。
image_5c4aa662_6e5d
DataSource中获取的链接来自于链接池中,而池中的链接根本也仍是从DriverManager获取而来
有了数据源这一中间层,就能够实现链接池和分布式事务的管理。
对外呈现DataSource就是相似于DriverManager的一个存在。
 
DataSource的形式是JNDI (Java Naming Directory Interface)
DataSource是JNDI资源的一种,那么到底什么是JNDI呢
此处不过多解释,能够简单认为JNDI是相似这样一个东西:
一个哈希表,类型为<String,Object>
JNDI的两个最主要操做:bind和lookup。bind操做负责往哈希表里存对象,lookup则根据这个键值字符串往外取对象。
开发人员可使用键值——也就是一个字符串名称——来获取某个对象。
简言之就是能够给一个对象命名,而后能够经过名称找到这个对象。
数据源的概念在应用程序与数据库链接之间插入了一个中间层,进而能够实现链接池以及事务管理,而且以JNDI的形式,也可以以很是方便的形式使用。
 

实现

核心架构

关于数据源有如下几个核心的接口
CommonDataSource接口定义了 DataSource、XADataSource 和 ConnectionPoolDataSource 之间公用的方法。
DataSource 是 官方定义的获取 connection 的接口, ConnectionPoolDataSource 是官方定义的从 connection pool 中拿 connection 的接口,XADataSource是定义的用来获取分布式事务链接的接口
也就是分为了三个方向,基本实现,链接池,事务
image_5c4aa662_28ee
对于ConnectionPoolDataSource的使用方案应该是下面所示
对于Connection Pool的实现,借助于ConnectionPoolDataSource,进而获取PooledConnection ,而后获取链接,这是一种标准作法
image_5c4aa662_1690
可是有的时候 事情的发展或许并不必定如规划的那般发展
不少的工具类仅仅实现DataSource了,也一并实现链接池以及事务的能力,接口就在那里,我直接实现一个强大的实现类,也没什么问题

DataSource

这是一个工厂对象,用于提供到此 DataSource 对象所表示的物理数据源的链接。
做为 DriverManager 工具的替代项,DataSource 对象是获取链接的首选方法。
实现 DataSource 接口的对象一般在基于 JavaTM Naming and Directory Interface (JNDI) API 的命名服务中注册。
 
DataSource 接口由驱动程序供应商实现。共有三种类型的实现:
  • 基本实现 - 生成标准的 Connection 对象
  • 链接池实现 - 生成自动参与链接池的 Connection 对象。此实现与中间层链接池管理器一块儿使用。
  • 分布式事务实现 - 生成一个 Connection 对象,该对象可用于分布式事务,大多数状况下老是参与链接池。此实现与中间层事务管理器一块儿使用,大多数状况下老是与链接池管理器一块儿使用。
 
DataSource 对象的属性在必要时能够修改。
例如,若是将数据源移动到另外一个服务器,则可更改与服务器相关的属性。其优势在于,因为能够更改数据源的属性,因此任何访问该数据源的代码都无需更改。
 
经过 DataSource 对象访问的驱动程序自己不会向 DriverManager 注册。
经过lookup操做获取 DataSource 对象,而后使用该对象建立 Connection 对象。
使用基本的实现,经过 DataSource 对象获取的链接与经过 DriverManager 设施获取的链接相同。
 
数据源的实现必须提供public的无参的构造函数。

API

DataSource只有两个方法(确切的说是一个方法的两个重载版本),用于创建与此 DataSource 对象所表示的数据源的链接。
  • Connection getConnection()
  • Connection getConnection(String username, String password)

小结

DriverManager用于管理驱动程序而且提供数据库的直连,频繁的建立和消耗链接增长系统大量开销,而且将数据库链接直接暴露。
数据源的概念就是为了在应用程序和DriverManager建立的数据库直接链接之间插入一个中间层
借助于中间层,应用程序与数据库的链接二者之间完成了解耦,也可以对数据库的真实链接进行隐藏;
一旦解耦,经过中间层间接调用,相似代理模式,就能够添加更多的服务---链接池以及分布式事务。
数据源相关接口有三个,可是不少是仅仅实现了DataSource接口
而对于链接池本质就是一个容器,负责管理建立好的数据库链接。
链接池与数据源逻辑上是两回事,可是在实现层面的代码中DataSource的实现类每每都具备了链接池以及链接池管理方面的功能。
因此有些时候,DataSource究竟是理解成数据源?仍是javax.sql.DataSource?仍是指的一个实现?仍是一个实现了数据库链接池的实现?(常常一个实现了DataSource的而且提供了链接池功能的实现,会被叫作数据库链接池)

应用

Java做为一种普遍使用的开发语言,天然不须要咱们本身实现DataSource,一些大厂已经帮咱们实现了
好比:DBCP ,C3P0 , druid
下面的三张图展现了类继承结构,能够看得出来他们实现的接口
 
image_5c4aa662_1ad3
 
image_5c4aa662_814
 
image_5c4aa662_7dc8
目前推荐使用ALI的Druid,http://druid.io/
maven中央仓库: http://central.maven.org/maven2/com/alibaba/druid/ 
Druid是一个开源项目,源码托管在github上,源代码仓库地址是 https://github.com/alibaba/druid。
Wiki首页:
与其余主流对比
https://github.com/alibaba/druid/wiki/%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E5%AF%B9%E6%AF%94
image_5c4aa662_4bf9

数据库链接池示例

以下一个简单的演示
package jdbc;
import com.alibaba.druid.pool.DruidDataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.apache.commons.dbcp2.BasicDataSource;
public class MyDataSource {
  public static void main(String[] args) throws Exception {
      String user = "root";
      String password = "123456";
      String url = "jdbc:mysql://localhost:3306/sampledb?useUnicode=true&characterEncoding=utf-8";
      //1.获取链接
      // Connection conn = getDHCPConnection(user,password,url);
      //Connection conn = getC3P0Connection(user,password,url);
      Connection conn = getDruidConnection(user, password, url);
      String sql = "select * from student limit 0,10";
      //二、得到sql语句执行对象
      Statement stmt = conn.createStatement();
      //三、执行并保存结果集
      ResultSet rs = stmt.executeQuery(sql);
      //四、处理结果集
      while (rs.next()) {
      System.out.print("id:" + rs.getInt(1));
      System.out.print(",姓名:" + rs.getString(2));
      System.out.print(",年龄:" + rs.getInt(3));
      System.out.println(",性别:" + rs.getString(4));
      }
      conn.close();
      stmt.close();
      rs.close();
}
public static Connection getDruidConnection(String user, String password, String url)
throws Exception {
    DruidDataSource ds = new DruidDataSource();
    ds.setUsername(user);
    ds.setPassword(password);
    ds.setUrl(url);
    ds.setDriverClassName("com.mysql.jdbc.Driver");
    return ds.getConnection();
    }
public static Connection getC3P0Connection(String user, String password, String url)
throws Exception {
    ComboPooledDataSource cpds = new ComboPooledDataSource();
    cpds.setUser(user);
    cpds.setPassword(password);
    cpds.setJdbcUrl(url);
    cpds.setDriverClass("com.mysql.jdbc.Driver");
    return cpds.getConnection();
    }
public static Connection getDHCPConnection(String user, String password, String url)
throws Exception {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        Connection connection = dataSource.getConnection();
        return connection;
    }
}
image_5c4aa663_5c6d

总结

数据源做为DriverManager的替代者,用于获取数据库链接,你应该老是使用DataSource
DataSource是应用程序与数据库链接的一个抽象的中间层,是一个接口
对于DataSource已经有了不少优秀的实现,其中较为突出的为Druid,建议使用,Druid不只仅提供了链接池的功能还提供了其余好比监控等功能,很是强大。
对于数据源的应用,除了用户名密码url还有其余的一些属性信息,好比最大链接数,创建链接的最大等待时间等,不一样的链接池略微有出入,能够查看手册。
对于DataSource的一些实现,常常被叫作数据库链接池,好比Druid官方文档中说“Druid是Java语言中最好的数据库链接池“,本质核心就是DataSource的一个实现类,做为中间层使用,而且基本上都提供了附带的其余的服务,也就是说不只仅实现了核心建筑,也基于核心之上构建了不少的外围建设。
相关文章
相关标签/搜索