自定义数据库框架

自定义数据库框架

我们以前写过的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);

//执行批处理

}

原文地址:https://www.cnblogs.com/lulu638/p/4438843.html