连接池——Druid、c3p0、动态代理

其实Java程序与MySQL数据库连接时,创建连接对象是最消耗资源的

然后而每次使用完就关闭然后需要的时候又开启,就会非常消耗内存资源

所以可以将不用的连接对象存放在一个容器中,而不是真正的关闭释放

 

连接池是创建和管理数据库连接的缓冲池技术

连接池就是一个容器,连接池中保存了一些数据库连接,这些连接是可以重复使用的

 

创建一个自定义连接池对象:

1.类实现DataSource接口,并重写DataSource所有抽象方法

2.实现类中要定义initCount(初始化连接个数),maxCount(最大存放连接个数),curCount(当前有连接个数)

3.定义一个LinkedList集合用于存放连接池中可用的连接

4.给连接池对象的构造方法体中,每次创建连接池对象,自动创建initCount个连接放入LinkedList集合中

5.定义一个创建连接的方法,每创建一个连接对象就要curCount++

6.关闭连接对象,不是真正的关闭连接而是将连接对象放回连接池中

public class ConnectionPool implements DataSource {
    private int initCount = 3;            //初始化连接池时,连接个数
    private int maxCount = 10;            //连接池最大容纳的连接数
    private int curCount = 0;             //当前连接池拥有连接数

    private LinkedList<Connection> list = new LinkedList<>();    

    public ConnectionPool() {
        for (int i = 0; i < initCount; i++) {
            Connection conn = createConnection();
            list.add(conn);
        }
    }

    public Connection createConnection() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/webdb2";
            String user = "root";
            String pwd = "abcd";
            Connection conn = DriverManager.getConnection(url, user, pwd);
            curCount++;
            return conn;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Connection getConnection() throws SQLException {
        if (list.size() > 0) {
            Connection conn = list.removeFirst();
            return conn;
        }
        if (curCount < maxCount) {
            Connection conn = createConnection();
            return conn;
        }
        throw new RuntimeException("连接已经使用达到上限");
    }

    public void close(Connection conn) {
        list.add(conn);
    }
}

至此,自定义的连接池就创建好了,要使用连接池中连接对象,可以直接调用getConnection()方法获取即可

我将部分没有使用到的重写方法省略了,自行创建时切记重写所有方法

 

 

动态代理:

为某个类的方法的进行增强

三要素:代理对象,被代理对象(就是要增强方法的那个对象),提供方法的接口

 

创建代理对象:

static  object  newProxyInstance(classLoader  loader , Class[ ] interfaces , InvocationHanlder  h )

loader:目标对象的类加载器,其实使用  本类.class.getClassLoader就可以获取

interfaces:要被代理对象的那个方法接口的class对象

InvocationHanlder:处理器,代理对象的具体操作都由处理器决定

 

创建处理器对象:

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

proxy:就是newProxyInstance()方法返回的代理对象

method:代理对象调用的方法对象

args:代理对象调用方法时传入的参数

 

例:想对连接池中的Connection的close()方法进行增强,让他调用close方法时不是直接关闭资源,而是放回连接池

在这个例子中,三要素中被代理对象就是原来连接池中的连接对象

代理对象就是我刚创建的connectionProxy对象

提供方法的接口就是Connection接口

public Connection createConnection() throws Exception{

        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/webdb2";
        String user = "root";
        String pwd = "abcd";
        Connection conn = DriverManager.getConnection(url, user, pwd);
        
        Connection connectionProxy = (Connection) Proxy.newProxyInstance(ConnectionPool.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                if (method.getName().equals("close")) {
                    list.add((Connection) proxy);
                    return null;
                } else {
                    return method.invoke(conn);
                }
            }
        });
        curCount++;
        return connectionProxy;
    }

我将添加入连接池的所有连接对象都换成了代理对象

这些代理对象在调用close()方法时会将线程放回连接池,而不是直接关闭释放

其他方法仍是原来Connection所使用的方法不变

 

创建代理对象时,传入的本类的类加载器和接口参数,等同于得到的代理对象可以向上转型,用接口来接受对象

则代理对象就可以调用接口中的方法,且每次调用方法时候,都会通过Hanlder处理器

其实没有传入Hanlder处理器参数,代理对象运行接口中的方法也可以,只是方法体的内容都是空的

 

在处理器对象内,一定要有一个明确的被代理对象,例子中明确的代理对象就是conn

然后再用method.getName()获取方法名,当方法名与要增强的方法相同时,自己改写方法执行的语句(其实就是代理对象运行该方法,可是方法体和参数已经不是被代理对象的方法体和参数了)

若是不需要改写的方法,则使用反射中method.invoke()使用代理对象和代理对象传入的参数args,调用方法(其实就是代理对象运行该方法,但是和被代理对象运行是一样的方法体和一样的参数)

 

 

市面上其实已经有已经很成熟的连接池框架供我们使用

c3p0连接池:

使用c3p0先导入jar包,再配置自己欲得到的连接池信息即可

C3P0地址:https://sourceforge.net/projects/c3p0/?source=navbar

C3P0的jar包: c3p0-0.9.1.2.jar

 

参数说明
initialPoolSize初始化连接数
maxPoolSize

最大连接数

checkoutTimeout最大等待时间
maxIdleTime最大空闲回收时间

配置文件:c3p0-config.xml 统一放在源代码src根目录下

<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/webdb2</property>
        <property name="user">root</property>
        <property name="password">abcd</property>

        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">7</property>
        <property name="checkoutTimeout">3000</property>
    </default-config>

    <named-config name="otherc3p0">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/webdb2</property>
        <property name="user">root</property>
        <property name="password">abcd</property>

        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">10</property>
        <property name="checkoutTimeout">3000</property>
    </named-config>
</c3p0-config>

public ComboPooledDataSource()                                                             无参构造使用默认配置

ComboPooledDataSource cpds = new ComboPooledDataSource();

(使用xml中default‐config标签中对应的参数)

 

public ComboPooledDataSource(String configName)                           有参构造使用命名配置

ComboPooledDataSource cpds = new ComboPooledDataSource("otherc3p0");

(configName:xml中配置的名称,使用xml中named‐config标签中对应的参数)

 

public Connection getConnection() throws SQLException                    从连接池中取出一个连接

ComboPooledDataSource cpds = new ComboPooledDataSource("otherc3p0");
Connection conn = cpds.getConnection();

c3p0中的close()已经被动态代理增强,所以直接调用Connection的close()方法即可将连接放回连接池中

 

 

DRUID连接池:

Druid地址:https://github.com/alibaba/druid

DRUID连接池使用的jar包: druid-1.0.9.jar

 

参数说明
initialSize初始化建立连接的个数
maxActive连接池最多连接个数
maxWait最大等待时间,单位毫秒

 

DRUID连接的配置文件时一个Properties文件,同样是放在源代码的src根目录下

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/webdb2
username=root
password=abcd
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

 

使用DRUID连接池,需要自己创建一个Properties对象来加载配置文件

InputStream in = Test.class.getResourceAsStream("/druid.properties");
Properties prop = new Properties();
prop.load(in);
DataSource ds = DruidDataSourceFactory.createDataSource(prop);
Connection conn = ds.getConnection();
conn.close();

使用本类的class类,调用getResourceAsStream()方法,传入参数加上"/"代表根目录

直接获取一个字节输入流对象,再创建properties对象加载该配置文件

就可以调用DataSource ds = DruidDataSourceFactory.createDataSource(prop) 创建连接池对象

同样Druid连接池的连接对象也是代理对象,直接调用close()方法也可以直接将连接对象放回连接池中

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值