码迷,mamicode.com
首页 > 数据库 > 详细

JDBC框架的编写

时间:2015-07-14 22:04:23      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:

JDBC框架
直接使用JDBC开发,非常麻烦,步骤繁琐,所以在企业开发Web程序时,连接数据库进行操作都是通过JDBC框架来完成的
知识点
1,JDBC元数据API(编写JDBC框架基础)
2,框架编写思想
3,Apache DBUtils(tomcat的JDBC框架)

数据库元数据(metadata)
数据库存储结构定义信息(库,表,记录,列的定义信息)
DataBaseMetaData数据库元数据
Connection.getMetaData();通过连接获得数据库元数据信息
getURL():返回一个String类对象,代表数据库的URL。
getUserName():返回连接当前数据库管理系统的用户名。
getDriverName():返回驱动驱动程序的名称。
getPrimaryKeys(String catalog, String schema, String table):返回指定表主键的结果集

参数元数据
ParameterMetaData
通过预编译对象PreparedStatement获得
String sql="select * from users where username=? and password=?";
PreparedStament preparedStatement=conn.preparedStatement(sql);
preparedStatement.getParameterMetaData();//通过参数元数据对象可以获得?参数的信息。
getParameterCount() 获得指定参数的个数
getParameterType(int param) 获得指定参数的sql类型
注意getParameterType方法并不是所有的数据库都支持mysql就不支持,回报异常,异常处理 Parameter metadata not available for the given statement
在数据库连接池配置文件中url后面拼接参数 ?generateSimpleParameterMetadata=true,但是即使是这样该方法的返回值都是varchar

结果集元数据
ResultSetMetaData
ResultSet. getMetaData() 获得代表ResultSet对象元数据的ResultSetMetaData对象。
getColumnCount() 返回resultset对象的列数
getColumnName(int column) 获得指定列的名称  
getColumnTypeName(int column) 获得指定列的类型

使用元数据简化JDBC代码
在实际业务背景下,系统中所有实体对象都涉及到基本的CRUD操作;所有的CUD操作代码基本相同,仅仅是发送给数据库的SQL语句不同而已,因此可以把操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句
当然实体的R操作除了SQL语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此一个query方法,除了以参数形式接收变化的SQL语句之外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet的数据映射到实体对象中。
DAO模式结合自定义JDBC框架framework

DAO模式编写JvaBean,Account类

public class Account {
    private int id;
    private String name;
    private double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

}

在未使用框架时编写AccountDAO

public void insertAccount(Account account) {
        Connection conn = null;
        PreparedStatement stmt = null;

        try {
            conn = JDBCUtils.getConnection();
            String sql = "insert into account values(null,?,?)";

            stmt = conn.prepareStatement(sql);
            // 设置参数
            stmt.setString(1, account.getName());
            stmt.setDouble(2, account.getMoney());

            stmt.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(stmt, conn);
        }
    }

通过不同对象DAO模式下的SQL操作比较对方法进行提取编写通用框架

public static void update(String sql, Object... args) {
        Connection conn = null;
        PreparedStatement stmt = null;

        try {
            conn = JDBCUtils.getConnection();

            stmt = conn.prepareStatement(sql);
            // 设置参数 --- 根据?设置参数
            ParameterMetaData parameterMetaData = stmt.getParameterMetaData();
            int count = parameterMetaData.getParameterCount();
            for (int i = 1; i <= count; i++) {
                stmt.setObject(i, args[i - 1]);
            }

            stmt.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(stmt, conn);
        }
    }

在使用框架之后写的AccountDAO

public void insertAccount(Account account) {
    String sql = "insert into account values(null,?,?)";
    Object[] params={account.getNmae(),account.getMoney()}
    JDBCFramework.update(sql,params)
    

}

通用框架的编写使用在后来可以不断重复使用,大大的简化了开发。但是上面的通用框架方法只适合CUD增删改,对于查询R来说是不能使用的,所以需要单独进行抽取编写框架方法

在未使用框架时

