1. 程式人生 > >MySQL---資料庫從入門走向大神系列(十五)-Apache的DBUtils框架使用

MySQL---資料庫從入門走向大神系列(十五)-Apache的DBUtils框架使用

DBUtils簡介:

commons-dbutils 是 Apache 組織提供的一個開源 JDBC工具類庫,它是對JDBC的簡單封裝,學習成本極低,並且使用dbutils能極大簡化jdbc編碼的工作量,同時也不會影響程式的效能。因此dbutils成為很多不喜歡hibernate的公司的首選(嗯~商業競爭…..)。

commons-dbutilsAPI介紹:

org.apache.commons.dbutils.QueryRunner
org.apache.commons.dbutils.ResultSetHandler
  工具類
org.apache.commons.dbutils
.DbUtils

QueryRunner類講解

該類簡單化了SQL查詢,它與ResultSetHandler組合在一起使用可以完成大部分的資料庫操作,能夠大大減少編碼量。
QueryRunner類提供了兩個構造方法:
1、預設的構造方法
2、需要一個 javax.sql.DataSource 來作引數的構造方法。

QueryRunner類的主要方法

public Object query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) throws SQLException:
執行一個查詢操作,在這個查詢中,物件陣列中的每個元素值被用來作為查詢語句的置換引數。該方法會自行處理 PreparedStatement 和 ResultSet 的建立和關閉。

public Object query(String sql, Object[] params, ResultSetHandler rsh) throws SQLException: 
幾乎與第一種方法一樣;唯一的不同在於它不將資料庫連線提供給方法,並且它是從提供給構造方法的資料來源(DataSource) 或使用的setDataSource 方法中重新獲得 Connection。

  public Object query(Connection conn, String sql, ResultSetHandler rsh) throws SQLException : 執行一個不需要置換引數的查詢操作。
  
  public int update(Connection conn, String sql, Object[] params) throws SQLException
  用來執行一個更新(插入、更新或刪除)操作。
  
  public int update(Connection conn, String sql) throws SQLException:
  用來執行一個不需要置換引數的更新操作。

JAR包準備:

程式碼演示:

首先準備資料庫:

create database hncu character set utf8;

use hncu;

create table person(
    id varchar(30) primary key,
    name varchar(30),
    address varchar(30),
    age int
);

insert into  person(id,name,address,age) values('P001','張三','湖南長沙',20);
insert into  person(id,name,address,age) values('P002','李四','中國北京',25);
insert into  person(id,name,address,age) values('P003','李白','武漢',56);
insert into  person(id,name,address,age) values('P004','張三丰','武當三',78);
insert into  person(id,name,address,age) values('P005','Tom','美國紐約',34);
insert into  person(id,name,address,age) values('P006','Jack','美國舊金山',28);

不使用dbUtils工具的資料庫查詢程式碼實現

@Test//原來不使用dbUtils工具的資料庫查詢程式碼實現
    public void jdbcQuery() throws SQLException{
        List<Person> persons = new ArrayList<Person>();
        Connection con = C3p0Pool.getConnection();
        String sql = "select * from person";
        Statement st = con.createStatement();
        ResultSet rs = st.executeQuery(sql);
        while(rs.next()){
            Person p = new Person();
            p.setId(rs.getString("id"));
            p.setName(rs.getString("name"));
            p.setAddr(rs.getString("address"));
            p.setAge(Integer.parseInt(rs.getString("age")));
            persons.add(p);
        }
        for(Person p:persons){
            System.out.println(p);
        }
    }

結果:

使用dbUtils工具的資料庫查詢程式碼實現

BeanListHandler返回型別為List<>

@Test
    public void dbUtilsQuery() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        String sql = "select * from person";
        List<Person> persons = run.query(sql,new BeanListHandler<Person>(Person.class));
        for(Person p:persons){
            System.out.println(p);
        }
    }
資料庫的欄位名為:address、
public String addr;
    //這裡的名字如果和資料庫的欄位名不同。會出現讀取值為null的情況
    //如果要解決,把get和set函式的set/get***寫成和資料的欄位名一樣就可以了。setAddress()/getAddress()
    //或者在查詢的時候取別名如:select id,name,address as addr ,age  from person
    //但是最好還是和資料庫的欄位名一樣比較好

MapListHandler返回型別為List<Map<String,Object>>

而且注意,這個與前面的依賴person類的不同,這個不依賴person類,
也就是person的成員變數名可以和資料庫的欄位名取不同。

    @Test
    public void dbUtilsQuery2() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        String sql = "select * from person ";
        List<Map<String, Object>> persons = run.query(sql,new MapListHandler());
        for(Map<String, Object> p:persons){
            System.out.println(p);
        }
    }

DbUtils工具的使用演示: 增刪改–用update()

只演示 增,刪和改類似:

