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);

    //执行批处理

    }

  • 相关阅读:
    接口的使用
    web service 实现无刷新返回一个表
    webservice 实现动态刷新
    js 实现子树选中时父目录全被选中
    相册的简单实现
    基于角色的身份验证3
    一个购物车的简单实现(多层开发)
    asp2.0 中实现 msdn 左边导航栏
    xsl 中 xsl:copy 的使用
    企业库中使用transaction(企业库中的列子)
  • 原文地址:https://www.cnblogs.com/lulu638/p/4438843.html
Copyright © 2011-2022 走看看