zoukankan      html  css  js  c++  java
  • 自定义数据库框架

    自定义数据库框架

    我们以前写过的DAO,其中有多少冗余代码!分析一下,找出冗余代码,把共同的部分写成方法,把不同的地方写为方法参数。做成一个工具类,就叫QueryRunner

    QueryRunner.java

    获取DataSource

    private   DataSource ds;

            

             public  QueryRunner(DataSource ds)

             {

                       this.ds=ds;

             }

     

    增删改:只有SQL语句,以及参数不同,其它都相同;

    public void update (String sql,Object []objs)

           {

                  Connection   con=null;

                  PreparedStatement   st=null;

                  try {

                         con=ds.getConnection();

                         st=con.prepareStatement(sql);

                  //得到参数的元数据

                         ParameterMetaData   pmd=st.getParameterMetaData();

                  //参数的个数

                         int count=pmd.getParameterCount();

                         if(count>0)

                         {

                                if(objs==null   || objs.length==0){

                                       throw new   RuntimeException("参数不能为空");

                                }

                                else if(count!=objs.length){

                                       throw new   RuntimeException("参数个数不匹配");

                                }

                                for (int   i = 0; i < count; i++) {

                                       st.setObject(i+1,   objs[i]);

                                }

                         }

                         st.executeQuery();

                  }   catch (SQLException e) {

                         e.printStackTrace();

                  }

           }

    查询:SQL语句不同,参数不同,还有对ResultSet的处理不同!有反把ResultSet映射成Student,还有映射成List<Student>。当然,如果写UserDao,那么还要把ResultSet映射成User或List<User>。

    public Object query(String sql,ResultSetHandler   resultHandler,Object []objs)

           {

                  Connection con=null;

                  PreparedStatement st=null;

                  ResultSet rs=null;

                  Object obj=null;

                 

                  try {

                         con=ds.getConnection();

                         st=con.prepareStatement(sql);

                        

                         ParameterMetaData   pmd=st.getParameterMetaData();

                         int count=pmd.getParameterCount();

                         if(count>0){

                                if(objs==null||objs.length==0)

                                {

                                       System.out.println("参数不能为空");

                                }else if(objs.length!=count)

                                {

                                       System.out.println("参数不匹配");

                                }

                                for(int   i=0;i<count;i++)

                                {

                                       st.setObject(i+1,   objs[i]);

                                }

                         }

                        

                         rs=st.executeQuery();

                        

                         obj =   resultHandler.handler(rs);

                  } catch (SQLException e) {

                         e.printStackTrace();

                  }

                 

                  return obj;

           }

      

    查询结果集处理

    查操作还有一个问题,查操作不只是SQL语句和参数不同,还有把ResultSet映射成什么样子的对象也不同!把结果集映射成什么对象,这应该由用来完成!

    因为把结果集映射成一个对象,不是数据,而是动作,那么这种问题就不能通过传递一个普通的参数来处理了,而是传递一个动作给我们的查方法!传递动作就是传递方法,这时你应该写一个接口。

    策略模式:把算法提取出来!

    public interface ResultSetHandler {

           Object   handler(ResultSet rs);

    }

     

    如果结果集是一条记录

    注意:可以把结果集转换成Bean对象!要求列名称与Bean属性名称必须一致!

    public class BeanHandler implements ResultSetHandler {

           private Class clz;

           public BeanHandler (Class<Account>   clz)

           {

                  this.clz=clz;

           }

           public Object handler(ResultSet rs) {

                  Object   obj=null;

                  try {

                  if(rs.next())

                  {

                                obj=clz.newInstance();

                                //获取结果集的元数据

                                ResultSetMetaData   rsmd = rs.getMetaData();

                                int count = rsmd.getColumnCount();//得到列数

                                for (int   i = 0; i < count; i++) {

                                       //列的名字

                                       String   columnName=rsmd.getColumnName(i+1);

                                       //每一列的值

                                       Object   columnValue=rs.getObject(i+1);

                                       Field   f=clz.getDeclaredField(columnName);

                                       f.setAccessible(true);

                                       f.set(obj,   columnValue);

                                }

                  }

                         }   catch (Exception e) {

                                e.printStackTrace();

                         }

                  return obj;

           }

    }

    结果集是多条记录

    public class BeanListHandler implements ResultSetHandler {

           private Class clz;

           public BeanListHandler (Class<Account>   clz)

           {

                  this.clz=clz;

           }

    public List   handler(ResultSet rs) {

                  List   list=new ArrayList();

                  Object   obj=null;

                  try {

                         while(rs.next())

                  {

                                obj=clz.newInstance();

                                //获取结果集的元数据

                                ResultSetMetaData   rsmd = rs.getMetaData();

                                int count = rsmd.getColumnCount();//得到列数

                                for (int   i = 0; i < count; i++) {

                                       //列的名字

                                       String   columnName=rsmd.getColumnName(i+1);

                                       //每一列的值

                                       Object   columnValue=rs.getObject(i+1);

                                      

                                       Field   f=clz.getDeclaredField(columnName);

                                       f.setAccessible(true);

                                       f.set(obj,   columnValue);

                                       list.add(obj);

                                }

                  }

                         }   catch (Exception e) {

                                e.printStackTrace();

                         }

                  return   list;

           }

    }

    测试类

    public class defineFrame {

           public static   void main(String[] args) {

                  QueryRunner   qr = new QueryRunner(c3p0Util.getDataSource());

                  qr.update("insert into account   values(?,?,?)",new Object []{6,"aj",1000});

                 

                  List<Account>   account = (List<Account>)qr.query("select   * from account", new   BeanListHandler(Account.class),null);

                  System.out.println(account);

                  qr.update("delete from account where   id=?",new Object []{6});

           }

    }

    ORM简介

    1 ORM是什么?

      ORM(Object/Relation Mapping)就是对象-关系的映射,对象就是Java这种面向对象语言,关系就是关系型数据库,其实就是把一个对象映射成表的一行记录,再把表的一行记录映射成Java中的一个对象。这就是ORM的用途!

    2 常用ORM工具(JDBC框架)

    l  Apache commons DBUtils:很简单的JDBC框架,很多公司在使用它,就是因为它内容很简单,也很方便;

    l  Hibernate(全自动):SSH中的H就是它了,它的HQL号称是面向对象的查询语言;

    l  Ibatis(半自动):简单、方便!很多人用“全自动”形容Hibernate,那么对Ibatis就是“半自动”了。Hibernate把面向关系的东西都封装起来了,甚至你可能对SQL不是很了解都可以通过Hibernate来操作数据库!但是,有是我们还是需要自己来通过面向关系(打开封装)来完成一些特殊的操作,那么“半自动”的Ibatis就派上用场了;

    l  Spring-JDBC(基本与DBUtils是一个级别的,很简单的封装):Spring中的JDBC框架与dbUtils很相似!但是Spring的IoC给Spring-JDBC做了强大的后盾,并且Spring通过AOP对声明式事务的处理可以说是为人能比,所以,Spring的JDBC框架还是很有用途的;

    l  EJB(Entity Bean)(老了):Java EE中的实体Bean,因为是重量级组件,现在已经很少使用了。

    DBUtils

    1 DBUtils简介

    DBUtils是Apache Commons组件中的一员,开源免费!

    DBUtils是对JDBC的简单封装,但是它还是被很多公司使用!

    DBUtils的Jar包:dbutils.jar

    2 DBUtils主要类

    l  DbUtils:都是静态方法,一系列的close()方法;

    l  QueryRunner:提供update()、query()、batch()方法;

    其实我们自定义的框架中,JdbcRunner就是按照QueryRunner来写的,所以大家对update()和query()方法的使用应该没有问题了。

    QueryRunner的query()方法也需要ResultSetHandler来映射结果集,接口名称也与我们写的一样,所以大家应该比较熟悉了。

    3 QueryRunner之更新

    在DBUtlis中最主要的类就是QueryRunner了,创建它有如下两种方式:

    QueryRunner qr1 = new QueryRunner();

    DataSource ds = …

    QueryRunner qr2 = new QueryRunner(ds);

    一种方法是给QueryRunner指定DataSource,另一种是不指定DataSource。本来在DBUtils1.0版本就存在的setDataSource()方法,在1.4已经消失了!不能向下兼容的东西,真是垃圾!

    QueryRunner的update()和query()方法有两种重要的重载方式:需要Connection参数的,和不需要Connection参数的,需要Connectoin参数的很好理解!不需要Connection参数时,QueryRunner使用DataSource来获取Connection。如果你没有给QueryRunner指定DataSource,那么你就不能使用不需要Connection的update()和query()方法了。

    l  query(Connection on, String sql, ResultSetHandler rsh, Object… params):需要Connection,不会关闭Connection,这说明调用者自己需要关闭Connection;

    l  query(String sql, ResultSetHandler rsh, Object… params):不需要Connection,会使用DataSource来获取Connection。如果没有给QueryRunner指定DataSource就会出现异常!会关闭Connection!

    l  update(Connection on, String sql, Object… params):需要Connection参数,执行完成后,不会关闭Connection,这说明调用者需要自己来关闭Connection;

    l  update(String sql, Object… params):不需要Connection,会使用DataSource来获取Connection,如果没有为QueryRunner指定DataSource,那么调用本方法就会抛出异常。执行结束后会关闭Connection。

           QueryRunner qr = new QueryRunner();

           String sql = "insert into tab_student values(?,?,?,?)";

           Connection con = ...

           Object[] params = {...};

           qr.update(con, sql, params);

           con.close();

           DataSource ds = ...

           QueryRunner qr = new QueryRunner(ds);

           String sql = "insert into tab_student values(?,?,?,?)";

           Object[] params = {...};

           qr.update(sql, params);

    4 QueryRunner之查询

    DBUtils为我们提供了一些处理器,即ResultSetHandler的实现类!当然,如果你觉得DBUtils提供的处理器还不够的话,你可以自己再写一些处理器。

    l  ArrayHandler:单行处理器!把结果集转换成Object[];

    l  ArrayListHandler:多行处理器!把结果集转换成List<Object[]>;

    l  MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键!

    l  MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;

    l  BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;

    l  BeanListHandler:多行处理器!把结果集转换成List<Bean>;

    l  ColumnListHandler:多行单列处理器!把结果集转换成List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new ColumListHandler(“name”)表示把name列的数据放到List中。

    l  KeyedHandler:多行处理器!把结果集转换成Map<Object,Map<String,Object>>。使用KeyedHandler时需要指定主键列名称或编码,例如:new KeyedHandler(“number”)!生成的Map中以主键列的值为键,值还是一个Map,Map表示当前行记录。

    l  ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student。

        @Test

        public void fun1() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student where number=?";

           Object[] objs = qr.query(sql, new ArrayHandler(), "S_2000");

           System.out.println(Arrays.toString(objs));

        }

       

        @Test

        public void fun2() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student";

           List<Object[]> list =   qr.query(sql, new ArrayListHandler());

           for(Object[] objs : list) {

               System.out.println(Arrays.toString(objs));

           }

        }

       

        @Test

        public void fun3() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student where number=?";

           Map<String,Object> map =   qr.query(sql, new MapHandler(), "S_2000");

           System.out.println(map);

        }

       

        @Test

        public void fun4() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student";

           List<Map<String,Object>>   list = qr.query(sql, new MapListHandler());

           for(Map<String,Object> map : list) {

               System.out.println(map);

           }

        }

       

        @Test

        public void fun5() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student where number=?";

           Student stu = qr.query(sql, new   BeanHandler<Student>(Student.class), "S_2000");

           System.out.println(stu);

        }

       

        @Test

        public void fun6() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student";

           List<Student> list =   qr.query(sql, new BeanListHandler<Student>(Student.class));

           for(Student stu : list) {

               System.out.println(stu);

           }

        }

       

        @Test

        public void fun7() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student";

           List<Object> list = qr.query(sql,   new ColumnListHandler("name"));

           for(Object s : list) {

               System.out.println(s);

           }

        }

       

        @Test

        public void fun8() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

           String sql = "select * from tab_student";

           Map<Object,Map<String,Object>>   map = qr.query(sql, new KeyedHandler("number"));

    /*与MapListHandler相似,MapListHandler返回的是List<Map>,而KeyedHandler返回的是Map<Object,Map>,其中键为主键列的值,所以在使用KeyedHandler时需要指定主键列名称

    */

           for(Map.Entry<Object,Map<String,Object>>   entry : map.entrySet()) {

               System.out.println(entry);

           }

        }

     

        @Test

        public void fun9() throws   SQLException {

           DataSource ds = JdbcUtils.getDBCPDataSource();

           QueryRunner qr = new QueryRunner(ds);

            String   sql = "select count(*) from   tab_student";

           Number number = (Number)qr.query(sql, new ScalarHandler());

    /*

    单行单列处理器,一般用于聚合查询,在使用ScalarHandler时可以指定列名,如果不指定,默认为第1列。

    */

           int cnt = number.intValue();

    /*

    对聚合函数的查询结果,有的驱动返回的是Long,有的返回的是BigInteger,所以这里我们把它转换成Number,Number是Long和BigInteger的父类!然后我们再调用Number的intValue()或longValue()方法就OK了。

    */

           System.out.println(cnt);

        }

    5 QueryRunner之批处理

    QueryRunner还提供了批处理方法:batch()。

    我们更新一行记录时需要指定一个Object[]为参数,如果是批处理,那么就要指定Object[][]为参数了。即多个Object[]就是Object[][]了,其中每个Object[]对应一行记录:

    @Test

    public void fun10() throws SQLException {

        DataSource ds = JdbcUtils.getDBCPDataSource();

        QueryRunner qr = new QueryRunner(ds);

        String sql = "insert into tab_student values(?,?,?,?)";

        Object[][] params = new Object[10][];//表示 要插入10行记录

        for(int i = 0; i < params.length; i++) {

           params[i] = new Object[]{"S_300" + i, "name" + i, 30 + i, i%2==0?"男":"女"};

        }

        qr.batch(sql, params);

    //执行批处理

    }

  • 相关阅读:
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之六 多点触控
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之九 定位
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之七 重力感应
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之五 保存数据的几种方式
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之八 照相机
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之三 Application 配置详解
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之四 打开与关闭应用程序是的保存数据
    ADOBE FLASH BUILDER 4.6 IOS 开发之部署与调试
    [译] 高性能JavaScript 1至5章总结
    页签及盒子的web标准实现
  • 原文地址:https://www.cnblogs.com/lulu638/p/4438843.html
Copyright © 2011-2022 走看看