• 常用数据库连接池


    1、使用数据库连接池优化程序性能

    2、数据库连接池编写原理分析

    1编写连接池需实现javax.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:

    Connection getConnection() 

    Connection getConnection(String username, String password) 

    2实现DataSource接口,并实现连接池功能的步骤:

    DataSource构造函数中批量创建与数据库的连接,并把创建的连接保存到一个集合对象中

    实现getConnection方法,让getConnection方法每次调用时,从集合对象中取一个Connection返回给用户。

    当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到连接池的集合对象中,而不要把conn还给数据库。

    package com.itheima.pool;

    import java.io.PrintWriter;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    import java.sql.Array;

    import java.sql.Blob;

    import java.sql.CallableStatement;

    import java.sql.Clob;

    import java.sql.Connection;

    import java.sql.DatabaseMetaData;

    import java.sql.DriverManager;

    import java.sql.NClob;

    import java.sql.PreparedStatement;

    import java.sql.SQLClientInfoException;

    import java.sql.SQLException;

    import java.sql.SQLWarning;

    import java.sql.SQLXML;

    import java.sql.Savepoint;

    import java.sql.Statement;

    import java.sql.Struct;

    import java.util.LinkedList;

    import java.util.List;

    import java.util.Map;

    import java.util.Properties;

    import javax.sql.DataSource;

    public class MyPool implements DataSource {

    private static List<Connection> poolList = new LinkedList<Connection>();

    static{

    try{

    Class.forName("com.mysql.jdbc.Driver");

    for(int i = 0;i<5; i++){

    Connection conn = DriverManager.getConnection("jdbc:mysql:///day11","root","root");

    poolList.add(conn);

    }

    }catch (Exception e) {

    e.printStackTrace();

    throw new RuntimeException();

    }

    }

    public Connection getConnection() throws SQLException {

    if(poolList.size()<=0){

    for(int i = 0;i<5; i++){

    Connection conn = DriverManager.getConnection("jdbc:mysql:///day11","root","root");

    poolList.add(conn);

    }

    }

    final Connection conn = poolList.remove(0);

    Connection procxy = (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){

    public Object invoke(Object proxy, Method method, Object[] args)

    throws Throwable {

    if("close".equals(method.getName())){

    poolList.add(conn);

    System.out.println("还回了一个连接,还剩余"+poolList.size());

    return null;

    }else{

    return method.invoke(conn, args);

    }

    }

    });

    System.out.println("取走了一个连接,还剩余"+poolList.size());

    return procxy;

    }

    public void retConn(Connection conn){

    try {

    if(conn == null || conn.isClosed())return;

    poolList.add(conn);

    System.out.println("还回了一个连接,还剩余"+poolList.size());

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    public Connection getConnection(String username, String password)

    throws SQLException {

    // TODO Auto-generated method stub

    return null;

    }

    public PrintWriter getLogWriter() throws SQLException {

    // TODO Auto-generated method stub

    return null;

    }

    public int getLoginTimeout() throws SQLException {

    // TODO Auto-generated method stub

    return 0;

    }

    public void setLogWriter(PrintWriter out) throws SQLException {

    // TODO Auto-generated method stub

    }

    public void setLoginTimeout(int seconds) throws SQLException {

    // TODO Auto-generated method stub

    }

    public boolean isWrapperFor(Class<?> iface) throws SQLException {

    // TODO Auto-generated method stub

    return false;

    }

    public <T> T unwrap(Class<T> iface) throws SQLException {

    // TODO Auto-generated method stub

    return null;

    }

    }

    package com.itheima.pool;

    import java.sql.Connection;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import org.junit.Test;

    public class PoolDemo1 {

    @Test

    public void test1(){

    MyPool pool = new MyPool();

    Connection conn = null;

    PreparedStatement ps = null;

    ResultSet rs = null;

    try{

    conn = pool.getConnection();

    ps = conn.prepareStatement("select * from account where id=?");

    ps.setInt(1, 1);

    rs = ps.executeQuery();

    while(rs.next()){

    String name = rs.getString("name");

    double money = rs.getDouble("money");

    System.out.println(name+":"+money);

    }

    }catch (Exception e) {

    e.printStackTrace();

    }finally{

    if(rs != null){

    try {

    rs.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    rs = null;

    }

    }

    if(ps != null){

    try {

    ps.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    ps = null;

    }

    }

    if(conn!=null){

    try {

    conn.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    conn = null;

    }

    }

    }

    }

    }

    3编写数据库连接池核心

    1扩展Connectionclose方法

    在关闭数据库连接时,将connection存回连接池中,而并非真正的关闭

    2扩展类的三种方式

    基于继承--- 方法覆盖

    使用装饰模式包装类,增强原有行为

    使用动态代理 --- 基于字节码Class在内存中执行过程

    package com.itheima.pool;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    interface 动物 {

    public void ();

    public void ();

    }

    interface xx{

    public void sss();

    }

    public class 狗 implements 动物 ,xx {

    public void (){

    System.out.println("狗在叫");

    }

    public void (){

    System.out.println("狗在吃");

    }

    //代理设计模式

    public static void main(String[] args) {

    final 狗 dog = new ();

    动物 proxy = (动物)Proxy.newProxyInstance(dog.getClass().getClassLoader(), dog.getClass().getInterfaces()

    , new InvocationHandler(){

    public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {

    if("".equals(method.getName())){

    System.out.println("代理狗在旺旺叫~~~~~~~~~~");

    return null;

    }else{

    return method.invoke(dog, args);

    }

    }

    });

    proxy.();

    proxy.();

    ((xx)proxy).sss();

    // dog.();

    // dog.();

    }

    public void sss() {

    System.out.println("sss");

    }

    }

    //装饰设计模式

    class 装饰狗 implements 动物{

    private 狗 dog = null;

    public 装饰狗(狗 dog) {

    this.dog = dog;

    }

    public void () {

    System.out.println("装饰狗在叫!!!!!");

    }

    public void () {

    dog.();

    }

    }

    //继承方式改变方法的功能

    class 继承狗 extends {

    @Override

    public void () {

    System.out.println("继承狗在叫");

    }

    }

    4、动态代理增强close示例

    使用动态代理技术构建连接池中的connection

    proxyConn = (Connection) Proxy.newProxyInstance(this.getClass()

    .getClassLoader(), conn.getClass().getInterfaces(),

    new InvocationHandler() {

    //此处为内部类,当close方法被调用时将conn还回池中,其它方法直接执行

    public Object invoke(Object proxy, Method method,

      Object[] args) throws Throwable {

    if (method.getName().equals("close")) {

    pool.addLast(conn);

    return null;

    }

    return method.invoke(conn, args);

    }

    });

    5开源数据库连接池(DataSource)

    1现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。

    2也有一些开源组织提供了数据源的独立实现:

    DBCP 数据库连接池 

    C3P0 数据库连接池

    Apache Tomcat内置的连接池(apache dbcp

    3实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。

    4原来由jdbcUtil创建连接,现在由dataSource创建连接,为实现不和具体数据为绑定,因此datasource也应采用配置文件的方法获得连接。

    6、DBCP数据源

    1DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:

    Commons-dbcp.jar:连接池的实现

    Commons-pool.jar:连接池实现的依赖库

    2Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用

    BasicDataSource dataSource = new BasicDataSource();

    dataSource.setDriverClassName("com.mysql.jdbc.Driver");

    dataSource.setUrl("jdbc:mysql:///day13");

    dataSource.setUsername("root");

    tPassword("root");

    Properties prop = new Properties();

    prop.load(new FileInputStream("config.properties"));

    DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);

    (3)使用DBCP示例代码

    static{

    InputStream in = JdbcUtil.class.getClassLoader().

    getResourceAsStream("dbcpconfig.properties");

    Properties prop = new Properties();

    prop.load(in);

    BasicDataSourceFactory factory = new BasicDataSourceFactory();

    dataSource = factory.createDataSource(prop);

    }

    driverClassName=com.mysql.jdbc.Driver

    url=jdbc:mysql:///day11

    username=root

    password=root

    package com.itheima.pool;

    import java.io.FileReader;

    import java.sql.Connection;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import java.util.Properties;

    import javax.sql.DataSource;

    import org.apache.commons.dbcp.BasicDataSourceFactory;

    import org.junit.Test;

    public class DBCPDemo {

    @Test

    public void test1(){

    // BasicDataSource dataSource = new BasicDataSource();

    // dataSource.setDriverClassName("com.mysql.jdbc.Driver");

    // dataSource.setUrl("jdbc:mysql:///day11");

    // dataSource.setUsername("root");

    // dataSource.setPassword("root");

    Connection conn = null;

    PreparedStatement ps = null;

    ResultSet rs = null;

    try{

    Properties prop = new Properties();

    prop.load(new FileReader("dbcpconfig.properties"));

    DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);

    conn = dataSource.getConnection(); 

    ps = conn.prepareStatement("select * from account where id=?");

    ps.setInt(1, 1);

    rs = ps.executeQuery();

    while(rs.next()){

    String name = rs.getString("name");

    double money = rs.getDouble("money");

    System.out.println(name+":"+money);

    }

    }catch (Exception e) {

    e.printStackTrace();

    }finally{

    if(rs != null){

    try {

    rs.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    rs = null;

    }

    }

    if(ps != null){

    try {

    ps.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    ps = null;

    }

    }

    if(conn!=null){

    try {

    conn.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    conn = null;

    }

    }

    }

    }

    }

    (4)配置文件写法说明

    #连接设置

    driverClassName=com.mysql.jdbc.Driver

    url=jdbc:mysql://localhost:3306/jdbc

    username=root

    password=

    #<!-- 初始化连接 -->

    initialSize=10

    #最大连接数量

    maxActive=50

    #<!-- 最大空闲连接 -->

    maxIdle=20

    #<!-- 最小空闲连接 -->

    minIdle=5

    #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->

    maxWait=60000

    #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 

    #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。

    connectionProperties=useUnicode=true;characterEncoding=gbk

    #指定由连接池所创建的连接的自动提交(auto-commit)状态。

    defaultAutoCommit=true

    #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。

    #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

    defaultTransactionIsolation=READ_UNCOMMITTED

    5、C3P0 数据源

    ComboPooledDataSource dataSource = new ComboPooledDataSource();

    ComboPooledDataSource dataSource = new ComboPooledDataSource("mySoruce");

    <?xml version="1.0"?>

    <c3p0-config>

      <default-config>

    <property  name="driverClass">com.mysql.jdbc.Driver</property >

    <property name="jdbcUrl">jdbc:mysql:///Day12</property >

    <property name="user">root</property>

    <property name="password">root</property>

      </default-config>

      <!-- This app is massive! -->

      <named-config name="mySoruce"> 

      <property  name="driverClass">com.mysql.jdbc.Driver</property >

    <property name="jdbcUrl">jdbc:mysql:///Day12</property >

    <property name="user">root</property>

    <property name="password">root</property>

      </named-config>

    </c3p0-config>

    driverClass

    jdbcUrl

    user

    password

    acquireIncrement:当连接池中已经没有连接时,连接池自动获取连接时一次获取的连接个数。

    initialPoolSize:连接池初始化时,获取连接的个数。

    maxPoolSize:连接池可以保有的最大的连接的数量。

    maxIdleTime:当连接空闲多久时释放连接。如果该时间值设置问为0,表示从不释放连接。

    minPoolSize:连接池应该保有的最小的连接的数量。

    package com.itheima.pool;

    import java.beans.PropertyVetoException;

    import java.sql.Connection;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import org.junit.Test;

    import com.mchange.v2.c3p0.ComboPooledDataSource;

    public class C3P0Demo {

    @Test

    public void test() throws PropertyVetoException{

    ComboPooledDataSource dataSource = new ComboPooledDataSource();

    Connection conn = null;

    PreparedStatement ps = null;

    ResultSet rs = null;

    try{

    conn = dataSource.getConnection(); 

    ps = conn.prepareStatement("select * from account where id=?");

    ps.setInt(1, 1);

    rs = ps.executeQuery();

    while(rs.next()){

    String name = rs.getString("name");

    double money = rs.getDouble("money");

    System.out.println(name+":"+money);

    }

    }catch (Exception e) {

    e.printStackTrace();

    }finally{

    if(rs != null){

    try {

    rs.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    rs = null;

    }

    }

    if(ps != null){

    try {

    ps.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    ps = null;

    }

    }

    if(conn!=null){

    try {

    conn.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    conn = null;

    }

    }

    }

    }

    }

    <?xml version="1.0" ?>

    <c3p0-config>

      <default-config>

      <property name="driverClass">com.mysql.jdbc.Driver</property>

      <property name="jdbcUrl">jdbc:mysql:///day11</property>

      <property name="user">root</property>

      <property name="password">root</property>

      </default-config>

      <named-config name="c1"> 

       <property name="driverClass">com.mysql.jdbc.Driver</property>

    <property name="jdbcUrl">jdbc:mysql:///day10</property>

    <property name="user">root</property>

    <property name="password">root</property>

      </named-config>

        <named-config name="c2"> 

       <property name="driverClass">com.mysql.jdbc.Driver</property>

    <property name="jdbcUrl">jdbc:mysql:///day09</property>

    <property name="user">root</property>

    <property name="password">root</property>

      </named-config>

    </c3p0-config>

    6、配置Tomcat数据源

    查看Tomcat文档,示例代码:

    <Context>

      <Resource name="jdbc/datasource" auth="Container"

                type="javax.sql.DataSource" username="root" password="root"

                driverClassName="com.mysql.jdbc.Driver" 

          url="jdbc:mysql://localhost:3306/jdbc"

                maxActive="8" maxIdle="4"/>

    </Context>

    Context initCtx = new InitialContext();

    Context envCtx = (Context) initCtx.lookup("java:comp/env");

    dataSource = (DataSource)envCtx.lookup("jdbc/datasource");

    特别提醒:此种配置下,驱动jar文件需放置在tomcatlib

    只有在servlet/jsp中才可以使用jndi机制

    操作步骤

    1、配置使用tomcat 内置连接池 配置<context> 元素 

    context元素有三种常见配置位置

    1) tomcat/conf/context.xml 所有虚拟主机,所有工程都可以访问该连接池 

    2) tomcat/conf/Catalina/localhost/context.xml 当前虚拟主机(localhost)下所有工程都可以使用该连接池

    3) 当前工程/META-INF/context.xml 只有当前工程可以访问该连接池 

    <Context>

      <Resource name="jdbc/EmployeeDB" auth="Container"

                type="javax.sql.DataSource" username="root" password="abc"

                driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql:///day14"

                maxActive="8" maxIdle="4"/>

    </Context>

    必须先将mysql驱动jar包 复制tomcat/lib下 

    tomcat启动服务器时,创建连接池对象,绑定 jdbc/EmployeeDB 指定名称上 

    2、通过运行在JNDI容器内部的程序(Servlet/JSP)去访问tomcat内置连接池 

    Context context = new InitialContext();

    Context envCtx = (Context)context.lookup("java:comp/env"); 固定路径

    DataSource datasource = (DataSource) envCtx.lookup("jdbc/EmployeeDB"); 通过绑定名称,查找指定java对象 

    =====================================================================补充知识:

    Context中配置数据源,有五个位置可以配置,参考tomcat文档

    ~conf/context.xml爸爸Context中配置,这个配置将被tomcat的所有web应用共享

    In the $CATALINA_BASE/conf/context.xml file: the Context element information will be loaded by all webapps.

    ~conf/Catalina/localhost/context.xml,这个配置将被当前虚拟主机所共享

    In the $CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default file: the Context element information will be loaded by all webapps of that host.

    ~conf/Catalina/localhost/XXXXXX.xml,这是配置web应用的对外访问路径,这个配置只对当前web应用起作用

    In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The name of the file (less the .xml extension) will be used as the context path. Multi-level context paths may be defined using #, e.g. foo#bar.xml for a context path of /foo/bar. The default web application may be defined by using a file called ROOT.xml.

    ~web应用个的META-INF目录下创建context.xml这个配置只对当前web应用起作用

    Only if a context file does not exist for the application in the $CATALINA_BASE/conf/[enginename]/[hostname]/, in an individual file at /META-INF/context.xml inside the application files. If the web application is packaged as a WAR then /META-INF/context.xml will be copied to $CATALINA_BASE/conf/[enginename]/[hostname]/ and renamed to match the application's context path. Once this file exists, it will not be replaced if a new WAR with a newer /META-INF/context.xml is placed in the host's appBase.

    ~conf/servler.xmlHost标签下配置Context标签

    Inside a Host element in the main conf/server.xml.

    4Cotext中配置:

      <Resource name="mySource"  ---在数据源创建好以后绑定到jndi容器中时使用的名字

                auth="Container" 

                type="javax.sql.DataSource" ---当前对象的类型,默认就是数据源

                username="root"  --- 数据库用户名

                password="root"  --- 数据库密码

                driverClassName="com.mysql.jdbc.Driver" ---数据库驱动名

                url="jdbc:mysql:///day12" --- 数据库连接信息

                maxActive="8" --- 最大连接数

                maxIdle="4"/> --- 最大空闲连接数

     5在程序中获取数据源:

      Context context = new InitialContext();

    Context envCtx = (Context)context.lookup("java:comp/env"); 

    DataSource datasource = (DataSource) envCtx.lookup("mySource");

    7JNDI技术简介

    1JNDI(Java Naming and Directory Interface)Java命名和目录接口,它对应于J2SE中的javax.naming包,

    2这套API的主要作用在于:它可以把Java对象放在一个容器中(支持JNDI容器 Tomcat),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需通过名称检索即可。

    3其核心APIContext,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。

    4原来由jdbcUtil创建连接,现在由dataSource创建连接,为实现不和具体数据为绑定,因此datasource也应采用配置文件的方法获得连接。

  • 相关阅读:
    【百度地图API】如何快速创建带有标注的地图?——快速创建地图工具+如何标注商家
    【百度地图API】百度做了一个艰难的决定——取消密钥机制!!
    【设计师工具】3个好用的在线配色工具
    【百度地图API】建立全国银行位置查询系统(二)——怎样为地图添加控件
    【百度地图API】如何在地图上添加标注?——另有:坐标拾取工具+打车费用接口介绍
    【百度地图API】多家地图API文件大小对比
    “街坊”房产数字平台,昔日的思想,曾经的努力
    软件工程之感想
    .net执行性能,Winform性能优化?如何提高.net程序性能
    个人之思考整理
  • 原文地址:https://www.cnblogs.com/aukle/p/3217776.html
Copyright © 2020-2023  润新知