Java 操作数据库(五) JDBC连接池封装-C3P0
目录
本节目标
- 学会完整封装使用 JDBC 连接池
本示例以 MySQL 数据库作为演示库
引入驱动包
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
封装工具类 C3p0Util
package com.bqteam.learn.jdbc;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.beanutils.BeanUtils;
import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class C3p0Util {
private static ComboPooledDataSource dataSource;
public static boolean init(String driverName, String dsn, String user, String pwd) {
if (dataSource == null) {
dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(driverName);
} catch (PropertyVetoException e) {
e.printStackTrace();
return false;
}
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl(dsn);
// 设置初始连接池的大小
dataSource.setInitialPoolSize(2);
// 设置连接池的最小值
dataSource.setMinPoolSize(1);
// 设置连接池的最大值
dataSource.setMaxPoolSize(10);
// 设置连接池中的最大Statements数量
dataSource.setMaxStatements(50);
// 设置连接池的最大空闲时间
dataSource.setMaxIdleTime(60);
}
return true;
}
/**
* 从连接池获得数据库连接
*
* @return Connection
*/
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 关闭 Connection
*
* @param connection 连接池对象
*/
private static void close(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭 Statement
*
* @param statement
*/
private static void close(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭 ResultSet
*
* @param resultSet
*/
private static void close(ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭 Connection 以及 Statement
*
* @param connection
* @param statement
*/
private static void close(Connection connection, Statement statement) {
close(connection);
close(statement);
}
/**
* 关闭 Connection,Statement 以及 ResultSet
*
* @param connection
* @param statement
* @param resultSet
*/
private static void close(Connection connection, Statement statement, ResultSet resultSet) {
close(connection, statement);
close(resultSet);
}
/**
* 设置参数
*
* @param preparedStatement Statement对象
* @param param 参数列表
* @return
* @throws SQLException
*/
private static boolean settingParams(PreparedStatement preparedStatement, Object[] param) throws SQLException {
if (param != null && param.length > 0) {
// 获取ParameterMetaData
ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
// 获得SQL中占位符个数
int paramCount = parameterMetaData.getParameterCount();
// 占位符个数与参数个数不一致,返回false表示出错
if (paramCount != param.length) {
return false;
}
// 设置对应的参数信息
for (int i = 0; i < paramCount; i++) {
preparedStatement.setObject(i + 1, param[i]);
}
}
return true;
}
/**
* 更新操作
*
* @param sql 执行的 SQL 语句
* @param param 对应的参数列表
* @return true 更新成功, false 更新失败
*/
public static boolean update(String sql, Object[] param) {
PreparedStatement preparedStatement = null;
Connection connection = getConnection();
if (connection == null) {
return false;
}
try {
preparedStatement = connection.prepareStatement(sql);
if (!settingParams(preparedStatement, param)) {
return false;
}
int result = preparedStatement.executeUpdate();
return result > 0;
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(connection, preparedStatement);
}
return false;
}
/**
* 获取单条数据
*
* @param sql 执行 SQL 语句
* @param param 对应的参数列表
* @param clazz 所要获取的对象的类型
* @param <T> 对象的类型
* @return
*/
public static <T> T queryOne(String sql, Object[] param, Class<T> clazz) {
Connection connection = getConnection();
if (connection == null) {
return null;
}
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
preparedStatement = connection.prepareStatement(sql);
if (!settingParams(preparedStatement, param)) {
return null;
}
resultSet = preparedStatement.executeQuery();
if (resultSet == null) {
return null;
}
if (resultSet.next()) {
// 利用反射机制创建对象
T data = clazz.newInstance();
// 获得 ResultSetMetaData
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
// 获得列的数量
int columnCount = resultSetMetaData.getColumnCount();
for (int i = 0; i < columnCount; i++) {
// 获得对应的列的名称
String name = resultSetMetaData.getColumnName(i + 1);
// 获得对应的列的值
Object rsData = resultSet.getObject(name);
// 使用 BeanUtils 工具对属性进行注入
BeanUtils.copyProperty(data, name, rsData);
}
return data;
} else {
return null;
}
} catch (InstantiationException | SQLException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
} finally {
close(connection, preparedStatement, resultSet);
}
return null;
}
/**
* 获取 Bean 并且封装成 List
*
* @param sql 执行 SQL 语句
* @param param 对应的参数列表
* @param clazz 所要获取的对象的类型
* @param <T> 对象的类型
* @return list
*/
public static <T> List<T> queryList(String sql, Object[] param, Class<T> clazz) {
Connection connection = getConnection();
if (connection == null) {
return null;
}
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
preparedStatement = connection.prepareStatement(sql);
if (!settingParams(preparedStatement, param)) {
return null;
}
resultSet = preparedStatement.executeQuery();
if (resultSet == null) {
return null;
}
List<T> results = new ArrayList<>();
while (resultSet.next()) {
// 创建对象
T data = clazz.newInstance();
// 获得ResultSetMetaData
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
// 获得列的数量
int columnCount = resultSetMetaData.getColumnCount();
for (int i = 0; i < columnCount; i++) {
// 获得对应的列的名称
String name = resultSetMetaData.getColumnName(i + 1);
// 获得对应的列的值
Object rData = resultSet.getObject(name);
// 使用BeanUtils工具对属性进行注入
BeanUtils.copyProperty(data, name, rData);
}
results.add(data);
}
return results;
} catch (InstantiationException | SQLException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
} finally {
close(connection, preparedStatement, resultSet);
}
return null;
}
}
使用 JUint 进行测试
package com.bqteam.learn.jdbc;
import com.bqteam.learn.bean.LphHomework;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertNotNull;
public class TestC3p0Util {
@BeforeClass
public static void init() {
String driverName = "com.mysql.cj.jdbc.Driver";
String dsn = "jdbc:mysql://host:port/database?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false";
String user = "user";
String pwd = "password";
C3p0Util.init(driverName, dsn, user, pwd);
}
@Test
public void testQueryList() {
final String SQL = "select * from lph_homework limit ?";
Object[] param = {10};
List<LphHomework> list = C3p0Util.queryList(SQL, param, LphHomework.class);
assertNotNull(list);
for (LphHomework item : list) {
System.out.printf("作业ID为 %d,名称为 %s,教学组ID为 %d\n", item.getId(), item.getName(), item.getMath_cls_group_id());
}
}
}
测试输出结果如下
作业ID为 92,名称为 作业12-3-20171128,教学组ID为 2
作业ID为 41,名称为 作业7-2-20171110,教学组ID为 1
作业ID为 47,名称为 作业8-1-20171110,教学组ID为 1
作业ID为 164,名称为 作业16-3-20180313,教学组ID为 6
作业ID为 104,名称为 作业13-2-20180307,教学组ID为 5
作业ID为 147,名称为 作业14-1-20180312,教学组ID为 5
作业ID为 53,名称为 作业8-3-20171110,教学组ID为 1
作业ID为 9,名称为 作业3-3-20171031,教学组ID为 3
作业ID为 15,名称为 作业4-1-20171031,教学组ID为 2
作业ID为 120,名称为 作业19-2-20180312,教学组ID为 4