第三十三天:JDBC高级 DataSource连接池(引入设计者模式,静态代理,动态代理)

1. 数据源

1.1 概念

初始化并维护多个连接对象,当其他地方需要时,从连接池获取;用完之后,归还到连接池。以此实现连接的复用,提高效率。

1.2 池化思想(重要)

以空间换时间的做法。

游戏背包、新闻客户端。

  1. 提供更好的使用体验
  2. 对资源的消耗会更少。不会频繁的创建和销毁对象。

0

1.3 自定义数据源思路

自定义一个连接池的整体思路

  1. 准备一个保存多个连接的容器ArrayList

  2. 一开始就创建多个连接,并存入上述容器

  3. 自己写一个类,封装上述的容器ArrayList对象,对外提供获取连接、归还链接的方法(封装了ArrayList的相关方法)

1.4 自定义数据源实现

实现获取连接的方法MyDataSource

//1.准备一个容器。用于保存多个数据库连接对象
// DateSource类中维护的容器才是真正的连接池
// DataSource(数据源)是一个维护并管理连接池的一个类
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

//2.定义静态代码块,获取多个连接对象保存到容器中
static{
    for(int i = 1; i <= 10; i++) {
        Connection con = JDBCUtils.getConnection();
        pool.add(con);
    }
}

//3.重写getConnection方法,用于返回一个连接对象
// 存在线程安全的隐患
@Override
public Connection getConnection() throws SQLException {
    if(pool.size() > 0) {
        Connection con = pool.remove(0);
        return con;
    }else {
        throw new RuntimeException("连接数量已用尽");
    }
}

//4.提供一个获取连接池大小的方法
public int getSize() {
    return pool.size();
}

测试

所有测试连接池的代码完全一样,可以复用之前的MyDataSourceTest

public class MyDataSourceTest {
    public static void main(String[] args) throws Exception{
        //1.创建连接池对象
        MyDataSource dataSource = new MyDataSource();

        System.out.println("使用之前的数量:" + dataSource.getSize());

        //2.通过连接池对象获取连接对象
        Connection con = dataSource.getConnection();
        // class com.mysql.jdbc.JDBC4Connection
        System.out.println(con.getClass());

        //3.查询学生表的全部信息
        String sql = "SELECT * FROM student";
        PreparedStatement pst = con.prepareStatement(sql);

        //4.执行sql语句,接收结果集
        ResultSet rs = pst.executeQuery();

        //5.处理结果集
        while(rs.next()) {
            System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
        }

        //6.释放资源
        rs.close();
        pst.close();
        con.close();    // 用完以后,关闭连接
        // dataSource.close(con);


        // 归还思路:
        /*
            1. 为MyDataSource添加一个归还的方法,传递连接这个参数,实现归还 dataSource.close(con);

            上面做法可以实现,但是编码规范不完美,我们要做的是使用connection自己的close方法,
            方法的实现由原来的释放资源,变成归还链接本身,接下来要做的就是增强(修改)close()

            class com.mysql.jdbc.JDBC4Connection是mysql的jar包中提供的类,他的close方法已经写死了,不能修改!
            
		保证从数据源中获取的链接对象是自己写的connection对象
            2. 自己写一个connection类,继承JDBC4Connection,可以继承并增强close方法,此路不通。
            3. 自己写一个connection类,直接实现Connection接口,自己写close方法,实现归还逻辑
            4. 自己写一个connection类,想办法只实现close方法,其他的方法我们继续调用JDBC4Connection的方法(静态代理)
            5. 动态代理


         */


        System.out.println("使用之后的数量:" + dataSource.getSize());
    }
}

1.5 归还连接的思路分析

// 归还思路:

// 思路1. 为MyDataSource添加一个归还的方法,传递连接这个参数,实现归还 
// dataSource.close(con);

// 4.提供一个归还连接的方法的方法
public void close(Connection con) {
    pool.add(con);
}
// 这种思路下:测试类中,不要再使用connection对象的close方法,而是调用MyDataSource对象的close

