javaweb编写自己的JDBC框架
一、元数据介绍
元数据指的是"数据库"、"表"、"列"的定义信息。
1.1、DataBaseMetaData元数据
Connection.getDatabaseMetaData()获得代表DatabaseMetaData元数据的DatabaseMetaData对象。
DataBaseMetaData对象的常用方法:
getURL():返回一个String类对象,代表数据库的URL。
getUserName():返回连接当前数据库管理系统的用户名。
getDatabaseProductName():返回数据库的产品名称。
getDatabaseProductVersion():返回数据库的版本号。
getDriverName():返回驱动驱动程序的名称。
getDriverVersion():返回驱动程序的版本号。
isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
复制代码
1/
2@Method:testDataBaseMetaData
3@Description:获取数据库的元信息
4@Anthor:孤傲苍狼
5
6@throwsSQLException
7/
8@Test
9publicvoidtestDataBaseMetaData()throwsSQLException{
10Connectionconn=JdbcUtils.getConnection();
11DatabaseMetaDatametadata=conn.getMetaData();
12//getURL():返回一个String类对象,代表数据库的URL
13System.out.println(metadata.getURL());
14//getUserName():返回连接当前数据库管理系统的用户名
15System.out.println(metadata.getUserName());
16//getDatabaseProductName():返回数据库的产品名称
17System.out.println(metadata.getDatabaseProductName());
18//getDatabaseProductVersion():返回数据库的版本号
19System.out.println(metadata.getDatabaseProductVersion());
20//getDriverName():返回驱动驱动程序的名称
21System.out.println(metadata.getDriverName());
22//getDriverVersion():返回驱动程序的版本号
23System.out.println(metadata.getDriverVersion());
24//isReadOnly():返回一个boolean值,指示数据库是否只允许读操作
25System.out.println(metadata.isReadOnly());
26JdbcUtils.release(conn,null,null);
27}
复制代码
运行结果如下:
1.2、ParameterMetaData元数据
PreparedStatement.getParameterMetaData()获得代表PreparedStatement元数据的ParameterMetaData对象。
Selectfromuserwherename=?Andpassword=?
ParameterMetaData对象的常用方法:
getParameterCount():获得指定参数的个数
getParameterType(intparam):获得指定参数的sql类型,MySQL数据库驱动不支持
复制代码
1/
2@Method:testParameterMetaData
3@Description:获取参数元信息
4@Anthor:孤傲苍狼
5
6@throwsSQLException
7/
8@Test
9publicvoidtestParameterMetaData()throwsSQLException{
10Connectionconn=JdbcUtils.getConnection();
11Stringsql="selectfromuserwherername=?andpassword=?";
12//将SQL预编译一下
13PreparedStatementst=conn.prepareStatement(sql);
14ParameterMetaDatapm=st.getParameterMetaData();
15//getParameterCount()获得指定参数的个数
16System.out.println(pm.getParameterCount());
17//getParameterType(intparam):获得指定参数的sql类型,MySQL数据库驱动不支持
18System.out.println(pm.getParameterType(1));
19JdbcUtils.release(conn,null,null);
20}
复制代码
1.3、ResultSetMetaData元数据
ResultSet.getMetaData()获得代表ResultSet对象元数据的ResultSetMetaData对象。
ResultSetMetaData对象的常用方法:
getColumnCount()返回resultset对象的列数
getColumnName(intcolumn)获得指定列的名称
getColumnTypeName(intcolumn)获得指定列的类型
复制代码
1/
2@Method:testResultSetMetaData
3@Description:结果集的元数据
4@Anthor:孤傲苍狼
5
6@throwsException
7/
8@Test
9publicvoidtestResultSetMetaData()throwsException{
10Connectionconn=JdbcUtils.getConnection();
11Stringsql="www.wang027.comselectfromaccount";
12PreparedStatementst=conn.prepareStatement(sql);
13ResultSetrs=st.executeQuery();
14//ResultSet.getMetaData()获得代表ResultSet对象元数据的ResultSetMetaData对象
15ResultSetMetaDatametadata=rs.getMetaData();
16//getColumnCount()返回resultset对象的列数
17System.out.println(metadata.getColumnCount());
18//getColumnName(intcolumn)获得指定列的名称
19System.out.println(metadata.getColumnName(1));
20//getColumnTypeName(intcolumn)获得指定列的类型
21System.out.println(metadata.getColumnTypeName(1));
22JdbcUtils.release(conn,st,rs);
23}
复制代码
二、使用元数据封装简单的JDBC框架
系统中所有实体对象都涉及到基本的CRUD操作
所有实体的CUD操作代码基本相同,仅仅发送给数据库的SQL语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句。
实体的R操作,除SQL语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可义一个query方法,除以参数形式接收变化的SQL语句外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet中的数据映射到实体对象中。
2.1、封装通用的update方法和qurey方法
定义一个JdbcUtils工具类,工具类负责获取数据库连接,释放资源,执行SQL的update和query操作,代码如下:
复制代码
1packageme.gacl.util;
2
3importjava.io.InputStream;
4importjava.sql.Connection;
5importjava.sql.DriverManager;
6importjava.sql.PreparedStatement;
7importjava.sql.ResultSet;
8importjava.sql.SQLException;
9importjava.sql.Statement;
10importjava.util.Properties;
11
12publicclassJdbcUtils{
13
14privatestaticStringdriver=null;
15privatestaticStringurl=null;
16privatestaticStringusername=null;
17privatestaticStringpassword=null;
18
19static{
20try{
21//读取db.properties文件中的数据库连接信息
22InputStreamin=JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
23Propertiesprop=newProperties();
24prop.load(in);
25
26//获取数据库连接驱动
27driver=prop.getProperty("driver");
28//获取数据库连接URL地址
29url=prop.getProperty("url");
30//获取数据库连接用户名
31username=prop.getProperty("username");
32//获取数据库连接密码
33password=prop.getProperty("password");
34
35//加载数据库驱动
36Class.forName(driver);
37
38}catch(Exceptione){
39thrownewExceptionInInitializerError(e);
40}
41}
42
43/
44@Method:getConnection
45@Description:获取数据库连接对象
46@Anthor:孤傲苍狼
47
48@returnConnection数据库连接对象
49@throwsSQLException
50/
51publicstaticConnectiongetConnection()throwsSQLException{
52returnDriverManager.getConnection(url,username,password);
53}
54
55/
56@Method:release
57@Description:释放资源,
58要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
59@Anthor:孤傲苍狼
60
61@paramconn
62@paramst
63@paramrs
64/
65publicstaticvoidrelease(Connectionconn,Statementst,ResultSetrs){
66if(rs!=null){
67try{
68//关闭存储查询结果的ResultSet对象
69rs.close();
70}catch(Exceptione){
71e.printStackTrace();
72}
73rs=null;
74}
75if(st!=null){
76try{
77//关闭负责执行SQL命令的Statement对象
78st.close();
79}catch(Exceptione){
80e.printStackTrace();
81}
82}
83
84if(conn!=null){
85try{
86//关闭Connection数据库连接对象
87conn.close();
88}catch(Exceptione){
89e.printStackTrace();
90}
91}
92}
93
94/
95@Method:update
96@Description:万能更新
97所有实体的CUD操作代码基本相同,仅仅发送给数据库的SQL语句不同而已,
98因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句
99@Anthor:孤傲苍狼
100@paramsql要执行的SQL
101@paramparams执行SQL时使用的参数
102@throwsSQLException
103/
104publicstaticvoidupdate(Stringsql,Objectparams[])throwsSQLException{
105Connectionconn=null;
106PreparedStatementst=null;
107ResultSetrs=null;
108try{
109conn=getConnection();
110st=conn.prepareStatement(sql);
111for(inti=0;i 112st.setObject(i+1,params[i]);
113}
114st.executeUpdate();
115
116}finally{
117release(conn,st,rs);
118}
119}
120
121/
122@Method:query
123@Description:万能查询
124实体的R操作,除SQL语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,
125因此可义一个query方法,除以参数形式接收变化的SQL语句外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet中的数据映射到实体对象中。
126@Anthor:孤傲苍狼
127
128@paramsql要执行的SQL
129@paramparams执行SQL时使用的参数
130@paramrsh查询返回的结果集处理器
131@return
132@throwsSQLException
133/
134publicstaticObjectquery(Stringsql,Objectparams[],ResultSetHandlerrsh)throwsSQLException{
135
136Connectionconn=null;
137PreparedStatementst=null;
138ResultSetrs=null;
139
140try{
141conn=getConnection();
142st=conn.prepareStatement(sql);
143for(inti=0;i 144st.setObject(i+1,params[i]);
145}
146rs=st.executeQuery();
147/
148对于查询返回的结果集处理使用到了策略模式,
149在设计query方法时,query方法事先是无法知道用户对返回的查询结果集如何进行处理的,即不知道结果集的处理策略,
150那么这个结果集的处理策略就让用户自己提供,query方法内部就调用用户提交的结果集处理策略进行处理
151为了能够让用户提供结果集的处理策略,需要对用户暴露出一个结果集处理接口ResultSetHandler
152用户只要实现了ResultSetHandler接口,那么query方法内部就知道用户要如何处理结果集了
153/
154returnrsh.handler(rs);
155
156}finally{
157release(conn,st,rs);
158}
159}
160}
复制代码
在设计query方法时,对于查询返回的结果集处理使用到了策略模式,query方法事先是无法知道用户对返回的查询结果集如何进行处理的,即不知道结果集的处理策略,那么这个结果集的处理策略就让用户自己提供,query方法内部就调用用户提交的结果集处理策略进行处理,为了能够让用户提供结果集的处理策略,需要对用户暴露出一个结果集处理接口ResultSetHandler,结果集处理器接口ResultSetHandler的定义如下:
复制代码
1packageme.gacl.util;
2
3importjava.sql.ResultSet;
4
5/
6@ClassName:ResultSetHandler
7@Description:结果集处理器接口
8@author:孤傲苍狼
9@date:2014-10-5下午12:01:27
10
11/
12publicinterfaceResultSetHandler{
13
14/
15@Method:handler
16@Description:结果集处理方法
17@Anthor:孤傲苍狼
18
19@paramrs查询结果集
20@return
21/
22publicObjecthandler(ResultSetrs);
23}
复制代码
用户只要实现了ResultSetHandler接口,那么就是针对查询结果集写了一个处理器,在query方法内部就调用用户自己写的处理器处理结果集。
2.2、编写常用的结果集处理器
为了提高框架的易用性,我们可以事先就针对结果集写好一些常用的处理器,比如将结果集转换成bean对象的处理器,将结果集转换成bean对象的list集合的处理器。
2.2.1、BeanHandler——将结果集转换成bean对象的处理器
复制代码
1packageme.gacl.util;
2
3importjava.lang.reflect.Field;
4importjava.sql.ResultSet;
5importjava.sql.ResultSetMetaData;
6
7/
8@ClassName:BeanHandler
9@Description:将结果集转换成bean对象的处理器
10@author:孤傲苍狼
11@date:2014-10-5下午12:00:33
12
13/
14publicclassBeanHandlerimplementsResultSetHandler{
15privateClass>clazz;
16publicBeanHandler(Class>clazz){
17this.clazz=clazz;
18}
19publicObjecthandler(ResultSetrs){
20try{
21if(!rs.next()){
22returnnull;
23}
24Objectbean=clazz.newInstance();
25//得到结果集元数据
26ResultSetMetaDatametadata=rs.getMetaData();
27intcolumnCount=metadata.getColumnCount();//得到结果集中有几列数据
28for(inti=0;i 29StringcoulmnName=metadata.getColumnName(i+1);//得到每列的列名
30ObjectcoulmnData=rs.getObject(i+1);
31Fieldf=clazz.getDeclaredField(coulmnName);//反射出类上列名对应的属性
32f.setAccessible(true);
33f.set(bean,coulmnData);
34}
35returnbean;
36}catch(Exceptione){
37thrownewRuntimeException(e);
38}
39}
40}
复制代码
2.2.2、BeanListHandler——将结果集转换成bean对象的list集合的处理器
复制代码
1packageme.gacl.util;
2
3importjava.lang.reflect.Field;
4importjava.sql.ResultSet;
5importjava.sql.ResultSetMetaData;
6importjava.util.ArrayList;
7importjava.util.List;
8
9/
10@ClassName:BeanListHandler
11@Description:将结果集转换成bean对象的list集合的处理器
12@author:孤傲苍狼
13@date:2014-10-5下午12:00:06
14
15/
16publicclassBeanListHandlerimplementsResultSetHandler{
17privateClass>clazz;
18publicBeanListHandler(Class>clazz){
19this.clazz=clazz;
20}
21
22publicObjecthandler(ResultSetrs){
23try{
24List |
|