1. 程式人生 > >javaWeb學習記錄:c3p0資料庫連線池;DBUtils工具

javaWeb學習記錄:c3p0資料庫連線池;DBUtils工具

1. c3p0資料庫連線池

讓我想起了星球大戰裡的C-3PO,哈哈。

1.1 資料庫連線池的概念

用池來管理Connection,這可以重複使用Connection。有了池,所以我們就不用自己來建立Connection,而是通過池來獲取Connection物件。當使用完Connection後,呼叫Connection的close()方法也不會真的關閉Connection,而是把Connection“歸還”給池。池就可以再利用這個Connection物件了。

1.2 c3p0資料庫連線池例子

需要的jar包:

  • c3p0-0.9.2-pre1.jar
  • mchange-commons-0.2.jar
  • mysql-connector-java-5.1.37-bin.jar

程式碼如下:

ComboPooledDataSource ds = new ComboPooledDataSource();
//基本配置
ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
ds.setUser("root");
ds.setPassword("dongjiong");
ds.setDriverClass("com.mysql.jdbc.Driver");

//每次的增量
ds.setAcquireIncrement(5);
//初始化連線數
ds.setInitialPoolSize
(30); //最少連線數 ds.setMinPoolSize(2); //最多連線數 ds.setMaxPoolSize(50); //得到聯結器 Connection con = ds.getConnection(); System.out.println(con); //歸還給池 con.close();

c3p0也可以指定配置檔案,而且配置檔案可以是properties,也可以是xml的。當然xml的高階一些了。但是c3p0的配置檔名必須為c3p0-config.xml,並且必須放在類路徑下。
配置檔案要求:

  • 檔名稱:必須叫c3p0-config.xml
  • 檔案位置:必須在src下


    c3p0-config.xml檔案如下:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- 這是預設配置資訊 -->
    <default-config> 
        <!-- 連線四大引數配置 -->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">dongjiong</property>
        <!-- 池引數配置 -->
        <property name="acquireIncrement">3</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">2</property>
        <property name="maxPoolSize">10</property>
    </default-config>
</c3p0-config>

xml檔案配置好之後,程式碼裡就不用再配置了,直接像下面的程式碼那樣呼叫就行:

ComboPooledDataSource ds = new ComboPooledDataSource();
//得到聯結器
Connection con = ds.getConnection();
System.out.println(con);
//歸還給池
con.close();

c3p0的配置檔案中可以配置多個連線資訊,可以給每個配置起個名字,這樣可以方便的通過配置名稱來切換配置資訊。上面xml檔案中預設配置為mysql的配置,也可以給oracle資料庫配置一下連線資訊,起名為oracle-config,使用時把名字作為引數傳給程式。
xml檔案內加入下面的資訊:

<!-- 專門為oracle提供的配置資訊 -->
<named-config name="oracle-config"> 
    <property>...</property>
    ...
    <property>...</property>
</named-config>

程式碼裡使用時:

ComboPooledDataSource ds = new ComboPooledDataSource("oracle-config");
//得到聯結器
Connection con = ds.getConnection();
System.out.println(con);
//歸還給池
con.close();

2. jdbcUtils類

之前每次用JDBC時都要寫那些基本配置的程式碼,所以就把這些程式碼寫到了jdbcUtils類裡的一個靜態方法裡,返回一個Connection,然後直接在其他類裡呼叫這個方法就可以了,減少了重複程式碼的書寫,提高效率。這個類的程式碼如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class jdbcUtils {
    private static String url =  "jdbc:mysql://localhost:3306/test";        
    private static String username = "root";
    private static String password = "dongjiong";

    static {
        try{
            Class.forName("com.mysql.jdbc.Driver");
        }catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getConnection() throws SQLException{
        return DriverManager.getConnection(url, username, password);
    }
}

現在使用了c3p0資料庫連線池,這個類裡的程式碼需要改一下:

import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;

public class jdbcUtils {
    // 配置檔案的預設配置!要求你必須給出c3p0-config.xml!!!
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

    /**
     * 使用連線池返回一個連線物件
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException{
        return dataSource.getConnection();
    }

    /**
     * 返回連線池物件!
     * @return
     */
    public static DataSource getDataSource() {
        return dataSource;
    }
}

3. DBUtils

Commons DbUtils是Apache組織提供的一個對JDBC進行簡單封裝的開源工具類庫,使用它能夠簡化JDBC應用程式的開發,同時也不會影響程式的效能。其最核心的特性是結果集的封裝,可以直接將查詢出來的結果集封裝成JavaBean,這就為我們做了最枯燥乏味、最容易出錯的一大部分工作。

使用DBUtils需要注意的一些問題:

  1. DBUtils對結果集自動封裝為JavaBean是有著苛刻要求的:必須滿足JavaBean的規範,其次Bean的getter與setter方法的名字與結果集的列名(資料庫表的列名)一一對應,而不要求JavaBean的私有成員與表結果集列名一一對應。比如:
    person表中有個欄位叫:address,那麼對應的JavaBean的Person類中必須有getAddress和setAddress兩個方法,而Person類中可以將address屬性命名為add,這是沒問題的。
  2. 對於JavaBean的成員型別定義,有一條原則那就是:儘可能使用包裝型別,而不要使用基本型別。
    //錯誤
    int a1 = (Integer) null;
    boolean x1 = (Boolean)null;
    //正確
    Integer a2 = (Integer) null;
    Boolean x2 = (Boolean)null;

實際上就是為了保證在查詢結果為null的時候,也不會因為給基本型別賦null值而發生錯誤。

DBUtils主要類:QueryRunner

QueryRunner類下面有幾個經常使用的方法:

  • update():執行insert、update、delete操作
  • query():執行select語句
  • batch():執行批處理

假設有一個student表,它有三列:id,name,age。對它進行一些操作。

update():執行insert、update、delete操作

@Test
public void insert() throws Exception{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "INSERT INTO student VALUES(?,?,?)";
    Object[] params = {3,"jinjin",22};
    qr.update(sql, params);
}

@Test
public void update() throws Exception{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "UPDATE student SET name=? WHERE id=?";
    Object[] params = {"yaoyao",3};
    qr.update(sql, params);
}

@Test
public void delete() throws Exception{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "DELETE FROM student WHERE id=?";
    Object[] params = {3};
    qr.update(sql, params);
}

query():執行select語句

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT * FROM student WHERE id=?";
    Object[] params = {2};

    Student student = qr.query(sql,new BeanHandler<Student>(Student.class),params);
    System.out.println(student);
}

