JDBC 数据库连接池详解和示例

JDBC数据库连接池

    • 学习目标
    • 数据库连接池
      • 数据库连接池原理
        • 第一步
        • 第二步
        • 第三步
        • 第四步
        • 第五步
    • DBCP
      • DBCP参数
      • 方法1
      • 方法2
    • C3P0
      • 方法1
      • 方法2
    • DbUtils
      • QueryRunner核心类
      • ResultSetHandler结果集处理类
      • 案例
      • 查询
      • 其他方法
  • 作业
    • 模拟数据库连接池
    • DBCP 连接池
    • C3P0连接池

学习目标

  1. 了解数据库连接池的原理
  2. 了解C3P0数据库连接池
  3. 了解DBCP数据库连接池
  4. 掌握Druid数据库连接池

数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用现有的N个(自定义)数据库连接,不用每次都再重新建立一个新的连接,以提高对数据库操作的性能。

常用开源的数据库连接池

  • C3P0:是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate [2] 一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。
  • Proxool:是一个Java SQDriver驱动程序,提供了对选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中,完全可配置,快速、成熟、健壮。可以透明地为现存的JDBC驱动程序增加连接池功能。
  • Jakarta DBCP:DBCP是一个依赖Jakartacommons-pool对象池机制的数据库连接池。DBCP可以直接的在应用程序中使用。
    -DBPool:是一个高效、易配置的数据库连接池。它除了支持连接池应有的功能之外,还包括了一个对象池,使用户能够开发一个满足自己需求的数据库连接池。
  • SmartPool:是一个连接池组件,它模仿应用服务器对象池的特性。SmartPool能够解决一些临界问题如连接泄漏(connection leaks)、连接阻塞、打开的JDBC对象(如Statements、PreparedStatements)等。
  • Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能。功能强大,能防SQL注入,内置Loging能诊断Hack应用行为。

数据库连接池原理

简单来说,数据库连接池就是在一开始先创建N多个数据库连接connection对象,存储在一个集合内,每次使用一个就从集合内取出一个,用完之后又添加到集合内,一直反复使用。

第一步

创建带有是否使用标记的Connection对象。自定义一个带有是否使用标记的Connection对象。

package com.pool;
import java.sql.Connection;
public class PooledConnection {
    // 数据库连接
    private Connection conn;
    // 用于标识当前数据库连接的状态 true:执行 false:空闲
    private boolean busy;
    public PooledConnection(Connection conn) {
        this.conn = conn;
    }
    public Connection getConn() {
        return conn;
    }
    public void setConn(Connection conn) {
        this.conn = conn;
    }
    public boolean isBusy() {
        return busy;
    }
    public void setBusy(boolean busy) {
        this.busy = busy;
    }
}

第二步

创建数据库线程池对象

数据库线程池对象包含默认连接数、最大连接数、每次新增个数、超时时间和连接对象集合。

package com.star;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;

/**
     * 连接池
     */
public class Poo{
    // 初始化连接数
    private static int initSize = 2;
    // 池中最大连接数
    private static int maxSize = 10;
    // 每次创建的连接数
    private static int stepSize = 2;
    // 超时时间
    private static int timeout = 2000;
    // 用来保存创建的数据库连接
    private static List<PoolCollection> poo= Collections.synchronizedList(new ArrayList<>());
    //单例对象
    private static Pooinstance;

    /**
     * 单利模式:无论什么时候只会有一个Pool对象
     */
    private Pool() {
        resizePool(initSize);
    }

    /**
     * 单利模式:无论什么时候只会有一个Pool对象
     */
    private Pool() {
        resizePool(initSize);
    }

    /**
     * 获取单例对象
     *
     * @return
     */
    public static synchronized PoogetInstance() {
        if (instance == null) {
            instance = new Pool();
        }
        return instance;
    }

    /**
     * 初始化连接池,循环使用池子里的连接对象,如果不够再创建num个,不超过最大数maxSize
     *
     * @param size 初始时按照initSize给池中添加连接,其他时候按照stepSize给池中加
     */
    private void resizePool(int size) {
        int current = pool.size();
        if (current + size > maxSize) {
            size = maxSize - current;

        }
        for (int i = 0; i < size; i++) {
            pool.add(new PoolCollection(createConnection()));
        }

    }
}