上面做法可以实现,但是编码规范不完美,我们想要使用的是 用connection自己的close方法,
方法的实现由原来的释放资源,变成归还链接,接下来要做的就是增强(修改)close()方法

        1. class com.mysql.jdbc.JDBC4Connection是mysql的jar包中提供的类,他的close方法已经写死了,不能修改!

        2. 自己写一个connection类,继承JDBC4Connection,可以继承并增强close方法
        	只要保证从数据源中获取的连接对象是我们自己写的子类connection类对象就可以了
        3. 自己写一个connection类,直接实现Connection接口,自己写close方法,实现归还逻辑(装饰者模式、静态代理)
        	我们只关心close方法,但是其他所有的抽象方法,都需要我们实现;我们实现的时候是调用原来jdbc4Connection对象的方法。
        4. 自己写一个connection类,想办法只实现close方法,其他的方法我们继续调用JDBC4Connection的方法(模板方法模式,静态代理)
        	我们就搞一个中间类,中间类中实现除close方法之外的其他方法,在这些方法中调用JDBC4Connection的对象,自己写的链接类,继承中间类,只实现close方法即可。
        5. 动态代理
                
                
                
                /*
                
                
                	华仔  优秀的艺人  Ctrl      经纪人

				开始的时候
					演戏唱歌跳舞 都直接找华仔
					
                有了经纪人之后
                	演戏唱歌跳舞 开始找经纪人 (谈合同、日常安排  售票    影迷互动)
                	
                	
                	经纪人以华仔的名义做了上述工作,但是不能替代的就是Ctrl这些
                	
                	
               静态代理
               		经纪人对外提供统一的服务,有Ctrl相关业务,直接找经纪人;经纪人可以直接做的,就自己完成;如果自己不能完成的,让华仔做。
               		
               		静态:这个经纪人(代理人)真是存在
               		动态:这个经纪人(代理人)是个虚拟的


				华仔 ==>   被代理对象(目标对象)
				代理人  ==>  代理对象
				
				之后所有的代码调用,直接找代理对象调用,该代理对象如果能自己完成,就自己做
				如果不能自己完成,找目标对象完成。
                **/
                
	/*
		静态代理
			在不修改目标对象(方法)代码的前提下,增强目标对象的功能。
	
	
	*/                

1.6 继承实现(此路不通)

MyConnection1

/*
    自定义的连接对象
    1.定义一个类,继承JDBC4Connection
    2.定义Connection连接对象和容器对象的成员变量
    3.通过有参构造方法为成员变量赋值
    4.重写close方法,完成归还连接
 */
public class MyConnection1 extends JDBC4Connection{//1.定义一个类,继承JDBC4Connection
    //2.定义Connection连接对象和容器对象的成员变量
    private Connection con;
    private List<Connection> pool;

    //3.通过有参构造方法为成员变量赋值
    public MyConnection1(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url,Connection con,List<Connection> pool) throws SQLException {
        super(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
        this.con = con;
        this.pool = pool;
    }

    //4.重写close方法,完成归还连接
    @Override
    public void close() throws SQLException {
        pool.add(con);
    }
}

MyDataSource

public class MyDataSource implements DataSource {
    //1.准备一个容器。用于保存多个数据库连接对象
    // DateSource类中维护的容器才是真正的连接池
    // DataSource(数据源)是一个维护并管理连接池的一个类
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    //2.定义静态代码块,获取多个连接对象保存到容器中
    static{
        for(int i = 1; i <= 10; i++) {
            Connection con = JDBCUtils.getConnection();
            pool.add(con);
        }
    }

    //4.提供一个获取连接池大小的方法
    public int getSize() {
        return pool.size();
    }


