dbutils

介绍

  • commons-dbutils 是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能,因此dbutils成为很多不喜欢hibernate的公司的首选。
  • API介绍
    • org.apache.commons.dbutils.QueryRunner–核心
    • org.apache.comons.dbutils.ResultSetHandler
    • 工具类
      • org.apache.commons.dbutils.DbUtils
QueryRunner runner = new QueryRunner();
        List<Account> as = runner.query(JdbcUtils.getConnection(),sql,new BeanListHandler<Account>(Account.class));

        for(Account a : as){
           System.out.println(a);
       }

手动封装数据

new ResultSetHandler<List<Account>>(){
    public List<Account> handler(ResultSet rs) throws SQLException{
        List<Account> as = new ArrayList<Account>();
        while(rs.next()){
            Account a new Account();
            a.setId(rs.getInt("id"));
            a.setName(rs.getString("name"));
            a.setMoney(rs.getDouble("money"));

            as.add(a);
        }
        return as;
    }
}

dbutils 核心

  • QueryRunner 类
    • 用于执行SQL语句的类
      • query 用于执行select
      • update 用于执行update 、select、insert
      • batch 批处理
    • ResultSetHandler接口
      • 用于定义结果集的封装,实现类是BeanListHandler()见手动封装结果集)
      • 它提供了九个实现类,可以进行不同的封装
    • DbUtils 类
      • 提供关于关闭资源及事务rollback,commit 操作。

QueryRunner类

获取方式

  • new QueryRunner();
    • 该构造方式创建的QueryRunner,它的事务是手动控制
  • new QueryRunner(DataSource rs )
    • 该构造方式创建的QueryRuuner,它的事务是自动控制的,即一条SQL语句,一个事务。

核心方法

  • query
  • update
  • batch
  • 对于上述三种方法,它们提供很多重载
    • 如果QueryRunner在创建时,没有床底DataSource 参数,那么在使用query ,update,batch方法时,要传递connection 参数
    • 如果在创建QueryRunner 时,传递了DataSource参数,那么在使用query,update,batch方法时,不需要传递connection参数。
public void fun1(){
    String sql = "select * from account";
    QueryRunner runner = new QueryRunner();//事务手动控制

    Connection con = DataSourceUtils.getConnection();
    List<Account> list = runner.query(con,sql,new BeanListHandler<Account>(Account.class));//需要传递con 参数

}
public void fun2(){
    String sql = "select * from account";
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());//自动事务
   List<Account> list = runner.query(sql,new BeanListHandler<Account>(Account.class));//不需要传递con
}

总结

QueryRunner runner = new QueryRunner();
runner.query(Connection,sql,ResultSetHandler,Object...param);
runner.update(Connection,sql,Object...param);
runner.batch(Connection con,sql,Object[][] objs);

QueryRunner runner = new QueryRunner(DataSource ds);
runner.query(sql,ResultSetHandler,Object...param);
runner.update(sql,Object...param);
runner.batch(sql,Object[][] objs);

ResultSetHandler接口

public void fun1() throws SqLException{
    String sql = "select * from account where id=?";
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    Account a = runner.query(sql,new ResultSetHandler<Account>(){//ResultSetHandler上的泛型就是我们执行query方法后得到的结果
//重写handle方法,在这个方法中确定,怎样将结果集封装
        public Account handle(ResultSet rs) throws SQLException{
            Account a = null;
            if(rs.next()){
                a=new Account();
                a.setId(rs.getInt("id"));
                a.setName(rs.getString("name"));
                a.setMoney(rs.getDouble("money"));
            }
            return a;
        }
    },2);

    System.out.println(a);  
}

模仿QueryRunner方法

public class MyQueryRunner{
    //执行select操作
    public Object query(){
        return null;
    }
    //执行update操作
    public int update(Connection con,String sql,Object ...params){
        PreparedStatement pst = con.prepareStatement(sql);//得到一个预处理的Statement
        //问题:SQL语句中可能存在参数,需要对参数赋值

        ParameterMetaData pmd= pst.getParameterMetaData();
        //可以得到有几个参数
        int count = pmd.getParameterCount();
        for(int i=1;i<=count;i++){
            pst.setObject(i,params[i-1]);
        }

        return pst.executeUpdate();
    }
}

ResultSetHandler的九个实现类

ArrayHandler
将结果集中的第一条记录封装到Object[],数组中的每一个元素就是记录中的字段值。

public void fun1() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
Object[] obj = runner.query("select * from account",new ArrayHandler());
System.out.pritnln(Arrays.toString(obj));
}

ArrayListHandler
将结果集中每一条记录封装到Object[],数组中的每一个元素就是记录中的字段值,再将这些数组装入到List集合。

