配色: 字号:
javaweb编写自己的JDBC框架
2016-08-27 | 阅:  转:  |  分享 
  
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{

15privateClassclazz;

16publicBeanHandler(Classclazz){

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{

17privateClassclazz;

18publicBeanListHandler(Classclazz){

19this.clazz=clazz;

20}

21

22publicObjecthandler(ResultSetrs){

23try{

24Listlist=newArrayList();

25while(rs.next()){

26Objectbean=clazz.newInstance();

27

28ResultSetMetaDatametadata=rs.getMetaData();

29intcount=metadata.getColumnCount();

30for(inti=0;i
31Stringname=metadata.getColumnName(i+1);

32Objectvalue=rs.getObject(name);

33

34Fieldf=bean.getClass().getDeclaredField(name);

35f.setAccessible(true);

36f.set(bean,value);

37}

38list.add(bean);

39}

40returnlist.size()>0?list:null;

41

42}catch(Exceptione){

43thrownewRuntimeException(e);

44}

45}

46}

复制代码

当框架自身提供的结果集处理器不满足用户的要求时,那么用户就可以自己去实现ResultSetHandler接口,编写满足自己业务要求的结果集处理器。



有了上述的JdbcUtils框架之后,针对单个实体对象CRUD操作就非常方便了,如下所示:



复制代码

1packageme.gacl.dao;

2

3importjava.sql.SQLException;

4importjava.util.List;

5importme.gacl.domain.Account;

6importme.gacl.util.BeanHandler;

7importme.gacl.util.BeanListHandler;

8importme.gacl.util.JdbcUtils;

9

10publicclassAccountDao{

11

12publicvoidadd(Accountaccount)throwsSQLException{

13Stringsql="insertintoaccount(name,money)values(?,?)";

14Objectparams[]={account.getName(),account.getMoney()};

15JdbcUtils.update(sql,params);

16}

17

18

19publicvoiddelete(intid)throwsSQLException{

20Stringsql="deletefromaccountwhereid=?";

21Objectparams[]={id};

22JdbcUtils.update(sql,params);

23}

24

25publicvoidupdate(Accountaccount)throwsSQLException{

26

27Stringsql="updateaccountsetname=?,money=?whereid=?";

28Objectparams[]={account.getName(),account.getMoney(),account.getId()};

29JdbcUtils.update(sql,params);

30

31}

32

33publicAccountfind(intid)throwsSQLException{

34Stringsql="selectfromaccountwhereid=?";

35Objectparams[]={id};

36return(Account)JdbcUtils.query(sql,params,newBeanHandler(Account.class));

37}

38

39publicListgetAll()throwsSQLException{

40Stringsql="selectfromaccount";

41Objectparams[]={};

42return(List)JdbcUtils.query(sql,params,newBeanListHandler(Account.class));

43}

44}

献花(0)
+1
(本文系thedust79首藏)