一、元数据介绍
元数据指的是"数据库"、"表"、"列"的定义信息。
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类对象,代表数据库的URL13 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 要执行的SQL101 * @param params 执行SQL时使用的参数102 * @throws SQLException103 */ 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
在设计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:2710 *11 */ 12 public interface ResultSetHandler {13 14 /**15 * @Method: handler16 * @Description: 结果集处理方法17 * @Anthor:孤傲苍狼18 *19 * @param rs 查询结果集20 * @return21 */ 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:3312 *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
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: BeanListHandler11 * @Description: 将结果集转换成bean对象的list集合的处理器12 * @author: 孤傲苍狼13 * @date: 2014-10-5 下午12:00:0614 *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
当框架自身提供的结果集处理器不满足用户的要求时,那么用户就可以自己去实现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 ListgetAll() throws SQLException{40 String sql = "select * from account";41 Object params[] = {};42 return (List ) JdbcUtils.query(sql, params,new BeanListHandler(Account.class));43 }44 }