    //3.重写getConnection方法,用于返回一个连接对象
    @Override
    public Connection getConnection() throws SQLException {
        if(pool.size() > 0) {
            Connection con = pool.remove(0);
			
            // 无法让DriverManager的getConnection的方法返回MyConnection1类型的对象
            // 所以此路不通。
            return myCon;
        }else {
            throw new RuntimeException("连接数量已用尽");
        }
    }

1.7 装饰者模式实现

设计模式(问题的解决方案)

为了解决开发 过程中遇到的某一类问题的解决方案

1.7.1 概念分析

装饰者模式,又称装饰模式,本质上是代理(代理增强的一种方式)。

代理分为:静态代理和动态代理

静态代理:在不修改目标对象(方法)源代码的前提下,对其进行功能增强。

/*
// 华仔 唱歌 演电影   ctrl  xuanchuan
// 华仔因为不火  所以找经济人帮他宣传
// 经纪人   -   代理华仔   -  代理对象	-  只做宣传工作 - MyCOnnection2
// 华仔	 -    被经纪人代理 - 被代理对象 - ctrl		- JDBC4Connection

// 经纪人在外面就代表了华仔,所有华仔会的动作,经纪人也要会,但是可以不用自己(经纪人)做(ctrl华仔来做)
// 他们实现相同的接口就可以达到这个效果
// 所以(静态/动态)代理要求被代理的对象必须实现了接口,代理类实现这个接口,增强也只能增强接口里面的方法。

// 经纪人真是存在  -  静态代理
// 经纪人不需要人来做了,通过AI合成虚拟人,根据你的时机情况,自动帮你营销  - 动态代理

经纪人{
    华仔

    宣传();  //经纪人自己宣传营销,也就是增强了华仔的营销宣传。
    // ctrl
    ctrl{
    	华仔.ctrl();  // ctrl让华仔做,更专业
    }
       
}    

MyCOnnection2{
    JDBC4Connection

    close();  //经纪人宣传营销  -- 重写并增强close方法
    // ctrl 
    JDBC4Connection.除了close的所有方法(); // 华仔ctrl ---  close之外的所有方法    
} 
*/

20201203145116796

1.7.2 设计模式代码演示

演员接口Actor.java

/*
    演员接口,有两种功能:
        1. Ctrl
        2. 宣传……
 */

public interface Actor {

    // ctrl
    void ctrl();

    // 宣传
    void close();
}

演员华仔HuazaiActor.java

// 华仔,擅长ctrl,不擅宣传
public class HuazaiActor implements Actor {

    // 擅长ctrl
    public void ctrl() {
        System.out.println("ctrl.....非常燃  huazai");
    }

    // 不擅宣传
    public void close() {
        System.out.println("我宣传的不好 huazai");
    }
}

经纪人ProxyActor.java

// 经纪人擅长宣传,不会ctrl;经纪人宣传,让华仔ctrl
public class ProxyActor implements Actor {


    //2. 定义一个原有对象的成员变量,
    // 经纪人干不完所有的是,ctrl这些需要华仔来干,所以经纪人对象内部持有一个华仔对象
    private Actor target;

    // 通过有参构造为成员变量赋值
    public ProxyActor(Actor target) {
        this.target = target;
    }

    // ctrl 华仔擅长,让华仔干
    @Override
    public void ctrl() {
        target.ctrl();
    }

    // 谈合同宣传  代理擅长,自己来
    @Override
    public void close() {
        System.out.println("宣传我行  proxy");

    }
}

测试类中开始演出ActorTest.java

public class ActorTest {

    // 演出的时候,由经纪人统一协调安排,都找经纪人。
    // 经纪人干的来的,自己干;干不来的,让华仔干
    public static void main(String[] args) {

        // 华仔 目标对象
        HuazaiActor target = new HuazaiActor();

        // 经纪人 代理对象 
        ProxyActor proxyActor = new ProxyActor(target);

        // 宣传 本质是经纪人干的
        proxyActor.close();
        
        // ctrl  本质是华仔干的
        proxyActor.ctrl();


    }
}
1.7.3 增强close方法

MyConnection2

/*
    1.定义一个类,实现Connection接口
    2.定义连接对象和连接池容器对象的成员变量
    3.通过有参构造方法为成员变量赋值
    4.重写close方法,完成归还连接
    5.剩余方法,还是调用原有的连接对象中的功能即可
 */
//1.定义一个类,实现Connection接口
public class MyConnection2 implements Connection{