@Test
    public void save() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        //statement方式
        //run.update("insert into person(id,name,address,age) values('P007','Rose','湖南長沙',22) ");
        //prepareStatement方式
        run.update("insert into person(id,name,address,age) values(?,?,?,?)", "P008","Marry","中國西安",34);
    }

如果使用prepareStatement方式,注意引數個數或型別 與 “?”號必須匹配,否則會出異常 。

為 增新增事務處理:

@Test
    public void saveTx() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        Connection con = C3p0Pool.getConnection();
        try {
            con.setAutoCommit(false);
            run.update(con, "insert into person(id,name,address,age) values(?,?,?,?)","P011","Tom","浙江杭州",24);
            run.update(con, "insert into person(id,name,address,age) values(?,?,?,?)","P012","Gimo","江蘇蘇州",45);
            con.commit();
        } catch (Exception e) {
            if(con!=null){
                con.rollback();
                System.out.println("事務回滾了...");
            }
        }finally{
            if(con!=null){
                con.setAutoCommit(true);
                con.close();
            }
        }
    }

注意,實現事務功能時,要傳入con物件,且多條語句共處一個事務時,要傳入同一個con物件。但如果不實現事務功能,可以不傳入con物件。

查詢的結果集封裝

封裝成BeanList

@Test
    public void query2() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        //封裝成BeanList: 如果值物件中的屬性名和表中的欄位名不一致,那麼該屬性的值返回的是null
        //解決方法是採用別名,或者修改set**/get**名
        List<Person> persons = run.query("select id,name,address addr,age from person ",new BeanListHandler<Person>(Person.class) );//用屬性名 當 欄位別名
        for(Person p:persons){
            System.out.println(p);
        }
    }

封裝成MapList

@Test
    public void query3() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        String sql = "select * from person";
        List<Map<String, Object>> persons = run.query(sql, new MapListHandler());
        for(Map<String, Object> p:persons){
            System.out.println(p);
        }
    }

封裝成BeanList—查詢帶引數

@Test
    public void query4() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        String sql = "select id,name,address,age from person where name like ? and age > ?";
        List<Person> persons = run.query(sql, new BeanListHandler<Person>(Person.class),"%o%",34);
        for(Person p:persons){
            System.out.println(p);
        }
    }

演示批處理功能

@Test
    public void batch() throws SQLException{
        QueryRunner run = new QueryRunner(C3p0Pool.getDataSource());
        for(int i=1;i<=100;i++){
            String sql = "insert into person values(?,?,?,?)";
            String str = "000"+i;
            str=str.substring(str.length()-3, str.length());

            String id1="A"+str;
            String id2="B"+str;
            String params[][]={{id1,"Alice"+i,"中國",i+""},{id2,"Bob"+i,"湖南",i+""}};
            run.batch(sql, params);
        }
    }

演示擴充套件包commons-dbutilss-ext.jar的功能

封裝成BeanList—直接通過JavaBean的位元組碼查詢所有

注意,下面的用法要生效,必須給值物件添加註解@Table(value = “person”)

@Test 
    public void query5(){
        ExtQueryRunner run = new ExtQueryRunner(C3p0Pool.getDataSource());
        List<Person> persons = run.query(Person.class);//不用sql語句,,直接查詢Bean-List
        for(Person p:persons){
            System.out.println(p);
        }
    }

封裝成JavaBean—直接通過JavaBean物件儲存進資料庫

    @Test
    public void save3(){
        ExtQueryRunner run = new ExtQueryRunner(C3p0Pool.getDataSource());
        Person p = new Person();
        p.setId("A000");
        p.setName("梨子");
        p.setAddress("中國");
        p.setAge(20);
        run.save(p);//不用sql語句,直接存物件
        System.out.println(p);
    }

注意:使用此功能時,需要在JavaBean物件中的每個成員變數上都加上@Column註解!!!

還有注意這裡的JavaBean中的addr與資料庫的欄位名address是不同的,所以需要在JavaBean物件的addr屬性上加上一句註解:
@Column(value=”address”)

Person.java

package cn.hncu.dbutils;

import org.apache.commons.dbutils.ext.Column;
import org.apache.commons.dbutils.ext.Table;


/**
 * @author 陳浩翔
 *
 * 2016-8-15
 */
@Table(value = "person")
public class Person {
    @Column
    private String id;
    @Column
    private String name;

    @Column(value="address")
    public String addr;
    //這裡的名字如果和資料庫的欄位名不同。會出現讀取值為null的情況
    //如果要解決,把get和set函式的set/get***寫成和資料的欄位名一樣就可以了。
    //或者在查詢的時候取別名如:select id,name,address as addr ,age  from person
    //但是最好還是和資料庫的欄位名一樣比較好
    @Column
    private Integer age;
    public Person() {
        super();
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return addr;
    }
    public void setAddress(String addr) {
        this.addr = addr;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "[id=" + id + ", name=" + name + ", addr=" + addr
                + ", age=" + age + "]";
    }

}