一、元数据介绍

  元数据指的是"数据库"、"表"、"列"的定义信息。

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     * @throws SQLException
 7     */
 8     @Test
 9     public void testDataBaseMetaData() throws SQLException {
10         Connection conn = JdbcUtils.getConnection();
11         DatabaseMetaData metadata = conn.getMetaData();
12         //getURL():返回一个String类对象,代表数据库的URL
13         System.out.println(metadata.getURL());
14         //getUserName():返回连接当前数据库管理系统的用户名
15         System.out.println(metadata.getUserName());
16         //getDatabaseProductName():返回数据库的产品名称
17         System.out.println(metadata.getDatabaseProductName());
18         //getDatabaseProductVersion():返回数据库的版本号
19         System.out.println(metadata.getDatabaseProductVersion());
20         //getDriverName():返回驱动驱动程序的名称
21         System.out.println(metadata.getDriverName());
22         //getDriverVersion():返回驱动程序的版本号
23         System.out.println(metadata.getDriverVersion());
24         //isReadOnly():返回一个boolean值,指示数据库是否只允许读操作
25         System.out.println(metadata.isReadOnly());
26         JdbcUtils.release(conn, null, null);
27     }

  运行结果如下:

  

1.2、ParameterMetaData元数据

  PreparedStatement.getParameterMetaData() 获得代表PreparedStatement元数据的ParameterMetaData对象。
  Select * from user where name=? And password=?
  ParameterMetaData对象的常用方法:

  • getParameterCount(): 获得指定参数的个数
  • getParameterType(int param):获得指定参数的sql类型,MySQL数据库驱动不支持
 1     /**
 2     * @Method: testParameterMetaData
 3     * @Description: 获取参数元信息
 4     * @Anthor:孤傲苍狼
 5     *
 6     * @throws SQLException
 7     */
 8     @Test
 9     public void testParameterMetaData() throws SQLException {
10         Connection conn = JdbcUtils.getConnection();
11         String sql = "select * from user wherer name=? and password=?";
12         //将SQL预编译一下
13         PreparedStatement st = conn.prepareStatement(sql);
14         ParameterMetaData pm = st.getParameterMetaData();
15         //getParameterCount() 获得指定参数的个数
16         System.out.println(pm.getParameterCount());
17         //getParameterType(int param):获得指定参数的sql类型,MySQL数据库驱动不支持
18         System.out.println(pm.getParameterType(1));
19         JdbcUtils.release(conn, null, null);
20     }