    //2.定义连接对象和连接池容器对象的成员变量
    private Connection con;
    private List<Connection> pool;

    //3.通过有参构造方法为成员变量赋值
    // con  从池子中取出来的jdbc4Connection
    // pool  池子
    public MyConnection2(Connection con,List<Connection> pool) {
        this.con = con;
        this.pool = pool;
    }

    //4.重写close方法,完成归还连接
    @Override
    public void close() throws SQLException {
        pool.add(con);
    }

    //5.剩余方法,还是调用原有的连接对象中的功能即可
	// 此处省略N个方法的实现
    // 这些方法中都是通过调用原来JDBC4Connection对象的方法
   /* 
    MyCOnnection2代理了JDBC4Connection,
        MyCOnnection2、JDBC4Connection都实现了Connection接口,都具有了相同的方法(实现于Connection接口)
        MyCOnnection2在实现的时候,除了close()方法之外,其他的所有方法都是找了JDBC4Connection来干的;
   */
        
}

测试类

public static void main(String[] args) throws Exception{
    //1.创建连接池对象
    MyDataSource dataSource = new MyDataSource();

    System.out.println("使用之前的数量:" + dataSource.getSize());

    //2.通过连接池对象获取连接对象
    Connection con = dataSource.getConnection();
    System.out.println(con.getClass());

    //3.查询学生表的全部信息
    String sql = "SELECT * FROM student";
    // 这里的prepareStatement,最终调用的值MyConnection2中con<JDBC4Connetcion对象>的方法(原来的方法)
    PreparedStatement pst = con.prepareStatement(sql);

    //4.执行sql语句,接收结果集
    ResultSet rs = pst.executeQuery();

    //5.处理结果集
    while(rs.next()) {
        System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
    }

    //6.释放资源
    rs.close();
    pst.close();
    con.close();    // 把这个连接归还到连接池中

    // dataSource.returnCon(con);
    /*
            归还思路:
                1. 直接修改connection对象所属类的方法,改成归还到连接池
                     需要修改第三方jar包的源码 不选用
                2. 在连接池管理类DataSource中,定义一个归还的办法 dataSource.returnCon(con);
                    不符合我们常规的归还方式,不选用。


                   最终想通过使用connection对象的close()方法实现归还连接到连接池,
                   白话:增强connection的close()方法

                3. 继承,在之类中增强(此路不通)
                    因为需要自定的内容太多,很多的类(DriverManager....)都需要被增强,不现实
                4. 装饰者模式
                	问题:自定义的connection类直接实现connection接口,需要实现的无关方法太多
                5. 适配器模式
                	
                6. 动态代理

        */

    System.out.println("使用之后的数量:" + dataSource.getSize());
}
1.7.4 该方式缺陷

在自定义的Connection实现类MyConnection2中,我们只关注close方法,但是在重写close方法的同时,我们写代码实现了大量自己不需要重点关注的方法。

1.8 模板方法模式

1.8.1 概念

当写一个类实现某个接口时,如果有大量不需要重点关注的方法需要重写,可以把这些方法抽取到一个抽象类中统一重写;

自己写的类只需要继承上述抽象类,在自己写的类中重点重写自己关注的方法。

20201203145733504

1.8.2 设计模式代码演示

目标接口Inter.java

public interface Inter{
    void method1();
    void method2();
    void method3();
    void method4();
    void method5();
}

中间抽象类GenericInter.java

public abstract class GenericInter implements Inter{
    // 可以不实现method1 方法
    