第三步

获取连接

/**
 * 创建连接
 *
 * @return
 */
public Connection createConnection() {
    try {
        //加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //加载配置文件
        Properties p = new Properties();
        p.load(new FileInputStream("jdbc.properties"));
        return DriverManager.getConnection(p.getProperty("url"), p.getProperty("user"), p.getProperty("password"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

/**
 * 获取连接
 *
 * @return
 */
public Connection getConnection() {
    Connection connection = getAddConnection();
    while (connection == null) {
        System.out.println(Thread.currentThread().getName() + "开始等待获取连接");
        try {
            Thread.sleep(timeout);
            connection = getAddConnection();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println(Thread.currentThread().getName() + "拿到连接");
    return connection;
}

/**
 * 可以实现递增获取的机制
 *
 * @return
 */
private Connection getAddConnection() {
    Connection connection = getUsableConnection();
    if (connection == null) {
        resizePool(stepSize);
        connection = getUsableConnection();
    }
    return connection;
}

/**
 * 获取可用的连接
 *
 * @return
 */
private Connection getUsableConnection() {
    Connection connection = null;
    if (pool.size() > 0) {
        for (PoolCollection poolCollection : pool) {
            if (poolCollection.isUsed() == false) {
                poolCollection.setUsed(true);
                connection = poolCollection.getConnection();
                //connection有课能在上次使用过程中产生异常被中断
                try {
                    // connection.isValid如果连接未关闭且有效,则返回true
                    if (connection.isValid(2000) == false) {
                        connection = createConnection();
                    }
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                break;
            }
        }
    }
    return connection;
}

第四步

归还

/**
 * 关闭
 * @param connection
 */
public void close(Connection connection){
    for (PoolCollection poolCollection : pool) {
        if(connection == poolCollection.getConnection()){
            poolCollection.setUsed(false);
        }
    }
}

第五步

测试

package com.star;

import java.sql.Connection;

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(){
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "获取连接");
                    Poopool1 = Pool.getInstance();
                    Connection connection = pool1.getConnection();
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    pool1.close(connection);
                    System.out.println(Thread.currentThread().getName() + "释放连接");
                }
            }.start();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

DBCP

下载DBCP地址:

下载pool地址

下载Logging地址

DBCP参数

参数 默认值 说明
username 传递给JDBC驱动的用于建立连接的用户名
password 传递给JDBC驱动的用于建立连接的密码
url 传递给JDBC驱动的用于建立连接的URL
driverClassName 使用的JDBC驱动的完整有效的Java 类名
initialSize 0 初始化连接:连接池启动时创建的初始化连接数量,1.2版本后支持
maxActive 8 最大活动连接:连接池在同一时间能够分配的最大活动连接的数量, 如果设置为非正数则表示不限制
maxIdle 8 最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放, 如果设置为负数表示不限制
minIdle 0 最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接, 如果设置为0则不创建
maxWait 无限 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间(以毫秒计数)超过时间则抛出异常,如果设置为-1表示无限等待
testOnReturn false 是否在归还到池中前进行检验
testWhileIdle false 连接是否被空闲连接回收器(如果有)进行检验.如果检测失败, 则连接将被从池中去除.设置为true后如果要生效,validationQuery参数必须设置为非空字符串
minEvictableIdleTimeMillis 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程 (如果有)回收的最小时间值,单位毫秒
numTestsPerEvictionRun 3 在每次空闲连接回收器线程(如果有)运行时检查的连接数量
timeBetweenEvictionRunsMillis -1 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. 如果设置为非正数,则不运行空闲连接回收器线程
validationQuery null SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.如果指定, 则查询必须是一个SQSELECT并且必须返回至少一行记录
testOnBorrow true 是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个.

方法1

package com.dbcp;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;

public class DBCPUtils {
	private String driver = "com.mysql.cj.jdbc.Driver";
	private String ur= "jdbc:mysql://localhost/mydbcp?serverTimezone=GMT";
	private String username = "root";
	private String password = "";
	private static BasicDataSource basicDataSource = new BasicDataSource();

	public DBCPUtils() {
		basicDataSource.setUrl(url);
		basicDataSource.setDriverClassName(driver);
		basicDataSource.setUsername(username);
		basicDataSource.setPassword(password);

		basicDataSource.setInitialSize(10);// 初始化时创建10个链接
		basicDataSource.setMaxIdle(8);// 设置最大连接数
		basicDataSource.setMaxIdle(5);// 这只最大的空闲连接数
		basicDataSource.setMinIdle(1);// 设置最小空闲连接数字
	}

	/**
	 * 返回一个数据源DataSource应该是在javax.sql.DataSource包下
	 * 
	 * @return
	 */
	public static DataSource getDataSource() {
		return basicDataSource;
	}
}

测试

package com.dbcp;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.sql.DataSource;

public class DBCPTest {
	public static void main(String[] args) {
		DBCPUtils uti= new DBCPUtils();
		DataSource ds = util.getDataSource();
		Connection conn;
		try {
			conn = ds.getConnection();
			String sq= "insert into user values(null,?,?,?,?)";
			PreparedStatement st = conn.prepareStatement(sql);
			st.setString(1, "王麻子");
			st.setInt(2, 1);
			st.setDate(3, new Date(new SimpleDateFormat("yyyy-MM-dd").parse("2019-06-08").getTime()));
			st.setInt(4, 1);

			int i = st.executeUpdate();
			if (i == 1) {
				System.out.println("success");
			} else {
				System.out.println("fail");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}

方法2

配置文件dbcp.properties

#驱动名
driverClassName=com.mysql.cj.jdbc.Driver
#数据库
database=mydbcp
#url
url=jdbc:mysql://localhost/${database}?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
#用户名
username=root
#密码
password=
#初试连接数
initialSize=30
#最大活跃数
maxTotal=30
#最大idle数
maxIdle=10
#最小idle数
minIdle=5
#最长等待时间(毫秒)
maxWaitMillis=1000
#程序中的连接不使用后是否被连接池回收(该版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
#removeAbandoned=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#连接在所指定的秒数内未使用才会被删除()(为配合测试程序才配置为1)
removeAbandonedTimeout=1

使用

package com.dbcp;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;

public class DBCPUtils2 {
	private static BasicDataSource basicDataSource = new BasicDataSource();

	public DBCPUtils2() {
		Properties prop = new Properties();
		try {
			prop.load(new FileInputStream("src/dbcp.properties"));
			basicDataSource = new BasicDataSourceFactory().createDataSource(prop);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 返回一个数据源DataSource应该是在javax.sql.DataSource包下
	 * 
	 * @return
	 */
	public static DataSource getDataSource() {
		return basicDataSource;
	}
}

测试

package com.dbcp;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.sql.DataSource;

public class DBCPTest2 {
	public static void main(String[] args) {
		DBCPUtils2 uti= new DBCPUtils2();
		DataSource ds = util.getDataSource();
		Connection conn;
		try {
			conn = ds.getConnection();
			String sq= "insert into user values(null,?,?,?,?)";
			PreparedStatement st = conn.prepareStatement(sql);
			st.setString(1, "王麻子");
			st.setInt(2, 1);
			st.setDate(3, new Date(new SimpleDateFormat("yyyy-MM-dd").parse("2019-06-08").getTime()));
			st.setInt(4, 1);

			int i = st.executeUpdate();
			if (i == 1) {
				System.out.println("success");
			} else {
				System.out.println("fail");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}

C3P0

下载C3P0地址:

方法1

package com.c3p0;

import java.beans.PropertyVetoException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Utils {

	private static ComboPooledDataSource cpds = null;

	/**
	 * 初始化
	 */
	public C3P0Utils() {
		cpds = new ComboPooledDataSource();
		try {
			cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
			cpds.setJdbcUrl("jdbc:mysql://localhost/mydbcp?serverTimezone=GMT");
			cpds.setUser("root");
			cpds.setPassword("");

			cpds.setMinPoolSize(5);
			cpds.setMaxPoolSize(20);
			cpds.setAcquireIncrement(5);
			cpds.setInitialPoolSize(5);
			cpds.setMaxStatements(50);
			cpds.setMaxIdleTime(60);
		} catch (PropertyVetoException e) {
			e.printStackTrace();
		}

	}
	/**
	 * 获取 Connection 连接
	 * 
	 * @return
	 */
	public static ComboPooledDataSource getDataSource() {
		return cpds;
	}
}

测试

package com.c3p0;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.sql.DataSource;

public class C3P0Test {
	public static void main(String[] args) {
		C3P0Utils uti= new C3P0Utils();
		DataSource ds = util.getDataSource();
		Connection conn;
		try {
			conn = ds.getConnection();
			String sq= "insert into user values(null,?,?,?,?)";
			PreparedStatement st = conn.prepareStatement(sql);
			st.setString(1, "王麻子");
			st.setInt(2, 1);
			st.setDate(3, new Date(new SimpleDateFormat("yyyy-MM-dd").parse("2019-06-08").getTime()));
			st.setInt(4, 1);

			int i = st.executeUpdate();
			if (i == 1) {
				System.out.println("success");
			} else {
				System.out.println("fail");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}

方法2

配置文件夹,通过 c3p0-config.xml文件进行配置,文件名不能改


<c3p0-config>
	
	<default-config>
		<property name="user">rootproperty>
		<property name="password">rootproperty>
		<property name="jdbcUrl">jdbc:mysql://localhost/mydbcp? serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useSSL=false
		property>
		<property name="driverClass">com.mysql.cj.jdbc.Driverproperty>
		<property name="checkoutTimeout">30000property>
		<property name="idleConnectionTestPeriod">30property>
		<property name="initialPoolSize">5property>
		<property name="maxIdleTime">60property>
		<property name="maxPoolSize">20property>
		<property name="minPoolSize">5property>
		<property name="maxStatements">50property>
		<property name="acquireIncrement">5property>
	default-config>

	
	<named-config name="test">
		<property name="user">Xiaopengweiproperty>
		<property name="password">123456property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/Xiaopengwei
		property>
		<property name="driverClass">com.mysql.jdbc.Driverproperty>
		
		<property name="acquireIncrement">5property>
		
		<property name="initialPoolSize">20property>
		
		<property name="maxPoolSize">25property>
		
		<property name="minPoolSize">5property>
	named-config>
c3p0-config>

使用

package com.c3p0;

import java.beans.PropertyVetoException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils2 {
	private static ComboPooledDataSource cpds = null;
	/**
	 * 初始化
	 */
	public C3P0Utils2() {
		cpds = new ComboPooledDataSource();
	}
	/**
	 * 获取 Connection 连接
	 * @return
	 */
	public static ComboPooledDataSource getDataSource() {
		return cpds;
	}
}

测试

package com.c3p0;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.sql.DataSource;

public class C3P0Test2 {
	public static void main(String[] args) {
		C3P0Utils2 uti= new C3P0Utils2();
		DataSource ds = util.getDataSource();
		Connection conn;
		try {
			conn = ds.getConnection();
			String sq= "insert into user values(null,?,?,?,?)";
			PreparedStatement st = conn.prepareStatement(sql);
			st.setString(1, "王麻子");
			st.setInt(2, 1);
			st.setDate(3, new Date(new SimpleDateFormat("yyyy-MM-dd").parse("2019-06-08").getTime()));
			st.setInt(4, 1);

			int i = st.executeUpdate();
			if (i == 1) {
				System.out.println("success");
			} else {
				System.out.println("fail");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}

DbUtils

DbUtils是在数据库连接池基础上建立起来的快速操作数据库的工具类。

后面会用到spring JdbcTemplate、Mybatis、hibernate等框架

下载地址:

DBUtils三个核心功能介绍

-QueryRunner中提供对sql语句操作的API

  • ResultSetHandler接口,用于定义select操作后,怎样封装结果集
  • DBUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

QueryRunner核心类

QueryRunner(DataSource ds),传入连接池,并且底层自动维护连接connection

-update(String sql,Obj...params),执行更新数据

  • query(String sql,ResultSetHandler rsh,Object...panrams),执行查询

ResultSetHandler结果集处理类

-ArrayHandler:适合取1条记录,把结果集中的第一行数据转成对象数组。

  • ArrayListHandler:适合取多条记录,把结果集中的每一行数据都转成一个对象数组,再存放到List中。
  • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中(把每条记录封装成对象,适合取一条记录)
    -BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
  • MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
  • MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
  • KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(Map),再把这些map再存到一个map里,其key为指定的列。
    -ColumnListHandler:将结果集中某一列的数据存放到List中。
  • ScalarHandler:将结果集第一行的某一列放到某个对象Object中。
  • 案例

    实体类

    package com.dbutils.entity;
    
    import java.sql.Date;
    
    public class User {
    
    	private Long id;
    	private String name;
    	private Boolean sex;
    	private Date birthday;
    	private Integer status;
    	
    	public User() {
    		super();
    	}
    
    	public User(Long id, String name, Boolean sex, Date birthday, Integer status) {
    		super();
    		this.id = id;
    		this.name = name;
    		this.sex = sex;
    		this.birthday = birthday;
    		this.status = status;
    	}
    
    	public User(String name, Boolean sex, Date birthday) {
    		super();
    		this.name = name;
    		this.sex = sex;
    		this.birthday = birthday;
    	}
    
    	public Long getId() {
    		return id;
    	}
    
    	public void setId(Long id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public Boolean getSex() {
    		return sex;
    	}
    
    	public void setSex(Boolean sex) {
    		this.sex = sex;
    	}
    
    	public Date getBirthday() {
    		return birthday;
    	}
    
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    
    	public Integer getStatus() {
    		return status;
    	}
    
    	public void setStatus(Integer status) {
    		this.status = status;
    	}
    
    }
    

    查询

    package com.dbutils;
    
    import java.sql.SQLException;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.ArrayHandler;
    import org.apache.commons.dbutils.handlers.ArrayListHandler;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    import org.apache.commons.dbutils.handlers.ColumnListHandler;
    import org.apache.commons.dbutils.handlers.KeyedHandler;
    import org.apache.commons.dbutils.handlers.MapHandler;
    import org.apache.commons.dbutils.handlers.MapListHandler;
    import org.apache.commons.dbutils.handlers.ScalarHandler;
    import org.junit.jupiter.api.Test;
    
    import com.dbutils.entity.User;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public class MyDbUtils {
    	// --1.ArrayHandler:将查询的结果的第一行放到一个数组中
    	@Test
    	public void query1() throws SQLException {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		Object[] array = runner.query("select * from user", new ArrayHandler());
    		System.out.println(array[0] + "," + array[1]);
    	}
    
    	// --2.ArrayListHandler:将查询的结果的每一行放到一个数组中,然后再将数组放到集合中;
    	@Test
    	public void query2() throws SQLException {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		List<Object[]> list = runner.query("select * from user", new ArrayListHandler());
    		for (Object[] objects : list) {
    			System.out.println(objects[0] + "," + objects[1]);
    		}
    	}
    
    	// --3.BeanHandler:将查询的结果的第一行封装到一份javabean对象中;
    	@Test
    	public void query3() throws SQLException {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		User user = runner.query("select * from user", new BeanHandler<User>(User.class));
    		System.out.println(user.getId() + "," + user.getName());
    	}
    
    	// --4.BeanListHandler:将查询的结果的每一行封装到一个javabean对象中,然后再将这些对象存入list中;
    	@Test
    	public void query4() throws SQLException {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		List<User> list = runner.query("select * from user", new BeanListHandler<User>(User.class));
    		for (User user : list) {
    			System.out.println(user.getId() + "," + user.getName());
    		}
    	}
    
    	// --5.MapHandler:将查询的结果的第一行存入到一个map中,键为列名,值为各列值;
    	@Test
    	public void query5() throws SQLException {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		Map<String, Object> map = runner.query("select * from user", new MapHandler());
    		for (Entry<String, Object> entry : map.entrySet()) {
    			String mapKey = entry.getKey();
    			Object mapValue = entry.getValue();
    			System.out.println(mapKey + ":" + mapValue);
    		}
    	}
    
    	// --6.MapListHandler:将查询的结果的每一行存入到一个map中,键为列名,值为各列值;然后再将map存入list中;
    	@Test
    	public void query6() throws SQLException {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		List<Map<String, Object>> map = runner.query("select * from user", new MapListHandler());
    		for (Map<String, Object> map2 : map) {
    			for (Entry<String, Object> entry : map2.entrySet()) {
    				String mapKey = entry.getKey();
    				Object mapValue = entry.getValue();
    				System.out.println(mapKey + ":" + mapValue);
    			}
    			System.out.println("------------------------------------------------");
    		}
    
    	}
    
    	// --7.KeyedHandler:将查询的结果集中某一列的数据存放到List中;
    	@Test
    	public void query7() {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		try {
    			// ScalarHandler 的参数可以是列的索引(从1开始)或列名
    			Map<Object, Map<String, Object>> map = (Map<Object, Map<String, Object>>) runner.query("select * from user",new KeyedHandler("id"));
    			for (Object key : map.keySet()) {
    				System.out.println(key + " " + map.get(key));
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    
    	// --8.ColumnListHandler:将查询的结果集中某一列的数据存放到List中;
    	@Test
    	public void query8() {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		try {
    			// ScalarHandler 的参数可以是列的索引(从1开始)或列名
    			List<Object> list = runner.query("select * from user", new ColumnListHandler<Object>(1));
    			for (Object string : list) {
    				System.out.println(string);
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    
    	// --9.ScalarHandler:将查询的结果的第一行的某一列放到一个对象中;精确定位到某个值;
    	@Test
    	public void query9() {
    		QueryRunner runner = new QueryRunner(new ComboPooledDataSource());
    		try {
    			// ScalarHandler 的参数可以是列的索引(从1开始)或列名
    			Object name = runner.query("select * from user", new ScalarHandler<Object>(2));
    			System.out.println(name);
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    其他方法

    • close():
      • DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭连接、声明和结果集(ResultSet)。
        -CloseQuietly:
      • CloseQuietly这一方法不仅能在连接、声明或者结果集(ResultSet)为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。
      • 如果你不想捕捉这些异常的话,这对你是非常有用的。
      • 在重载CloseQuietly方法时,特别有用的一个方法是closeQuietly(Connection conn,Statement stmt,ResultSet rs),这是因为在大多数情况下,连接、声明和结果集(ResultSet)是你要用的三样东西,而且在最后的块你必须关闭它们。
      • 使用这一方法,你最后的块就可以只需要调用这一方法即可。
    • CommitAndCloseQuietly(Connection conn)
      • 这一方法用来提交连接,然后关闭连接,并且在关闭连接时不向上抛出在关闭时发生的一些SQL异常。
      • LoadDriver(String driveClassName):这一方法装载并注册JDBC驱动程序,如果成功就返回TRUE。
      • 使用这种方法,你不需要去捕捉这个异常ClassNotFoundException。使用loadDrive方法,编码就变得更容易理解,
      • 你也就得到了一个很好的Boolean返回值,这个返回值会告诉你驱动类是不是已经加载成功了。

    作业

    模拟数据库连接池

    DBCP 连接池

    package utility;
    /*
     *@author Liu
     *@Description DBPC连接池的工具类
     *@data 2021/12/28
     */
    
    import Entity.User;
    import MapperEntity.UserMapperEntity;
    import org.apache.commons.dbcp2.BasicDataSource;
    import org.apache.commons.dbcp2.BasicDataSourceFactory;
    
    import java.io.FileInputStream;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Properties;
    
    public class DBCPUtility {
        private static BasicDataSource basicDataSource;
    
        //加载配置文件
        static {
            Properties properties = new Properties();
            try (
                    FileInputStream fis = new FileInputStream("dbpc.properties");
            ) {
                properties.load(fis);
                basicDataSource = BasicDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static List<User> executeQuery(String sql,Object ... params)  {
            Connection connection = getConnection();
            PreparedStatement statement=null;
            List<User> list = new ArrayList<>();
            if (connection==null) {
                return null;
            }
            try {
                connection.setAutoCommit(false);
                statement=connection.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) {
                    statement.setObject(i+1,params[i]);
                }
                ResultSet resultSet = statement.executeQuery();
                list = UserMapperEntity.getUser(resultSet);
                connection.commit();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                try {
                    connection.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        Close(connection,statement);
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
         return list;
        }
    
        /**
         * 修改
         * @param sql
         * @param params
         * @return
         */
        public static int executeUpdate(String sql,Object ... params)  {
            Connection connection = getConnection();
            PreparedStatement statement=null;
            int rows=0;
            List<User> list = new ArrayList<>();
            if (connection==null) {
                return rows;
            }
            try {
                connection.setAutoCommit(false);
                statement=connection.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) {
                    statement.setObject(i+1,params[i]);
                }
                rows = statement.executeUpdate();
                connection.commit();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                try {
                    connection.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        Close(connection,statement);
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            return rows;
        }
        /**
         * 获取数据库的连接
         *
         * @return 连接
         */
        public static Connection getConnection(){
            try {
               return basicDataSource.getConnection();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return null;
        }
    
        /**
         * 关闭Connection
         *
         * @param connection 连接
         * @throws SQLException
         */
        public static void Close(Connection connection) throws SQLException {
            if (connection != null) {
                connection.close();
            }
        }
    
        /**
         * 关闭statement
         *
         * @param statement 连接
         * @throws SQLException
         */
        public static void Close(Statement statement) throws SQLException {
            if (statement != null) {
                statement.close();
            }
        }
    
        /**
         * 关闭connection 和 statement
         * @param connection 连接
         * @param statement statement
         * @throws SQLException
         */
        public static void Close(Connection connection,Statement statement) throws SQLException {
           connection.close();
           statement.close();
        }
    }
    

    C3P0连接池

    package utility;
    /*
     *@author Liu
     *@Description
     *@data 2021/12/28
     */
    
    import Entity.User;
    import MapperEntity.UserMapperEntity;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    
    public class C3P0Utility {
        private static final ComboPooledDataSource dataSource;
        static{
            dataSource=new ComboPooledDataSource();
        }
    
        /**
         * 获取连接
         * @return
         */
        public static Connection getConnection(){
            try {
                return dataSource.getConnection();
            } catch (SQLException throwables)
            {
                throwables.printStackTrace();
            }
            return null;
        }
    
        /**
         * 查询
         * @param sql
         * @param params
         * @return
         */
        public static List<User> executeQuery(String sql,Object ... params){
            Connection connection = getConnection();
            PreparedStatement statement=null;
            List<User> list = new ArrayList<>();
            if (connection==null) {
                return null;
            }
            try {
                connection.setAutoCommit(false);
                statement=connection.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) {
                    statement.setObject(i+1,params[i]);
                }
                ResultSet resultSet = statement.executeQuery();
                list = UserMapperEntity.getUser(resultSet);
                connection.commit();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                try {
                    connection.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally {
                    Close(connection,statement);
                }
            }
            return list;
        }
    
        /**
         * 修改
         * @param sql
         * @param params
         * @return
         */
        public static int executeUpdate(String sql,Object ... params){
            Connection connection = getConnection();
            PreparedStatement statement=null;
            int rows=0;
            if (connection==null) {
                return rows;
            }
            try {
                connection.setAutoCommit(false);
                statement=connection.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) {
                    statement.setObject(i+1,params[i]);
                }
                rows = statement.executeUpdate();
                connection.commit();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                try {
                    connection.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }finally {
                    Close(connection,statement);
                }
            }
            return rows;
        }
    
        /**
         * 关闭连接
         * @param connection
         * @return
         */
        public static void Close(Connection connection){
            if (connection!=null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        public static void Close(Statement statement){
            if(Objects.nonNull(statement)){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        public static void Close(Connection connection,Statement statement){
            Close(connection);
            Close(statement);
        }
    }
    

    你可能感兴趣的:(Java+JDBC,数据库,database,jdbc)