DBUTILS的可以操作数据库 , 突发奇想想山寨一个,于是……..
自定义连接池
之前由于对MapListHandler功能的理解有误,该对象并不是通过反射去获取值,而是直接通过sql预编译获得的结果集进行操作
Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了(close).每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.程序初始化的时候,初始化多个连接,将多个连接放入到池(集合)中.每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.
- 使用连接池的目的: 可以让连接得到复用, 避免浪费
下图是自定义的连接池+装饰者+jdbc工具类(很low , 见怪)
jdbc工具类
1 | import java.io.IOException; |
装饰者(增强连接池的close)
1 | package MyDataSource; |
连接池–新建的连接调用close会被销毁
1 | package MyDataSource; |
由于笔者比较菜,许多因素未考虑到,俗话说工欲善其事,必先利其器,为此选择连接池和JDBC工具包来提高效率
C3P0 –创建连接池
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。C3P0是异步操作的,所以一些操作时间过长的JDBC通过其它的辅助线程完成。目前使用它的开源项目有Hibernate,Spring等。C3P0有自动回收空闲连接功能
这里我使用的是IDEA创建—–C3P0 包来完成对连接池对象的创建和sql数据库连接对象的调用方法
1 | package C3P0; |
这里有几点需要注意 :
DBUTILS
DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能 ,简而言之就是—–简化JDBC操作数据库的步骤
JavaBean
数据库查询出来的数据一定会有地方来进行存储 , 封装数据 , 它就是javabean(创建一个Person类) , 只是多了如下要求 :
- 私有字段
- 提供公共的get/set方法
- 无参构造
- 实现Serializable
- 字段: 全局/成员变量 eg:
private String username
- 属性: 去掉get或者set首字母变小写 eg:
setUsername-去掉set->Username-首字母变小写->username
利用DBUTILS进行增删改
利用DBUTILS进行查,结果封装在JavaBean里面
自定义DBUTILS功能—-增删改查
秉承着知其然 , 亦知其所以然 , 自己玩玩o(∩_∩)o 哈哈
增删改
1 | package DBUtils; |
查
分析BeanHandler , MapHandler , BeanListHandler , MapListHandler发现他们一个共同的巴巴–ResultSetHandler , 这里我只对BeanHandler进行分析 , 其中Type就是beanhandler传入的字节码对象 , 根据底层源码描述
1 | /** |
一句话 : bean做为一个载体封装sql查询的数据 , ResultSetHandler做为获取bean对象和sql结果集的中间商
依照这个思路,这里我重载单条查询和多条查询的query方法 ,开工 ,见下图
单条查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30public static <T> T query(String sql, ResultSetHandler<T> handler, Object... parament) throws Exception {
// 获取传入的handler的成员变量
Field[] fields = handler.getClass().getDeclaredFields();
Method[] methods = handler.getClass().getDeclaredMethods();
//获取 type 字段的字节码对象
fields[0].setAccessible(true);
Object o = fields[0].get(handler);
//获取泛型T的对象
Class o2 = (Class) o;
T o1 = (T) o2.getConstructor().newInstance();
//获取sql预编译集合
PreparedStatement pstm = connection.prepareStatement(sql);
//判断传参
if (sql == null || handler == null) {
throw new RuntimeException("Miss one of parament of sql or handler !");
}
//这里还需要判断parament是否是存在
//存在
if (parament.length != 0) {
for (int i = 1; i < parament.length + 1; i++) {
pstm.setObject(i, parament[i - 1]);
getDataAndSetData((Class) o, o1, pstm );
}
} else {
//不存在
//结果集
getDataAndSetData((Class) o, o1, pstm);
}
return o1;
}
getDataAandSetDate方法
1 | public static <T> void getDataAndSetData(Class o, T o1, PreparedStatement pstm) throws Exception{ |
单条查询测试结果
多条查询
list1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30public static <T> List<T> query(String sql, ResultSetHandler<T> handler, Object... parament) throws Exception {
// 获取传入的handler的成员变量
Field[] fields = handler.getClass().getDeclaredFields();
Method[] methods = handler.getClass().getDeclaredMethods();
//获取 type 字段的字节码对象
fields[0].setAccessible(true);
Object o = fields[0].get(handler);
//获取泛型T的对象
Class o2 = (Class) o;
T o1 = (T) o2.getConstructor().newInstance();
//获取sql预编译集合
PreparedStatement pstm = connection.prepareStatement(sql);
//判断传参
if (sql == null || handler == null) {
throw new RuntimeException("Miss one of parament of sql or handler !");
}
//这里还需要判断parament是否是存在
//存在
if (parament.length != 0) {
for (int i = 1; i < parament.length + 1; i++) {
pstm.setObject(i, parament[i - 1]);
return getDataAndSetListData((Class) o, o1, pstm,fields );
}
} else {
//不存在
//结果集
return getDataAndSetListData((Class) o, o1, pstm,fields);
}
return null;
}
getDataAandListSetDate方法
1 | public static <T> List<T> getDataAndSetListData(Class o, T o1, PreparedStatement pstm,Field[] fields) throws Exception { |
测试结果
Map——–这里的思想是将查询到的数据库数据直接封装在Map,然后在封装在List
1 | public static <T> List<Map<String,Object>> query(String sql,ResultSetHandler<T> handler, Object... parament) throws Exception { |
getDataAndSetMapData方法
1 |
|
测试结果
总结
通过这次 , 加深了对反射和泛型的运用 ;同时书写一个程序时,要先考虑清楚目标,理清思路然后写Bug , 最后再调试Bug—-o(∩_∩)o 哈哈