数据库连接池

来源:互联网 发布:js last indexof的用法 编辑:程序博客网 时间:2024/05/29 17:22
 

数据连接池的基本实现

1、  实现途径:

编写JdbcPool implements java.sql.DataSource类

l  静态初始化块

l  getConnection()

l  release()

总结:

可以解决连接池的实现问题,但是必须要求编程人员熟悉JdbcPool的使用

解决此问题的方法——增强Connection的功能

 

2、  方案列表:

1)        编写Connection的子类,此方法理论上可以解决,但是没有可操作性,因为基本无法实现对Connection对象的初始化工作

2)        采用装饰模式

装饰模式解决方案

用包装设计模式对connnction的close方法进行增强

1.写一个类实现与被增强对象相同的接口

2.在类中定义一个变量记住被增强对象

3.在类中定义一个构造函数,接收被增强对象

4.覆盖想增强的方法

5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法

 

总结:

装饰模式可以很好的解决问题,但是在此任然不合适,因为Connection接口中定义了太多的方法,逐个去实现非常繁琐

 

3)        动态代理技术实现

       public Connection getConnection() throws SQLException {

             

              if(list.size()>0){

                     final Connection conn = list.removeFirst();  //mysql

                     System.out.println("用户从池中拿走了:" +  conn);

                     System.out.println("池的大小为" + list.size());

                    

                     //myconnection   preparedstatement  commit close

                     return (Connection)Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){

 

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

                                          throws Throwable {

                                   if(!method.getName().equalsIgnoreCase("close")){

                                          return method.invoke(conn, args);

                                   }

                                   System.out.println(conn + "被还到池中了");

                                   list.add(conn);

                                   System.out.println("池的大小为" + list.size());

                                   return null;

                            }

                     });

                    

                    

              /*    MyConnection myconn = new MyConnection(conn,list);

                     return myconn;    //   conn = pool.getConnection();  conn.preparedstatment  conn

*/           }else{

                     throw new RuntimeException("对不起,数据库忙,请等会再来!!");

              }

       }

 

代理模式

代理模式的作用:

为其他对象提供一种代理以控制对这个对象的访问。(在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用)

l  抽象角色:声明真实对象和代理对象的公共接口。

l  代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真是对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

l  真实角色:代理角色所代表的真实对象,是我们要真正要引用的对象。

 

Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1) InvocationHandler接口,是代理实例的调用处理程序实现的接口。 它只有一个方法:invoke(Object proxy, Method method, Object[] args)。我们需要在实现InvocationHandler接口的具体类中的invoke方法内,编写代理行为的具体逻辑。然后将这个InvocationHandler对象传递给Proxy类中生成一个动态的代理对象。

(2) Proxy 类,提供用于创建动态代理类和实例的静态方法。其最重要的两个静态创建方法:
        Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
        Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

invoke Object invoke(Objectproxy, Methodmethod,Object[] args) throwsThrowable

在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

参数

proxy - 在其上调用方法的代理实例

method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。

返回

从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出 NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出 ClassCastException。

 


DBCP

DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要3个包:

common-dbcp.jar,

common-pool.jar

,common-collections.jar

由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

 

操作步骤

1、赋值jar包及dbconfig.properties文件

2、修改配置文件

3、  修改DBManager文件

a)         静态初始化块,加载配置文件

b)        DataSource ds =

BasicDataSourceFactory.createDataSource(prop);

c)         修改getConnection()

public static Connection getConnection()throws SQLException{

       return ds.getConnection();

}

3、在数据库操作中任然使用DBManager的getConnection和release方法即可

 


C3P0

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

 

1、  复制jar文件

c3p0-0.9.2-pre1.jar

mchange-commons-0.2.jar

2、  创建DBManager_c3p0

ds = new ComboPooledDataSource();

      

ds.setDriverClass("com.mysql.jdbc.Driver");

ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");

ds.setUser("root");

ds.setPassword("admin");

 

ds.setInitialPoolSize(20);

ds.setMaxPoolSize(40);

ds.setMinPoolSize(10);

 

3、  测试代码

 

解决c3p0配置问题

1、  在src目录下创建c3p0-config.xml文件,在c3p0文档中找到配置文件案例代码复制到xml中,格式化代码。

2、  修改xml文件,添加driverClass, jdbcUrl, user, password四个属性如下

<c3p0-config>

    <default-config>

       <property name="automaticTestTable">con_test</property>

       <property name="checkoutTimeout">30000</property>

       <property name="idleConnectionTestPeriod">30</property>

       <property name="initialPoolSize">10</property>

       <property name="maxIdleTime">30</property>

       <property name="maxPoolSize">100</property>

       <property name="minPoolSize">10</property>

       <property name="maxStatements">200</property>

    </default-config>

   

    <named-config name="mysql">

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

       <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>

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

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

   

       <property name="acquireIncrement">5</property>

       <property name="initialPoolSize">10</property>

       <property name="minPoolSize">5</property>

       <property name="maxPoolSize">30</property>

    </named-config>

</c3p0-config>

 

3、  修改DBManager_c3p0

try{

    ds = new ComboPooledDataSource("mysql");

}catch (Exception e) {

    throw new ExceptionInInitializerError(e);

}

4、  测试代码

 

c3p0与dbcp区别

  dbcp没有自动的去回收空闲连接的功能

c3po有自动回收空闲连接功能

 

 

JNDI

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API。命名服务将名称和对象联系起来,使得我们可以用名称访问对象。目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性。

 

配置JNDI

(tomcat文档中有说明和案例,可以打开localhost:8080查看)

 

l  途径一:

在tomcat服务器的server.xml文件中过的host中加入<context> …</context>

<Context path=” /DataSource_JNDI_Test”

docBase=”webapps/DataSource_JNDI_Test”>

  <Resource name="jdbc/TestDB"

            auth="Container"

            type="javax.sql.DataSource"           

            driverClassName="com.mysql.jdbc.Driver"

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

            username="root"

            password="admin"

            maxActive="8"

            maxIdle="4"/>

</Context>

 

l  途径二:

在web工程中的添加context.xml文件

步骤

1、  在myecipse的web项目的META-INF目录下创建context.xml,内容如下:

<Context>

  <Resource name="jdbc/TestDB"

            auth="Container"

            type="javax.sql.DataSource"           

            driverClassName="com.mysql.jdbc.Driver"

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

            username="root"

            password="admin"

            maxActive="8"

            maxIdle="4"/>

</Context>

 

2、  加载连接池,代码如下

//初始化jndi容器

Context initCtx = new InitialContext();

 

//检索出jndi容器Context envCtx = (Context) initCtx.lookup("java:comp/env");

 

//从容器中找到连接池

DataSource ds = (DataSource) envCtx.lookup("jdbc/TestDB");

conn = ds.getConnection();

conn.close();

 

3、  讲mysql的驱动包复制到tomcat的lib目录下

4、  启动服务器,测试

原创粉丝点击