写在前面
在阅读本文之前,你或许应该先了解:
- JDBC的实现步骤(注册驱动、建立连接、发送SQL、处理结果集)
- 数据库连接池的使用(本文使用
c3p0
连接池)
DbUtils是Apache的一个对于数据库操作的封装类,本文重写了DbUtils的query与update方法,而代码着重于封装的实现原理,对于很多异常等都未做详细的处理。
实现步骤
- 首先,通过
c3p0
连接池建立数据库连接,并获取连接对象。
- 导入
c3p0-0.9.2-pre1.jar
- 创建
c3p0.properties
或c3p0-config.xml
文件,下面是.xml文件主要内容:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,当使用ComboPooledDataSource无参构造器时,使用的就是这个配置 -->
<default-config>
<!-- 基本配置 -->
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/share?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=utf8</property>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 每次增量,当需要创建Connection对象时,一次创建几个 -->
<property name="acquireIncrement">3</property>
<!-- 当创建池对象后,池中应该有几个Connection对象 -->
<property name="initialPoolSize">10</property>
<!-- 池中最少Connection个数,如果少于这个值,就会创建Connection -->
<property name="minPoolSize">2</property>
<!-- 池中最大连接个数 -->
<property name="maxPoolSize">15</property>
</default-config>
</c3p0-config>
- 创建数据库连接池,获取连接对象的包装类
JdbcUtil
public class JdbcUtil {
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static DataSource getDataSource(){
return dataSource;
}
}
- 数据库增删查改的类
MyRunner
public class MyRunner {
private DataSource dataSource;
public MyRunner(DataSource dataSource){
this.dataSource = dataSource;
}
public <T> T query(String sql, MyResultSetHandler<T> handler, Object... params){
T result = null;
try {
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
generateParams(pstmt, params); // 给pstmt赋值
result = handler.handle(pstmt.executeQuery());
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
/**
* 数据操作 包括增、删、改
* @param sql sql语句
* @param params 参数列表
*/
public void update(String sql, Object... params){
try {
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
generateParams(pstmt, params); // 给pstmt赋值
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 给指定的pstmt 预处理的? 赋值
* @param pstmt PreparedStatement
* @param params 参数列表
* @throws SQLException
*/ private static void generateParams(PreparedStatement pstmt, Object[] params) throws SQLException {
for(int i = 1; i <= params.length; i++){
pstmt.setObject(i, params[i-1]);
}
}
}
- 创建统一的处理
ResultSet
结果集的接口类MyResultSetHandler
/**
* @Auther dbc
* @Date 2020/9/11 17:04
*/
public interface MyResultSetHandler<T> {
T handle(ResultSet resultSet) throws SQLException;
}
- 实现上一步的接口
MyBeanHandler
public class MyBeanHandler<T> implements MyResultSetHandler<T> {
private Class<T> clazz;
public MyBeanHandler(Class<T> T){
this.clazz = T;
}
@Override
public T handle(ResultSet resultSet) throws SQLException {
T t = null;
if(resultSet.next()){
try {
t = clazz.newInstance();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
for(int i = 1; i <= columnCount; i++){
String columnName = metaData.getColumnName(i);
Object columnValue = resultSet.getObject(columnName);
try {
Field field = clazz.getDeclaredField(columnName);
field.setAccessible(true); // 获取访问操作权限
field.set(t, columnValue);
}catch (NoSuchFieldException e){
e.printStackTrace();
}
}
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return t;
}
}
- 对于结果集为多个,需要用List来接收,同样用一个类来实现
MyResultSetHandler
,传入List<T>即可,本文就不再做演示。 - 增加测试类Account,数据库也应当存在此表即一些测试数据。主要有以下字段:
private int id;
private String name;
private Double money;
//注意:mysql中定义decimal字段,应由BigDecimal来接收
- 测试
public static void main(String[] args) {
MyRunner myRunner= new MyRunner(JdbcUtil.getDataSource());
Account account = myRunner.query("SELECT * FROM account WHERE id =?;",new MyBeanHandler<Account>(Account.class),1);
System.out.println(account);
List<Account> accounts = myRunner.query("SELECT * FROM account",new MyBeanListHandler<>(Account.class));
System.out.println(accounts);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。