public Account findById(int id) {
     Connection conn = null;
     PreparedStatement stmt = null;
     ResultSet rs = null;
    Account account = null;
    
     try {
    conn = JDBCUtils.getConnection();
    String sql = "select * from account where id = ?";
    
     stmt = conn.prepareStatement(sql);
    
    //设置参数
    stmt.setInt(1, id);
    
     rs = stmt.executeQuery();
    if (rs.next()) {
    account = new Account();
    account.setId(rs.getInt("id"));
    account.setName(rs.getString("name"));
     account.setMoney(rs.getDouble("money"));
    }

    } catch (SQLException e) {
    e.printStackTrace();
     } finally {
    JDBCUtils.release(rs, stmt, conn);
     }
    
     return account;
     }

编写框架

public static <T> T query(String sql, MyResultSetHandler<T> handler,
            Object... args) {
        T obj = null;

        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;

        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.prepareStatement(sql);

            // 设置参数
            ParameterMetaData parameterMetaData = stmt.getParameterMetaData();
            int count = parameterMetaData.getParameterCount();
            for (int i = 1; i <= count; i++) {
                stmt.setObject(i, args[i - 1]);
            }

            rs = stmt.executeQuery();
            obj = handler.handle(rs);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(rs, stmt, conn);
        }
        return obj;
    }

要另外定义接口将rs结果集中的数据封装成一个对象

public interface MyResultSetHandler<T> {
    // 将rs中数据封装对象
    public T handle(ResultSet rs);
}

使用框架之后

public Account findById(int id) {
        // 使用自定义框架
        String sql = "select * from account where id = ?";
        MyResultSetHandler handler = new MyResultSetHandler() {//内部类实现框架的接口封装数据。但是每次都要实现 MyResultSetHandler接口,手动完成数据的封装的动作,所以此动作依然可以继续向上抽取。
            @Override
            public Object handle(ResultSet rs) {
                try {
                    if (rs.next()) {
                        Account account = new Account();
                        account.setId(rs.getInt("id"));
                        account.setName(rs.getString("name"));
                        account.setMoney(rs.getDouble("money"));
                        return account;
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                return null;
            }
        };

        return (Account) JDBCFramework.query(sql, handler, id);
    }
内部类实现框架的接口封装数据。但是每次都要实现 MyResultSetHandler接口,手动完成数据的封装的动作,所以此动作依然可以继续向上抽取。
将封装结果集数据的动作进行向上提取,利用泛型和反射在框架中编写通用的Handler程序,☆难点。
public class MyBeanHandler<T> implements MyResultSetHandler<T> {

    private Class<T> domainClass;

    public MyBeanHandler(Class<T> domainClass) {//泛型是存在编译时期的,要创建T泛型的实例,需要将具体类的字节码文件对象传入利用反射技术去创建对象。
        this.domainClass = domainClass;
    }

    @Override
    public T handle(ResultSet rs) {//用泛型去指代返回的数据类型。
        try {
            ResultSetMetaData resultSetMetaData = rs.getMetaData();// 结果集元数据
            int count = resultSetMetaData.getColumnCount();

            BeanInfo beanInfo = Introspector.getBeanInfo(domainClass);//使用内省技术获得字节码文件对象的属性描述器。
            PropertyDescriptor[] descriptors = beanInfo
                    .getPropertyDescriptors();
            if (rs.next()) {
                T t = domainClass.newInstance();//此处获得T的实例对象
                for (int i = 1; i <= count; i++) {
                    String columnName = resultSetMetaData.getColumnName(i);
                    // 获得列名 --- 需要去查找匹配属性
                    for (PropertyDescriptor propertyDescriptor : descriptors) {
                        if (columnName.equals(propertyDescriptor.getName())) {
                            // 列名 存在 同名属性 ---- 列值 存到属性里
                            Method writeMethod = propertyDescriptor
                                    .getWriteMethod(); // setName setMoney
                            writeMethod.invoke(t, rs.getObject(columnName));
                        }
                    }
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

最后简化出的DAO下的查询方法

public Account findById(int id) {
        String sql = "select * from account where id = ?";
        return JDBCFramework.query(sql,new MyBeanHandler<Account>(Account.class),id)
}

 

JDBC框架的编写

标签:

原文地址:http://www.cnblogs.com/ss561/p/4646426.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!