jdbc元数据_自定义O-R Mapping照射框架
jdbc元数据_自定义O-R Mapping映射框架
类似于javase的反射
0 元数据概念:
a) 数据的定义数据
b) 数据库,表,列等信息也是一种对象,他们也是由最基础的数据组建而成,基础组件就叫做元数据。
1 数据库元数据: DataBaseMetaData
a) 获取方式: connection.getMetaData();
b) 常用方法说明:
getURL() | 返回一个String类对象,代表数据库的URL。 |
getUserName() | 返回连接当前数据库管理系统的用户名。 |
getDatabaseProductName() | 返回数据库的产品名称。 |
getDatabaseProductVersion() | 返回数据库的版本号 |
getDriverName() | 返回驱动驱动程序的名称 |
getDriverVersion() | 返回驱动程序的版本号 |
isReadOnly() | 返回一个boolean值,指示数据库是否只允许读操作 |
代码如下:
public static void main(String[] args) { try { Connection conn = JdbcUtils.getConnection(); DatabaseMetaData dbmetadata = conn.getMetaData(); String url = dbmetadata.getURL(); String username = dbmetadata.getUserName(); String dbProName = dbmetadata.getDatabaseProductName(); String dbProVersion = dbmetadata.getDatabaseProductVersion(); String driverName = dbmetadata.getDriverName(); String diriverVersion = dbmetadata.getDriverVersion(); boolean readonly = dbmetadata.isReadOnly(); System.out.println("url: " + url); System.out.println("username: " + username); System.out.println("dbProName: " + dbProName); System.out.println("dbProVersion: " + dbProVersion); System.out.println("driverName: " + driverName); System.out.println("diriverVersion: " + diriverVersion); System.out.println("readonly: " + readonly); } catch (SQLException e) { e.printStackTrace(); } } 结果: url: jdbc:mysql://localhost:3306/jdbc username: root@localhost dbProName: MySQL dbProVersion: 5.0.96-community-nt driverName: MySQL-AB JDBC Driver diriverVersion: mysql-connector-java-5.0.8 ( Revision: ${svn.Revision} ) readonly: false
2 参数元数据:
a) 获取方式: preparedStatement.getParameterMetaData();
b) 常用方法说明:
getParameterCount() | 获得指定参数的个数 |
getParameterType(int param) | 获得指定参数的sql类型 |
代码如下:
// 参数元数据 public static void test1(){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "select * from account where id=? and name=?"; st = conn.prepareStatement(sql); ParameterMetaData meta = st.getParameterMetaData(); System.out.println(meta.getParameterCount()); //int i = meta.getParameterType(1); // 1 数据类型都放在 Types, in java.sql.Types中,用整数表示 2 mysql驱动对此方法支持不利 方法执行不了 System.out.println(i); }catch(Exception e){ e.printStackTrace(); } finally { JdbcUtils.release(rs, st, conn); } } 结果: 2
3 结果集元数据:
a) 获取方式:resultSet.getMetaData();
b) 常用方法说明:
getColumnCount() | 返回resultset对象的列数 |
getColumnName(int column) | 获得指定列的名称 |
getColumnTypeName(int column) | 获得指定列的类型 |
代码如下:
// 结果集元数据 public static void test2(){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "select * from user"; st = conn.prepareStatement(sql); rs = st.executeQuery(); ResultSetMetaData meta = rs.getMetaData(); System.out.println(meta.getColumnCount()); System.out.println(meta.getColumnName(2)); // 参数角标从1开始 }catch(Exception e){ e.printStackTrace(); } finally { JdbcUtils.release(rs, st, conn); } } 结果为: 5 name
4 自定义o-r mapping映射框架实现dml:
a) 所有实体的CUD操作代码基本相同,仅仅发送给数据库的SQL语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句。
b) 实体的R操作,除SQL语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可义一个query方法,除以参数形式接收变化的SQL语句外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet中的数据映射到实体对象中。
c) 在查询中,因为使用到反射,因此表中属性要和javabean属性保持一致(大小写),否则映射不过去报java.lang.NoSuchFieldException
代码如下:
自定义o-r mappping dml写法: interface ResultSetHandler{ public Object handler(ResultSet rs); } /** * 把查询结果封装到bean中 * public Customer find(int id) throws SQLException { String sql = "select id,name,sex,birthday,cellphone,email,preference,type,description from customer where id=?"; Object params[] = {id}; return (Customer) JdbcUtils.query(sql, params, new BeanHandler(Customer.class)); } * */ class BeanHandler implements ResultSetHandler{ // 封装到实际对象的类型 private Class clazz; public BeanHandler(Class clazz){ this.clazz = clazz; } // javabean数据封装 public Object handler(ResultSet rs) { try{ Object obj = clazz.newInstance(); if(!rs.next()){ return null; } ResultSetMetaData meta = rs.getMetaData(); int count = meta.getColumnCount(); for(int i=0;i<count;i++){ // 得到每一列 的名称和值 String columnName = meta.getColumnName(i+1); Object value = rs.getObject(i+1); // 通过反射得到 每一列列名 区域,然后在把值给设置进来 Field f = clazz.getDeclaredField(columnName); f.setAccessible(true); f.set(obj, value); } return obj; }catch(Exception e){ throw new RuntimeException(e); } } } /** * 把查询结果封装到集合中 * public List getAll() throws SQLException{ String sql = "select * from customer"; Object params[] = {}; return (List) JdbcUtils.query(sql, params, new ListBeanHandler(Customer.class)); } */ class ListBeanHandler implements ResultSetHandler{ private Class clazz; public ListBeanHandler(Class clazz){ this.clazz = clazz; } public Object handler(ResultSet rs) { try{ if(rs==null){ return null; } ResultSetMetaData meta = rs.getMetaData(); int count = meta.getColumnCount(); List list = new ArrayList(); while(rs.next()){ Object obj = clazz.newInstance(); for(int i=0;i<count;i++){ String columnName = meta.getColumnName(i+1); Object value = rs.getObject(i+1); Field f = clazz.getDeclaredField(columnName); f.setAccessible(true); f.set(obj, value); } list.add(obj); } return list; }catch(Exception e){ throw new RuntimeException(e); } } } public class JdbcUtils { /*private static String driver = "com.mysql.jdbc.Driver"; private static String url = "jdbc:mysql://localhost:3306/jdbc2"; private static String username = "root"; private static String password = "root";*/ /* private static String driver = "oracle.jdbc.driver.OracleDriver"; private static String url = "jdbc:oracle:thin:@localhost:1521:orcl"; private static String username = "scott"; private static String password = "tiger";*/ private static String driver = null; private static String url = null; private static String username = null; private static String password = null; static{ try { InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("bj/util/db.properties"); Properties prop = new Properties(); prop.load(in); driver = prop.getProperty("driver"); url = prop.getProperty("url"); username = prop.getProperty("username"); password = prop.getProperty("password"); Class.forName(driver); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException{ return DriverManager.getConnection(url,username,password); } public static void release(ResultSet rs,Statement st,Connection conn){ if(rs!=null) { try{ rs.close(); }catch(Exception e){ e.printStackTrace(); } rs = null; } if(st!=null) { try{ st.close(); }catch(Exception e){ e.printStackTrace(); } st = null; } if(conn!=null){ try{ conn.close(); }catch(Exception e){ e.printStackTrace(); } conn = null; } } /* * DBUtils工具类的 增删改 原理代码 * 用Object数组接受传递参数的个数和类型 */ public static void update(String sql,Object params[]) throws SQLException{ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils.getConnection(); st = conn.prepareStatement(sql); for(int i=0;i<params.length;i++){ st.setObject(i+1, params[i]);// 给参数赋值时,PreparedStatement角标从1开始,因此第一个参数为i+1 } st.executeUpdate(); }finally{ JdbcUtils.release(rs, st, conn); } } /* * 策略模式:1 在查询到数据后,让方法的调用者来处理 获取db数据和映射实体之间转换工作, 2 定义公共接口约定调用者实现细则时要遵守的细则 * DBUtils工具类的 查询 原理代码 */ public static Object query(String sql,Object params[],ResultSetHandler rh) throws SQLException{ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ conn = JdbcUtils.getConnection(); st = conn.prepareStatement(sql); for(int i=0;i<params.length;i++){ st.setObject(i+1,params[i]); } rs = st.executeQuery(); // 交给调用者传递的处理类将db返回结果和业务实体bean封装 return rh.handler(rs); }finally{ JdbcUtils.release(rs, st, conn); } } }
5 常用O-R Mapping映射工具
a) Hibernate:现在用的少了
b) Ibatis: 现在一般用的是 mybatis
c) Commons DbUtils(只是对JDBC简单封装)