public void fun2() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    List<Object[]> objs=runner.query("select * from account",new ArrayListHandler());
    for(Object[] obj:objs){
        System.out.println(obj);
    }
}

BeanHandler(重点)
将结果集中的第一条记录封装到一个JavaBean中

public void fun3() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    Account obj = runner.query("select * from account",new Beanhandler<Account>(Account.class));
    System.out.printnln(obj);
}

BeanListHandler(重点)
将结果集中的每一条记录封装到JavaBean中,再将JavaBean封装到List集合中。

public void fun4() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    List<Account> obj = runner.query("select * from account",new BeanListHandler<Account>(Account.class));
    System.out.println(obj);
}

ColumnListHandler
把结果集中的指定列的值封装到了List集合里。

public void fun5() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    List<Object> obj = runner.query("select * from account",new ColumnListHandler("name"));
    System.out.println(obj);
}

MapHandler
将结果集中第一条记录封装到Map集合中,集合中的key就是字段名称,value就是字段值

public void fun6() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    Map<String,Object> obj = runner.query("select * from account",new MapHandler());
    System.out.println(obj);
}

MapListHandler
将结果集中每一条记录封装到Map集合中,集合中的key就是字段名称,value就是字段名值,再将这些Map封装到List集合中。

public void fun7() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    List<Map<String,Object>> obj = runner.query("select * from account",new MapListHandler());
    System.out.println(obj);
}

KeyedHandler
将结果集中每一条记录封装到一个Map集合,再使用指定的列的值作为一个Map集合的key,值为每一条记录的Map集合封装。

public void fun8() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    Map<Object,Map<String,Object>> obj = runner.query("select * from account",new KeyedHandler("name"));
    System.out.println(obj);
}

ScalarHandler
进行单值查询 select count(*) from account;

public void fun9() throws SQLException{
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    long obj = (long)runner.query("select count(*) from account",new ScalarHandler());
    System.out.println(obj);
    //System.out.println(obj.getCalss().getName())
}

模仿实现BeanHandler

//从结果集方向封装数据
public Object handle(ResultSet rs) throws SQLException{
    Objet obj = null;
    //得到结果集元数据
    ResultSetMetaData md = rs.getMetaData();
    //得到所有字段名称
    int count = md.getColumnCount();

    if(rs.nest()){
        try{
            BeanInfo bif = Introspector.getBeanInfo(clazz);//得到BeanInfo
            PropertyDescriptor[] pds = bif.getPropertyDescriptors();//得到JavaBean的所有属性描述器
            obj = clazz.newInstance();
            for(int i=1;i<=count ;i++){
                String name = md.getColumnName(i);//得到每一列的名称
                for(PropertyDescriptor pd:pds){
                    if(name.equals(pd.getName())){
                        pd.getWriteMethod().invoke(obj,rs.getObject(name));//使用setXXX方法将结果集中的字段值封装到JavaBean的对应属性上。
                    }
                }
            }
        }
    }
}

案例演示(客户信息展示)

客户信息

字段名说明类型
Id编号varchar(40)
name客户姓名varchar(20)
gender性别varchar(10)
birthday生日date
cellphone手机varchar(20)
email电子邮件varchar(40)
preference客户爱好varchar(100)
type客户类型varchar(40)
description备注varchar(255)

创建表

create table customer(
    id varchar(40) primary key,
    name varchar(20),
    gender varchar(10),
    birthday date,
    cellphone varchar(20),
    email varchar(40),
    preference varchar(100),
    type varchar(40),
    description varchar(255)
);

环境搭建

  • JavaEE 三层结构
  • Servlet +JSP + JavaBean +jstl+DBUtils+DAO+MySQL
  • 导入jar包:JSTL,BeanUtils,DBUtils,C3P0,mysql驱动
  • 创建包结构
    • cn.xd.customer.web 表现层
    • cn,xd.customer.service 业务层
    • cn.xd.customer.dao 持久层
    • cn.xd.customer.utils工具包
    • cn.xd.customer.domain实体类 (JavaBean)
  • 应用的jar包
    • MySQL驱动包
    • c3p0包
    • dbutils包
    • BeanUtil包
    • JSTL包
    • c3p0的配置文件
  • 公共程序 domain utils
  • Customer 类 实体类
  • DataSourceUtils 工具类
编写代码

创建Customer的JavaBean

   private String id;
    private String name;
    private String gender;
    private Date birthday;
    private String email;
    private String preference;
    private String type;
    private String description;

为了测试方便,向customer表中插入数据

insert into customer values("a11","tom","男","2010-10-10","1372389034","tom@163.com","吃喝玩","vip","good man");
insert into customer values("a12","fox","男","2010-10-10","1372389034","fox@163.com","吃喝玩","vip","good man");
insert into customer values("a13","james","男","2010-10-10","1372389034","james@163.com","吃喝玩","vip","good man");