我們知道在執行select語句之後得到的是ResultSet,然後我們還需要對ResultSet進行轉換,得到最終我們想要的資料。你可能希望把ResultSet的資料放到一個List中,也可能想把資料放到一個Map中,或是一個Bean中。DBUtils提供了一個介面ResultSetHandler,它就是用來ResultSet轉換成目標型別的工具。DBUtils提供了很多個ResultSetHandler介面的實現。
如下:

  1. MapHandler:單行處理器!把結果集轉換成Map<String,Object>,其中列名為鍵!
  2. MapListHandler:多行處理器!把結果集轉換成List<Map<String,Object>>;
  3. BeanHandler:單行處理器!把結果集轉換成Bean,該處理器需要Class引數,即Bean的型別;
  4. BeanListHandler:多行處理器!把結果集轉換成List;
  5. ColumnListHandler:多行單列處理器!把結果集轉換成List<Object>,使用ColumnListHandler時需要指定某一列的名稱或編號,例如:new ColumListHandler(“name”) 表示把name列的資料放到List中。
  6. ScalarHandler:單行單列處理器!把結果集轉換成Object。一般用於聚集查詢,例如select count(*) from tab_student。
  7. ArrayHandler:把結果集中的第一行資料轉成物件陣列。
  8. ArrayListHandler:把結果集中的每一行資料都轉成一個物件陣列,再存放到List中。
  9. KeyedHandler:將結果集中的每一行資料都封裝到一個Map裡,然後再根據指定的key把每個Map再存放到一個Map裡。

舉幾個例子吧:

MapHandler:

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT * FROM student WHERE id=?";
    Object[] params = {2};

    Map<String, Object> student = qr.query(sql,new MapHandler(),params);
    System.out.println(student);
}

MapListHandler

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT * FROM student";

    List<Map<String, Object>> stuList = qr.query(sql,new MapListHandler());
    System.out.println(stuList);
}

BeanHandler

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT * FROM student WHERE id=?";
    Object[] params = {2};

    Student student = qr.query(sql,new BeanHandler<Student>(Student.class),params);
    System.out.println(student);
}

BeanListHandler

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT * FROM student";

    List<Student> stuList = qr.query(sql,new BeanListHandler<Student>(Student.class));
    System.out.println(stuList);
}

ScalarHandler

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT COUNT(*) FROM student";

    Number count = (Number) qr.query(sql,new ScalarHandler());//必須這樣寫,然後再轉換
    int num = count.intValue();

    System.out.println(num);
}

對聚合函式的查詢結果,有的驅動返回的是Long,有的返回的是BigInteger,所以這裡我們把它轉換成Number,Number是Long和BigInteger的父類!然後我們再呼叫Number的intValue()或longValue()方法轉成我們需要的型別。

ColumnListHandler

@Test
public void select() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "SELECT name FROM student";

    List<Object> names = qr.query(sql, new ColumnListHandler());

    System.out.println(names);
}

batch():執行批處理

我們更新一行記錄時需要指定一個Object[]陣列為引數,如果是批處理,處理多行資料,那麼就要指定一個二維陣列:Object[][]為引數。其中每個Object[]對應一行記錄。

@Test
public void insertBath() throws SQLException{
    QueryRunner qr = new QueryRunner(jdbcUtils.getDataSource());
    String sql = "INSERT INTO student VALUES(?,?,?)";

    Object[][] params = new Object[10][]; //表示 要插入10行記錄
    for(int i = 0; i < params.length; i++) {
        params[i] = new Object[]{30 + i,"name" + i,10+i};
    }

    qr.batch (sql, params);
}