1.3、ResultSetMetaData元数据

  ResultSet. getMetaData() 获得代表ResultSet对象元数据的ResultSetMetaData对象。
  ResultSetMetaData对象的常用方法:

  • getColumnCount() 返回resultset对象的列数
  • getColumnName(int column) 获得指定列的名称
  • getColumnTypeName(int column)获得指定列的类型
 1     /**
 2     * @Method: testResultSetMetaData
 3     * @Description: 结果集的元数据
 4     * @Anthor:孤傲苍狼
 5     *
 6     * @throws Exception
 7     */
 8     @Test
 9     public void testResultSetMetaData() throws Exception {
10         Connection conn = JdbcUtils.getConnection();
11         String sql = "select * from account";
12         PreparedStatement st  = conn.prepareStatement(sql);
13         ResultSet rs = st.executeQuery();
14         //ResultSet.getMetaData()获得代表ResultSet对象元数据的ResultSetMetaData对象
15         ResultSetMetaData metadata = rs.getMetaData();
16         //getColumnCount() 返回resultset对象的列数
17         System.out.println(metadata.getColumnCount());
18         //getColumnName(int column) 获得指定列的名称
19         System.out.println(metadata.getColumnName(1));
20         //getColumnTypeName(int column)获得指定列的类型
21         System.out.println(metadata.getColumnTypeName(1));
22         JdbcUtils.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操作,代码如下:

  1 package me.gacl.util;
  2
  3 import java.io.InputStream;
  4 import java.sql.Connection;
  5 import java.sql.DriverManager;
  6 import java.sql.PreparedStatement;
  7 import java.sql.ResultSet;
  8 import java.sql.SQLException;
  9 import java.sql.Statement;
 10 import java.util.Properties;
 11
 12 public class JdbcUtils {
 13
 14     private static String driver = null;
 15     private static String url = null;
 16     private static String username = null;
 17     private static String password = null;
 18
 19     static{
 20         try{
 21             //读取db.properties文件中的数据库连接信息
 22             InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
 23             Properties prop = new Properties();
 24             prop.load(in);
 25
 26             //获取数据库连接驱动
 27             driver = prop.getProperty("driver");
 28             //获取数据库连接URL地址
 29             url = prop.getProperty("url");
 30             //获取数据库连接用户名
 31             username = prop.getProperty("username");
 32             //获取数据库连接密码
 33             password = prop.getProperty("password");
 34
 35             //加载数据库驱动
 36             Class.forName(driver);
 37
 38         }catch (Exception e) {
 39             throw new ExceptionInInitializerError(e);
 40         }
 41     }
 42
 43     /**
 44     * @Method: getConnection
 45     * @Description: 获取数据库连接对象
 46     * @Anthor:孤傲苍狼
 47     *
 48     * @return Connection数据库连接对象
 49     * @throws SQLException
 50     */
 51     public static Connection getConnection() throws SQLException{
 52         return DriverManager.getConnection(url, username,password);
 53     }
 54
 55     /**
 56     * @Method: release
 57     * @Description: 释放资源,
 58     *     要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
 59     * @Anthor:孤傲苍狼
 60     *
 61     * @param conn
 62     * @param st
 63     * @param rs
 64     */
 65     public static void release(Connection conn,Statement st,ResultSet rs){
 66         if(rs!=null){
 67             try{
 68                 //关闭存储查询结果的ResultSet对象
 69                 rs.close();
 70             }catch (Exception e) {
 71                 e.printStackTrace();
 72             }
 73             rs = null;
 74         }
 75         if(st!=null){
 76             try{
 77                 //关闭负责执行SQL命令的Statement对象
 78                 st.close();
 79             }catch (Exception e) {
 80                 e.printStackTrace();
 81             }
 82         }
 83
 84         if(conn!=null){
 85             try{
 86                 //关闭Connection数据库连接对象
 87                 conn.close();
 88             }catch (Exception e) {
 89                 e.printStackTrace();
 90             }
 91         }
 92     }
 93
 94     /**
 95     * @Method: update
 96     * @Description: 万能更新
 97     * 所有实体的CUD操作代码基本相同,仅仅发送给数据库的SQL语句不同而已,
 98     * 因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句
 99     * @Anthor:孤傲苍狼
100     * @param sql 要执行的SQL
101     * @param params 执行SQL时使用的参数
102     * @throws SQLException
103     */
104     public static void update(String sql,Object params[]) throws SQLException{
105         Connection conn = null;
106         PreparedStatement st = null;
107         ResultSet rs = null;
108         try{
109             conn = getConnection();
110             st = conn.prepareStatement(sql);
111             for(int i=0;i<params.length;i++){
112                 st.setObject(i+1, params[i]);
113             }
114             st.executeUpdate();
115
116         }finally{
117             release(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     * @param sql 要执行的SQL
129     * @param params 执行SQL时使用的参数
130     * @param rsh 查询返回的结果集处理器
131     * @return
132     * @throws SQLException
133     */
134     public static Object query(String sql,Object params[],ResultSetHandler rsh) throws SQLException{
135
136         Connection conn = null;
137         PreparedStatement st = null;
138         ResultSet rs = null;
139
140         try{
141             conn = getConnection();
142             st = conn.prepareStatement(sql);
143             for(int i=0;i<params.length;i++){
144                 st.setObject(i+1, params[i]);
145             }
146             rs = st.executeQuery();
147             /**
148              * 对于查询返回的结果集处理使用到了策略模式,
149              * 在设计query方法时,query方法事先是无法知道用户对返回的查询结果集如何进行处理的,即不知道结果集的处理策略,
150              * 那么这个结果集的处理策略就让用户自己提供,query方法内部就调用用户提交的结果集处理策略进行处理
151              * 为了能够让用户提供结果集的处理策略,需要对用户暴露出一个结果集处理接口ResultSetHandler
152              * 用户只要实现了ResultSetHandler接口,那么query方法内部就知道用户要如何处理结果集了
153              */
154             return rsh.handler(rs);
155
156         }finally{
157             release(conn, st, rs);
158         }
159     }
160 }

  在设计query方法时,对于查询返回的结果集处理使用到了策略模式,query方法事先是无法知道用户对返回的查询结果集如何进行处理的,即不知道结果集的处理策略, 那么这个结果集的处理策略就让用户自己提供,query方法内部就调用用户提交的结果集处理策略进行处理, 为了能够让用户提供结果集的处理策略,需要对用户暴露出一个结果集处理接口ResultSetHandler, 结果集处理器接口ResultSetHandler的定义如下:

 1 package me.gacl.util;
 2
 3 import java.sql.ResultSet;
 4
 5 /**
 6 * @ClassName: ResultSetHandler
 7 * @Description:结果集处理器接口
 8 * @author: 孤傲苍狼
 9 * @date: 2014-10-5 下午12:01:27
10 *
11 */
12 public interface ResultSetHandler {
13
14     /**
15     * @Method: handler
16     * @Description: 结果集处理方法
17     * @Anthor:孤傲苍狼
18     *
19     * @param rs 查询结果集
20     * @return
21     */
22     public Object handler(ResultSet rs);
23 }

  用户只要实现了ResultSetHandler接口,那么就是针对查询结果集写了一个处理器,在query方法内部就调用用户自己写的处理器处理结果集。

2.2、编写常用的结果集处理器

  为了提高框架的易用性,我们可以事先就针对结果集写好一些常用的处理器,比如将结果集转换成bean对象的处理器,将结果集转换成bean对象的list集合的处理器。

2.2.1、BeanHandler——将结果集转换成bean对象的处理器

 1 package me.gacl.util;
 2
 3 import java.lang.reflect.Field;
 4 import java.sql.ResultSet;
 5 import java.sql.ResultSetMetaData;
 6
 7 /**
 8 * @ClassName: BeanHandler
 9 * @Description: 将结果集转换成bean对象的处理器
10 * @author: 孤傲苍狼
11 * @date: 2014-10-5 下午12:00:33
12 *
13 */
14 public class BeanHandler implements ResultSetHandler {
15     private Class<?> clazz;
16     public BeanHandler(Class<?> clazz){
17         this.clazz = clazz;
18     }
19     public Object handler(ResultSet rs) {
20         try{
21             if(!rs.next()){
22                 return null;
23             }
24             Object bean = clazz.newInstance();
25             //得到结果集元数据
26             ResultSetMetaData metadata = rs.getMetaData();
27             int columnCount = metadata.getColumnCount();//得到结果集中有几列数据
28             for(int i=0;i<columnCount;i++){
29                 String coulmnName = metadata.getColumnName(i+1);//得到每列的列名
30                 Object coulmnData = rs.getObject(i+1);
31                 Field f = clazz.getDeclaredField(coulmnName);//反射出类上列名对应的属性
32                 f.setAccessible(true);
33                 f.set(bean, coulmnData);
34             }
35             return bean;
36         }catch (Exception e) {
37             throw new RuntimeException(e);
38         }
39     }
40 }

2.2.2、BeanListHandler——将结果集转换成bean对象的list集合的处理器

 1 package me.gacl.util;
 2
 3 import java.lang.reflect.Field;
 4 import java.sql.ResultSet;
 5 import java.sql.ResultSetMetaData;
 6 import java.util.ArrayList;
 7 import java.util.List;
 8
 9 /**
10 * @ClassName: BeanListHandler
11 * @Description: 将结果集转换成bean对象的list集合的处理器
12 * @author: 孤傲苍狼
13 * @date: 2014-10-5 下午12:00:06
14 *
15 */
16 public class BeanListHandler implements ResultSetHandler {
17     private Class<?> clazz;
18     public BeanListHandler(Class<?> clazz){
19         this.clazz = clazz;
20     }
21
22     public Object handler(ResultSet rs) {
23         try{
24             List<Object> list = new ArrayList<Object>();
25             while(rs.next()){
26                 Object bean = clazz.newInstance();
27
28                 ResultSetMetaData  metadata = rs.getMetaData();
29                 int count = metadata.getColumnCount();
30                 for(int i=0;i<count;i++){
31                     String name = metadata.getColumnName(i+1);
32                     Object value = rs.getObject(name);
33
34                     Field f = bean.getClass().getDeclaredField(name);
35                     f.setAccessible(true);
36                     f.set(bean, value);
37                 }
38                 list.add(bean);
39             }
40             return list.size()>0?list:null;
41
42         }catch (Exception e) {
43             throw new RuntimeException(e);
44         }
45     }
46 }

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

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

 1 package me.gacl.dao;
 2
 3 import java.sql.SQLException;
 4 import java.util.List;
 5 import me.gacl.domain.Account;
 6 import me.gacl.util.BeanHandler;
 7 import me.gacl.util.BeanListHandler;
 8 import me.gacl.util.JdbcUtils;
 9
10 public class AccountDao {
11
12     public void add(Account account) throws SQLException{
13         String sql = "insert into account(name,money) values(?,?)";
14         Object params[] = {account.getName(),account.getMoney()};
15         JdbcUtils.update(sql, params);
16     }
17
18
19     public void delete(int id) throws SQLException{
20         String sql = "delete from account where id=?";
21         Object params[] = {id};
22         JdbcUtils.update(sql, params);
23     }
24
25     public void update(Account account) throws SQLException{
26
27         String sql = "update account set name=?,money=? where id=?";
28         Object params[] = {account.getName(),account.getMoney(),account.getId()};
29         JdbcUtils.update(sql, params);
30
31     }
32
33     public Account find(int id) throws SQLException{
34         String sql = "select * from account where id=?";
35         Object params[] = {id};
36         return (Account) JdbcUtils.query(sql, params, new BeanHandler(Account.class));
37     }
38
39     public List<Account> getAll() throws SQLException{
40         String sql = "select * from account";
41         Object params[] = {};
42         return (List<Account>) JdbcUtils.query(sql, params,new BeanListHandler(Account.class));
43     }
44 }

  编写的这个JDBC框架就是模拟Apache的DBUtils框架的实现,下一篇将具体介绍Apache的DBUtils框架。

javaweb学习总结(四十)——编写自己的JDBC框架相关推荐

  1. JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet

    一.Servlet的传统配置方式 在JavaWeb开发中, 每次编写一个Servlet都需要在web.xml文件中进行配置,如下所示: 1 <servlet> 2 <servlet- ...

  2. javaweb学习总结(四十六)——Filter(过滤器)常见应用

    2019独角兽企业重金招聘Python工程师标准>>> 一.统一全站字符编码 通过配置参数charset指明使用何种字符编码,以处理Html Form请求参数的中文问题 1 pack ...

  3. JavaWeb学习总结(四十九)——简单模拟Sping MVC

    在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下: ...

  4. javaweb学习总结(四十四)——监听器(Listener)学习

    一.监听器介绍 1.1.监听器的概念 监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动.监听器其实就是一个实现特定接口的普通 ...

  5. javaweb学习总结(四十二)——Filter(过滤器)学习

    一.Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态 ...

  6. javaweb学习总结(四十五)——监听器(Listener)学习二

    一.监听域对象中属性的变更的监听器 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信 ...

  7. javaweb学习总结(二十五)——Apache的DBUtils框架学习

    一.commons-dbutils简介 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化 ...

  8. javaweb学习总结(三十九)——数据库连接池

    javaweb学习总结(三十九)--数据库连接池 一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10 ...

  9. 孤傲苍狼 只为成功找方法,不为失败找借口! javaweb学习总结(三十九)——数据库连接池 一、应用程序直接获取数据库连接的缺点   用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要

    孤傲苍狼 只为成功找方法,不为失败找借口! javaweb学习总结(三十九)--数据库连接池 一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对 ...

最新文章

  1. SQL SERVER中什么情况会导致索引查找变成索引扫描
  2. linux GDB 简单用法以及例子
  3. Understand Tasks and Back Stack--Defining launch modes
  4. xrkmonitor监控mysql_xrkmonitor字符云监控系统
  5. 【翻译】Ext JS 4——Ajax和Rest代理处理服务器端一场和消息的方法
  6. 5911. 模拟行走机器人 II
  7. 《剑指Offer》37:序列化二叉树
  8. 数模写作必备利器—latex
  9. php类中引函数变量,一个非线性差分方程的隐函数解
  10. 为什么用java开发app_安卓开发为什么选择用Java语言
  11. gradle是干什么_gradle和ant等构建工具有什么核心优势?
  12. 电信业降薪可能并不完全是空穴来风
  13. Python入门--获取指定目录下的所有.py文件
  14. [BZOJ1594] [Usaco2008 Jan]猜数游戏(二分 + 并查集)
  15. atitit.避免NullPointerException 总结and 最佳实践 o99
  16. 基于VHD和grub4dos的秒还原系统
  17. chm打不开怎么办?
  18. Matlab二维正态分布可视化
  19. Intel_IPP 的基本使用方法
  20. 南柯33的Python学习笔记第(一)部分

热门文章

  1. hadoop + spark+ hive 集群搭建(apache版本)
  2. R语言CRAN软件包Meta分析
  3. kafka设计与原理
  4. android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)...
  5. OpenStack 通用设计思路 - 每天5分钟玩转 OpenStack(25)
  6. java中String对象和String变量
  7. memcahce 介绍以及安装以及扩展的安装
  8. ie8开发人员工具无法使用,按f12任务栏里出现任务,但是窗体不弹出
  9. 一个在菜场看到的,神一般的大爷!
  10. Ptthon学习记录(八)-------list和元组