实现查询所有客户信息操作

  • 在success.jsp页面添加连接
    • <a href="${pageContext.request.ContextPath}/findAll">查看客户信息</a>
  • 在CustomerFindAllServlet中调用service,在service中调用dao,最后得到一个List<Customer>
  • 在showCustomer.jsp页面展示客户信息
<c:forEach items="${cs}" var="c">
            <tr>
                <td><input type="checkbox"></td>
                <td>${c.id}</td>
                <td>${c.name}</td>
                <td>${c.gender}</td>
                <td>${c.birthday}</td>
                <td>${c.cellphone}</td>
                <td>${c.email}</td>
                <td>${c.preference}</td>
                <td>${c.type}</td>
                <td>${c.description}</td>
                <td>
                    <a>编辑</a>&nbsp;&nbsp;&nbsp;<a>删除</a>
                </td>
            </tr>

        </c:forEach>

删除操作

  • 在showCustomer.jsp页面的删除连接上添加参数 客户的id
    <a>编辑</a>&nbsp;&nbsp;&nbsp;<a href="${pageContext.request.contextPath}/delById?id=${c.id}">删除</a>
  • 创建一个CustomerDelByIdServlet,完成获取请求参数,调用service中删除方法
    • 问题:如果删除完成后,怎么处理?
      • 跳转到 CustomerFindAllServlet中,再重新查询数据

编辑

  • 查询,做回显示
    • <a href="${pageContext.req.contextPath}/findById?id=${c.id}">编辑</a>
    • 创建CustomerFindByIdServlet,得到要查询的id,调用service,得到Customer对象
    • 将customer对象存储到request域,请求转发到customerInfo.jsp页面。
    • 在customerInfo,jsp中展示客户信息
    • 注意:客户的id不能修改,所以使用<input type="hedden">
  • 修改
    • 注意使用BeanUtils时的类型转换问题
    • 注意编码问题
      • post:request.setCharacterEncoding(“utf-8”);
      • get:手动转换 new String(request.getParameter(name).getBytes(“iso8859-1”),”utf-8”)
    • 进行修改操作

添加

  • 在showCustomer.jsp页面上添加一个连接,可以直接访问到添加页面 add.jsp
  • 创建add.jsp
    • 关于生日的日历组件
      • 导入js
      • 在input type = text组件上添加 calss,onclick
    • 关于id问题
      • 使用UUID获取
    • 创建CustomerAddServlet完添加操作
    • 得到所有请求参数封装到Customer对象
      • 编码问题
      • 使用BeanUtils,注意Date类型转换问题,
      • 手动封装id
    • 调用service完成添加操作
<td>
    <a href="${pageContext.request.contextPath}/add.jsp">添加</a>
</td>
//add.jsp
<head>
<script language="javascript" type="text/javascript" src="${pageContext.request.contextPath}/My97DatePicker/WdatePicker.js"></script>
</head>
<body>
${requestScope["add.message"]}<br>
<form action="${pageContext.request.contextPath}/add" method="post">
    客户姓名:<input type="text" name="name"><br>
    客户性别:<input type="radio" name="gender" value="男"><input type="radio" name="gender" value="女">女
    客户生日:<input type="text" name="birthday" class="Wdate" onclick="WdatePicker()"><br>
    客户电话:<input type="text" name="cellphone" ><br>
    客户邮箱:<input type="text" name="email" ><br>
    客户爱好:<input type="text" name="preference" ><br>
    客户类型:<input type="text" name="type" ><br>
    客户备注:<input type="text" name="description" ><br>    
    <input type="submit" value="添加">
</form>
</body>
//CustomerAddServlet.java
req.setCharacterEncoding("utf-8");
DateConverter dc = new DateConverter();
dc.setPattern("yyyy-MM-dd");
try{
    ConverUtils.register(dc,java.util.Date.class);
    BeanUtils.populate(c,req.getParameterMap());

}catch(IllegalAccessException e){
    e.printStackTrace();
}catch(InvocationTargetException e){
    e.printStackTrace();
}


//手动将id封装到Customer对象中
c.setId(IDUtils.getUUID());
//调用service完成添加操作
CustomerService service = new CustomerService();
try{
    service.add(c);
    //添加成功
    resp.sendRedirect(req.getContextPath()+"/fondAll");
}catch (SQLException e){
    e.printStackTrace();
    req.setAttribute("add.message","添加客户信息失败");
    req.getRequestDispatcher("/add.jsp").forward(req,resp);
    return;
}