    void method2(){
    	// 实现逻辑
    }
    void method3(){
    	// 实现逻辑
    }
    void method4(){
    	// 实现逻辑
    }
    void method5(){
    	// 实现逻辑
    }
}

最终的子类InterImpl.java只重写method1方法

`

public interface InterImpl extends GenericInter{
    void method1(){
     // 实现逻辑   
    }
}
1.8.4 增强close方法

MyAdapter

/*
    1.定义一个适配器类。实现Connection接口
    2.定义连接对象的成员变量
    3.通过有参构造为变量赋值
    4.重写所有的抽象方法(除了close)
 */
public abstract class MyAdapter implements Connection {

    //2.定义连接对象的成员变量
    private Connection con;

    //3.通过有参构造为变量赋值
    public MyAdapter(Connection con) {
        this.con = con;
    }


    //4.重写所有的抽象方法(除了close)
}

// MyAdapter  + MyConnection3 = MyConnection2
// 理解简单,写起来麻烦

MyConnection3

/*
    1.定义一个类,继承适配器类
    2.定义连接对象和连接池容器对象的成员变量
    3.通过有参构造为变量赋值
    4.重写close方法,完成归还连接
 */
//1.定义一个类,继承适配器类
public class MyConnection3 extends MyAdapter {

    //2.定义连接对象和连接池容器对象的成员变量
    private Connection con;
    private List<Connection> pool;

    //3.通过有参构造为变量赋值
    public MyConnection3(Connection con,List<Connection> pool) {
        super(con);
        this.con = con;
        this.pool = pool;
    }

    //4.重写close方法,完成归还连接
    @Override
    public void close() {
        pool.add(con);
    }
}
1.8.5 该方式缺点

MyAdapter + MyConnection3 = MyConnection2 // 理解简单,写起来麻烦

代码量 相对于装饰者模式的静态代理实现方式,并没有降低。

1.9 动态代理

1.9.1 概念分析

动态代理是装饰者模式的一种表现形式

静态代理:在不修改目标对象(方法)源代码的前提下,对其进行功能增强。

动态代理:程序运行期间,在不修改目标对象(方法)源代码的前提下,动态的对其进行功能增强。

1.9.2 注意事项
  1. JDK原生支持动态代理,但是要求被代理对象必须实现了接口,增强的也是目标对象从父接口中继承的方法
  2. JDK动态代理会拦截目标对象的所有方法
    • 所有方法,指的是所有从父接口中继承的方法
    • 目标对象的所有方法的执行都会经过invocationHandler(调用处理器)对象的invoke方法
1.9.3 动态代理演示代码
  • 共同父接口StudentInterface

    public interface StudentInterface {
        void eat(String name);
        void study();
    }
    
  • 被代理的类Student

    public class Student implements StudentInterface{
        public void eat(String name) {
            System.out.println("学生吃" + name);
        }
    
        public void study() {
            System.out.println("在家自学");
        }
    }
    
  • 动态代理编写和测试JDKProxy

    public class Test {
        public static void main(String[] args) {
            Student stu = new Student();
            /*stu.eat("米饭");
            stu.study();*/
    
            /*
                要求:在不改动Student类中任何的代码的前提下,通过study方法输出一句话:来图书馆学习
                类加载器:			 和被代理对象使用相同的类加载器
                接口类型Class数组:	和目标对象使用相同接口的字节码对象数组
                InvocationHandler:	调用处理器对象,真正的增强或者调用目标方法的逻辑写在其内部的invoke方法中
    
             */
            StudentInterface proxyStu =
                    (StudentInterface) Proxy.newProxyInstance(
                            stu.getClass().getClassLoader(),
                            new Class[]{StudentInterface.class/*,xxx.class*/},
                            new InvocationHandler() {
                /*
                    执行Student代理类中所有的方法都会经过invoke方法
                    对method方法进行判断
                        如果是study,则对其增强(修改)
                        如果不是,还调用学生对象原有的功能即可
                 */
    
                /**
                 invoke可以完成两个工作
                        1. 调用目标方法       method.invoke(stu,args);
                        2. 在调用目标方法前后添加增强代码
                 *
                 * @param proxy     代理对象,这个位置的代理对象是给系统使用
                 * @param method    目标方法的封装对象,也就是目标对象中所有(从父接口中继承)方法
                 * @param args      调用目标方法传递的实参
                 * @return          表示目标方法的返回值,一定要在该方法内部,把调用目标方法获得的返回值return出去,否则外界无法获取该值
                 * @throws Throwable
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if("study".equals(method.getName())) {
                        System.out.println("来图书馆学习");
                        method.invoke(stu,args);
                        return null;
                    }
                    // 通过反射调用指定方法(student中非study的方法)
                    // 调用目标方法 
                    return method.invoke(stu,args);
                   
                }
            });
    
            proxyStu.eat("米饭");
            proxyStu.study();
            
            Student stu = new Student();
            stu.eat("小米粥");
    
        }
    }
    
1.9.4 增强close方法
public class MyDataSource implements DataSource {
    //1.准备一个容器。用于保存多个数据库连接对象
    // DateSource类中维护的容器才是真正的连接池
    // DataSource(数据源)是一个维护并管理连接池的一个类
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    //2.定义静态代码块,获取多个连接对象保存到容器中
    static{
        for(int i = 1; i <= 10; i++) {
            Connection con = JDBCUtils.getConnection();
            pool.add(con);
        }
    }

    //4.提供一个获取连接池大小的方法
    public int getSize() {
        return pool.size();
    }

    /*
        动态代理方式
     */
    @Override
    public Connection getConnection() throws SQLException {
        if(pool.size() > 0) {
            Connection con = pool.remove(0);
			// 通过JDK动态代理生成了一个con的代理对象proxyCon
            Connection proxyCon = (Connection) Proxy.newProxyInstance(
                con.getClass().getClassLoader(), 
                new Class[]{Connection.class}, 
                new InvocationHandler() {

                    /*执行Connection代理类连接对象所有的方法都会经过invoke
                    如果是close方法,归还连接
                    如果不是,直接执行连接对象原有的功能即可
                    proxy:代理对象,给系统用,自己不要用
                    method:每一个代理类的方法执行的时候,经过该invoke方法,都会被封装成一个方法对象赋值给method
                    args:代理对象调用上述method的时候传递的实参列表
                    
                    */

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if("close".equals(method.getName())) {
                        //归还连接
                        pool.add(con);
                        return null;
                    }else {
                        // 调用目标对象的目标方法,使用原来的功能
                        return method.invoke(con,args);
                    }
                }
            });
			
            return proxyCon;
        }else {
            throw new RuntimeException("连接数量已用尽");
        }
    }

    // 以下是数据源接口规定的,作为一个数据源需要重写的N个方法,与我们增强代理JDBC4Connection无关
    // 所以,需要继续重写一下几个方法
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
1.9.5 该方式缺点

不好写,以后框架会帮我们自动封装。

动态代理

  • JDK动态代理,只能对接口或者接口的实现类进行增强。为目标对象生成一个兄弟对象,在兄弟对象中做增强。
  • CGLIB代理,基于父类的代理。目标对象生成一个子类对象,在子类中增强父类功能。

2. 第三方数据源

2.1 C3P0

导包

c3p0-0.9.5.2.jar
mchange-commons-java-0.2.12.jar

准备配置文件c3p0-config.xml,配置文件名字固定,内容中标签和name值固定。

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://192.168.59.129:3306/db14</property>
    <property name="user">root</property>
    <property name="password">itheima</property>
    
    <!-- 连接池参数 -->
    <!--初始化的连接数量-->
    <property name="initialPoolSize">5</property>
    <!--最大连接数量-->
    <property name="maxPoolSize">10</property>
    <!--超时时间-->
    <property name="checkoutTimeout">3000</property>
  </default-config>
</c3p0-config>

测试代码

public class C3P0Test1 {
    public static void main(String[] args) throws Exception{
        //1.创建c3p0的数据库数据源对象
        DataSource dataSource = new ComboPooledDataSource();

        //2.通过数据源对象获取数据库连接
        Connection con = dataSource.getConnection();

        //3.执行操作
        String sql = "SELECT * FROM student";
        PreparedStatement pst = con.prepareStatement(sql);

        //4.执行sql语句,接收结果集
        ResultSet rs = pst.executeQuery();

        //5.处理结果集
        while(rs.next()) {
            System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
        }

        //6.释放资源
        rs.close();
        pst.close();
        con.close();
    }
}

C3P0相关知识点测试

public class C3P0Test2 {
    public static void main(String[] args) throws Exception{
        //1.创建c3p0的数据库连接池对象
        DataSource dataSource = new ComboPooledDataSource();

        //2.测试
        for(int i = 1; i <= 11; i++) {
            Connection con = dataSource.getConnection();
            System.out.println(i + ":" + con);

            if(i == 5) {
                con.close();
            }
        }
    }
}

2.2 Druid

导包

druid-1.0.9.jar

properties配置文件(名字任意),但是配置文件中key的值固定。

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.59.129:3306/db14
username=root
password=itheima
# 初始化连接数量
initialSize=5
# 最大连接数量
maxActive=10
# 超时时间
maxWait=3000

测试

/*
    1.通过Properties集合,加载配置文件
    2.通过Druid连接池工厂类获取数据库连接池对象
    3.通过连接池对象获取数据库连接进行使用
 */
public class DruidTest1 {
    public static void main(String[] args) throws Exception{
        //获取配置文件的流对象
        // 从当前项目的类路径下读取。类路径:
        // 非web项目 out\production\项目, 不是src路径
        // web项目 out\artifacts\项目, 不是src路径
        
        // new FileInputStream(new File("绝对路径"))  可以用,但是需要根据项目所在位置不断修改该绝对路径
        // classLoader().getResourceAsStream  推荐用,会从当前类路径下(src下)加载配置文件,不受项目所在位置的影响
        InputStream is = DruidTest1.class.getClassLoader().getResourceAsStream("druid.properties");

        //1.通过Properties集合,加载配置文件
        Properties prop = new Properties();
        prop.load(is);

        //2.通过Druid连接池工厂类获取数据库数据源对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //3.通过数据源对象获取数据库连接进行使用
        Connection con = dataSource.getConnection();


        String sql = "SELECT * FROM student";
        PreparedStatement pst = con.prepareStatement(sql);

        //4.执行sql语句,接收结果集
        ResultSet rs = pst.executeQuery();

        //5.处理结果集
        while(rs.next()) {
            System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + "\t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
        }

        //6.释放资源
        rs.close();
        pst.close();
        con.close();
    }
}

2.3 使用Druid优化工具类

/*
    数据库数据源的工具类
 */
public class DataSourceUtils {
    //1.私有构造方法
    private DataSourceUtils() {
    }

    //2.声明数据源变量
    private static DataSource dataSource;

    //3.提供静态代码块,完成配置文件的加载和获取数据库连接池对象
    static {
        try {
            //完成配置文件的加载
            InputStream is = DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");

            Properties prop = new Properties();
            prop.load(is);

            //获取数据库连接池对象
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //4.提供一个获取数据库连接的方法
    public static Connection getConnection() {
        Connection con = null;
        try {
            con = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    //5.提供一个获取数据库连接池对象的方法
    public static DataSource getDataSource() {
        return dataSource;
    }

    //6.释放资源
    public static void close(Connection con, Statement stat, ResultSet rs) {

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }


        if (stat != null) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    public static void close(Connection con, Statement stat) {
        close(con, stat, null);
    }
}

{
e.printStackTrace();
}
}

//4.提供一个获取数据库连接的方法
public static Connection getConnection() {
    Connection con = null;
    try {
        con = dataSource.getConnection();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return con;
}

//5.提供一个获取数据库连接池对象的方法
public static DataSource getDataSource() {
    return dataSource;
}

//6.释放资源
public static void close(Connection con, Statement stat, ResultSet rs) {

    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    if (stat != null) {
        try {
            stat.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

public static void close(Connection con, Statement stat) {
    close(con, stat, null);
}

}














  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值