数据库连接池
先来看一个我们平时查询普通的流程是怎样的
上面是一个请求查询的方式,实际项目请求有很多个,不同用户发起请求,每次都要进行连接,连接完后又释放掉,十分浪费资源,那有什么办法楠
可以使⽤数据库连接池解决这⼀问题。 数据库连接池的基本思想就是为数据库建⽴⼀个缓冲池,预先向缓冲池中放⼊⼀定数量的连接对象,当 需要获取数据库连接的时候,只需要从缓冲池中取出⼀个对象,⽤完之后再放回到缓冲池中,供下⼀次 请求使⽤,做到了资源的重复利⽤,允许程序重复使⽤⼀个现有的数据库连接对象,⽽不需要重新创 建。 当数据库连接池中没有空闲的连接时,新的请求就会进⼊等待队列,等待其他线程释放连接
相当于在java程序与数据库之间放一个连接池,来画个图
需要的时候就从数据库连接池拿出来就行了,不要了又放回去
怎么实现呢?
JDBC 的数据库连接池使⽤ javax.sql.DataSource 接⼝来完成的,DataSource 是 Java 官⽅提供的接 ⼝,使⽤的时候开发者并不需要⾃⼰来实现该接⼝,可以使⽤第三⽅的⼯具,C3P0 是⼀个常⽤的第三 ⽅实现,实际开发中直接使⽤ C3P0 即可完成数据库连接池的操作
意思就是有人在一个类里面已经把那些接口实现了,我们只需要创建对象拿来用就行了
导包
需要用到的表
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//创建C3P0对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//获取驱动
comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
//获取连接
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("123456");
connection = comboPooledDataSource.getConnection();
//用?来表示
String sql = "select ename from emp where ename like ?";
//取得数据库操作对象
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"_A%");
//执行查询语句
resultSet = preparedStatement.executeQuery();
//输出
while (resultSet.next()){
System.out.println(resultSet.getString("ename"));
}
} catch (SQLException e) {
e.printStackTrace();
} catch (PropertyVetoException e) {
e.printStackTrace();
} finally {
//关闭流
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
这样也是能查到的
为了不让太多代码写在Java程序中,也为了便于更改,我们将文件写在xml中
实际开发,将 C3P0 的配置信息定义在 xml ⽂件中,Java 程序只需要加载配置⽂件即可完成数据库连接 池的初始化操作。
1、配置⽂件的名字必须是 c3p0-config.xml
2、初始化 ComboPooledDataSource 时,传⼊的参数必须是 c3p0-config.xml 中 named-config 标签 的 name 属性值。
看看我xml文件的位置 xml中&;代表&
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="studentc3p0">
<!-- 指定连接数据源的基本属性 -->
<property name="user">root</property>
<property name="password">123456</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/student?
useUnicode=true&characterEncoding=UTF-8</property>
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">20</property>
<!-- 数据库连接池中的最⼩的数据库连接数 -->
<property name="minPoolSize">2</property>
<!-- 数据库连接池中的最⼤的数据库连接数 -->
<property name="maxPoolSize">40</property>
</named-config>
</c3p0-config>
那Java文件怎么写呢
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//创建C3P0对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("studentc3p0");
//获取连接
connection = comboPooledDataSource.getConnection();
//用?来表示
String sql = "select ename from emp where ename like ?";
//取得数据库操作对象
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"_A%");
//执行查询语句
resultSet = preparedStatement.executeQuery();
//输出
while (resultSet.next()){
System.out.println(resultSet.getString("ename"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭流
try {
resultSet.close();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
DBUtils
DBUtils 可以帮助开发者完成数据的封装(结果集到 Java 对象的映射)
顾名思义,当然是方便用户呀,我们来几个例子
和数据库常量池一样,DBUtils提供了实现类,我们直接创建对象然后调用方法就行了
用到的表,为了把学生对象和表元素对应,我们把t_user拿来使用
写一个学生类,把我查询到的放在学生类对象里面再输出(注意有参无参构造和toString方法加上
public class Student {
private Integer id;
private String username;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
public Student() {
}
public Student(Integer id, String username) {
this.id = id;
this.username = username;
}
}
最初的查询办法
public static void main(String[] args) {
System.out.println(findBId());
}
public static Student findBId(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Student student = null;
try {
//创建C3P0对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("1c3p0");
//获取连接
connection = comboPooledDataSource.getConnection();
//用?来表示
String sql = "select * from t_user where id = 1";
//取得数据库操作对象
preparedStatement = connection.prepareStatement(sql);
//执行查询语句
resultSet = preparedStatement.executeQuery();
//输出
while (resultSet.next()) {
Integer id = resultSet.getInt(1);
String username = resultSet.getString(2);
student = new Student(id,username);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭流
try {
resultSet.close();
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return student;
}
获取连接后我们有更简单的方法来处理sql语句后面的那部分
也就是这一部分
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Integer id = resultSet.getInt(1);
String username = resultSet.getString(2);
student = new Student(id,username);
}
怎么做呢? 先把包导进来,包可以取网上下载
拿到数据怎么办楠,用下面的实现类来处理,查询多条记录就要用到第二个第三个了
看得出来是用来处理结果集的
public static Student findDBUtils(){
//创建C3P0对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("1c3p0");
Connection connection = null;
Student student = null;
try {
connection = comboPooledDataSource.getConnection();
String sql = "select * from t_user where id = 1";
//使用DBUtils提供的类
QueryRunner queryRunner = new QueryRunner();
student = queryRunner.query(connection,sql,new BeanHandler<>(Student.class));
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return student;
}
使用DBUtils提供的类调用query方法来执行,具体可以自己看看query方法的源码,把结果处理都自己完成了。
ResultSetHandler rsh 便是我们上面的new BeanHandler(Student.class)
private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
if (conn == null) {
throw new SQLException("Null connection");
} else if (sql == null) {
if (closeConn) {
this.close(conn);
}
throw new SQLException("Null SQL statement");
} else if (rsh == null) {
if (closeConn) {
this.close(conn);
}
throw new SQLException("Null ResultSetHandler");
} else {
PreparedStatement stmt = null;
ResultSet rs = null;
Object result = null;
try {
stmt = this.prepareStatement(conn, sql);
this.fillStatement(stmt, params);
rs = this.wrap(stmt.executeQuery());
result = rsh.handle(rs);
} catch (SQLException var33) {
this.rethrow(var33, sql, params);
} finally {
try {
this.close(rs);
} finally {
this.close(stmt);
if (closeConn) {
this.close(conn);
}
}
}
return result;
}
}
那后面的Object... params参数是什么意思呢,就是我们自己传入的参数,...代表多个
就拿上面的例子来说,这样也是一样的哦
public static Student findDBUtils(Integer id, String username){
//创建C3P0对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("1c3p0");
Connection connection = null;
Student student = null;
try {
connection = comboPooledDataSource.getConnection();
String sql = "select * from t_user where id = ? and username = ?";
//使用DBUtils提供的类
QueryRunner queryRunner = new QueryRunner();
student = queryRunner.query(connection,sql,new BeanHandler<>(Student.class),id,username);
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return student;
}
那我们来讲一下查询多条结果( new BeanListHandler() )
List list = queryRunner.query(connection,sql,new BeanListHandler<>(Student.class));
System.out.println(list);
输出list就行
上面都是是输出Student对象,我们用什么方式来输出数据库内容楠
这用到new MapHandler()
代码改成这样就行了
public static void main(String[] args) {
findDBUtils();
}
public static void findDBUtils(){
//创建C3P0对象
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("1c3p0");
Connection connection = null;
Student student = null;
try {
connection = comboPooledDataSource.getConnection();
String sql = "select * from t_user where id = 1";
//使用DBUtils提供的类
QueryRunner queryRunner = new QueryRunner();
Map map = queryRunner.query(connection,sql,new MapHandler());
System.out.println(map);
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
那多条结果呢?
这是什么意思呢
List<Map<String, Object>> list = queryRunner.query(connection,sql,new MapListHandler());
for(Map<String, Object> map : list){
System.out.println(map);
}
就是先把数据取出来先存在Map(String,Object)中,数据类型是默认的,不用更改
再把map存在list集合中
好了,这期就讲到这里,下期我们讲一个JSP + Servlet + JDBC 增删改查的例子
能不能点个赞再走呜呜