//UUID示例
public class IDUtils{
    public static String getUUID(){
        return UUID.randomUUID().toString();
    }
    public static void main(String[] args){
        System.out.println(getUUID());
    }
}
//CustomerService.java
//添加客户信息
public void add(Customer c) throws SQLException{
    dao.add(c);
}
//dao.java
public void add(Customer c) throws SQLException{
    String sql="insert into customer values(?,?,?,?,?,?,?,?,?)";
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    runner.update(sql,c.getId(),c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription());


}

批量删除

  • 完成页面上全选与全不选操作
  • 完成批量删除
    • 页面上怎样将数据提交到服务器端
      • 可以创建一个表单,,将表单数据提交
      • 直接使用js操作,需要手动拼接出url路径
    • 在服务器端怎样批量删除
      • 得到所用要删除的id值
//showCustomer.jsp

<head>
    <script>
        function change(){
            //得到id为main的checkbox
            documnet.getElementById("main");
            var flag = main.checked;
            //得到所有name=ck 的checkbox
            var cks = document.getElementsByName("ck");
            //将cks中所有的checkbox的checked值设置为flag
            for(var i=0;i<cks.length;i++){
                cks[i].checked=flag;
            }
        }
    </script>

</head>



<table>
<tr>
    <td>
        <input type="checkbox" id="main" onclick="change()">
    </td>
</tr>

<c:forEach items="${cs}" var="c">
<tr>
    <td>
        <input type="checkbox" name="ck">
    </td>
</tr>
</c:forEach>
</table>
//showCustomer.jsp
<script>
//作用:让表单提交
function sendDel(){
    document.getElementById("f").submit;//表单提交
    var cks = document.getElementsByName("ck");
  /*  var url="${pageContext.request.contextPath}/delSelect?"
    for(var i=0;i<cks.length;i++){
        if(cks[i].checked){
            var id=cks[i].value;
            url+="id="+id+"&";
        }*/
    }


};
</script>



<c:if test ="${not empty cs}">
<form action = "${pageContext.request.contextPath}/delSelect" method="post" id="f">
<table>
<c:forEach items="${cs}" var = "c">
    <tr>
        <td>
            <input type="checkbox" value="${c.id}" name="ck">
        </td>
    </tr>
</c:forEach>
</table>
</form>
</c:if>
<tr>
    <td colspan="10"><a href="javascript:void(0)" onclick="sendDel();">删除选中</a></td>
</tr>
//CustomerDelSelectServlet

//得到所有要删除的客户的id
String[] id = req.getParameterCalues("ck");
//调用service,完成批量删除
CustomerService service = new CustomerService();
service.delSelect(id);
//CustomerService.java
//批量删除
public void delSelect(String[] id){

    dao.delSelect(id);
}
//customerDao.java
public void delSelect(Stinf[] id){
    String sql="delete from customer where id=?";
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    for(int i=0;i<id.length;i++){
        ids[i][0]=id[i];
    }
    runner.batch(sql,ids);

}

条件查询

  • 页面完成
  • 创建CustomerSimpleSelectServlet完成条件查询
//showCustomer.jsp
<c:if test="${not empty cs}">
    <div align ="center">
        <form action="${pageContext.request.contextPath}/simpleSelect" method="post">
        <select name="sel">
            <option>请选择条件</option>
            <option value="name">按姓名查询</option>
            <option value="cellphone">按手机号查询</option>
            <option value="gender">按性别查询</option>
        </select>
        <input type="text" name="msg">
        <input type=“submit” value="查询">
        </form>
    </div>
</c:if>
  • 问题:select的名称叫什么?每一个option的值是什么?
    • select可以任意起名
    • option的value名称需要与Customer表中的字段名称对应
  • 创建CustomerSimpleSelectServlet完成条件查询
    • 注意SQL语句问题:
    • String sql = “select * from customer where “+sel+” like?”;
//CustomerSimpleSelectServlet.java
String sel = request.getParameter("sel");//字段名称
String msg = request.getParameter("msg");//字段值

//调用service完成查询操作
CustomerService service = new CustomerService();
try{
    List<Customer> cs = service.simpleSelect(sel,msg);

}catch(SQLException e){
    e.printStackTrace();
    resp.getWriter().write("条件查询失败");
    return;
}


//CustomerService
public List<Customer> simpleSelect(String sel,String msg){
    return dao.simpleSelect(sel,msg);
}
//CustomerDao
//sel 字段名称
//msg 字段值
public List<Customer> simpleSelect(String sel,String msg){
//SQL语句中,?号会默认加单引号
//select * from customer where 'name' like '%'小'%'
    //String sql = "select * from customer where ? like '%?%'"
    String sql = "select * from customer where "+sel+" like ?"
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource()); 
    return runner.query(sql,new BeanListHandler<Customer>(Customer.class),"%"+msg+"%");

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值