DBUtils 學習使用 commons-dbutils簡介 commons-dbutils是Apache組織提供的一個開源JDBC工具類庫,它是對JDBC的簡單封裝,學習成本極低,並且使用dbutils能極大簡化jdbc編碼的工作量,同時也不會影響程式的性能。因此dbutils成為很多不喜歡hib ...
DBUtils 學習使用
commons-dbutils簡介
commons-dbutils是Apache組織提供的一個開源JDBC工具類庫,它是對JDBC的簡單封裝,學習成本極低,並且使用dbutils能極大簡化jdbc編碼的工作量,同時也不會影響程式的性能。因此dbutils成為很多不喜歡hibernate的公司的首選。 dbutils的官方網站http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi
dbutils 優點
- 對於數據表的讀操作,他可以把結果轉換成List,Array,Set等java集合,便於程式員操作;
- 對於數據表的寫操作,也變得很簡單(只需寫sql語句)
- 可以使用數據源,使用JNDI,資料庫連接池(dbcp,c3p0)等技術來優化性能--重用已經構建好的資料庫連接對象,而不像php,asp那樣,費時費力的不斷重覆的構建和析構這樣的對象。
commons-dbutils API介紹
- org.apache.commons.dbutils.QueryRunner QueryRunner (insert、update、delete使用)
- org.apache.commons.dbutils.ResultSetHandler (用於查詢結果處理使用)
- org.apache.commons.dbutils.DbUtils (工具類)
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
用來執行一個不需要置換參數的更新操作。
public int[] batch(Connection conn, String sql, Object[][] params) throws SQLException
這個方法對應著批處理,經常用於在同一個表中批量插入數據,或批量更新表的數據。 該方法為何會接收二維數組Object[][] params
呢? 答:例如現在要想在同一個表中批量插入數據,編寫的SQL語句為:
String sql = "insert into users(id,name) values(?,?)";
該方法接收二維數組Object[][] params
,那麼調用其的時候就要傳遞一個諸如這樣的實參[[1,aa],[2,bb],[3,cc]]
,即用二維數組裡面的每一個一維數組生成一條sql語句。 那為何又會返回int[]
呢? 答:該方法的返回值是int[]
,所以會返回諸如這樣的結果:[1,1,1]
,意思是生成的第一條sql語句影響資料庫幾行、生成的第二條sql語句影響資料庫幾行、生成的第三條sql語句影響資料庫幾行。
ResultSetHandler介面使用講解
該介面用於處理java.sql.ResultSet,將數據按要求轉換為另一種形式。ResultSetHandler介面提供了一個單獨的方法:Object handle (java.sql.ResultSet .rs)
。
ResultSetHandler介面的實現類
- ArrayHandler:把結果集中的第一行數據轉成對象數組。
- ArrayListHandler:把結果集中的每一行數據都轉成一個數組,再存放到List中。
- BeanHandler:將結果集中的第一行數據封裝到一個對應的JavaBean實例中。
- BeanListHandler:將結果集中的每一行數據都封裝到一個對應的JavaBean實例中,存放到List里。
- ColumnListHandler:將結果集中某一列的數據存放到List中。
- KeyedHandler(name):將結果集中的每一行數據都封裝到一個Map里,再把這些map再存到一個map里,其key為指定的key。
- MapHandler:將結果集中的第一行數據封裝到一個Map里,key是列名,value就是對應的值。
- MapListHandler:將結果集中的每一行數據都封裝到一個Map里,然後再存放到List。
DbUtils類使用講解
DbUtils:提供如關閉連接、裝載JDBC驅動程式等常規工作的工具類,裡面的所有方法都是靜態的。主要方法如下:
public static void close(…) throws java.sql.SQLException
DbUtils類提供了三個重載的關閉方法。這些方法檢查所提供的參數是不是NULL,如果不是的話,它們就關閉Connection、Statement和ResultSet。public static void closeQuietly(…)
這一類方法不僅能在Connection、Statement和ResultSet為NULL情況下避免關閉,還能隱藏一些在程式中拋出的SQLException。public static void commitAndCloseQuietly(Connection conn)
用來提交連接,然後關閉連接,並且在關閉連接時不拋出SQL異常。public static boolean loadDriver(java.lang.String driverClassName)
這一方法裝載並註冊JDBC驅動程式,如果成功就返回true。使用該方法,你不需要捕捉這個異常ClassNotFoundException。
使用DBUtils完成資料庫的CRUD
在使用DBUtils完成資料庫的CRUD之前,我們先編寫測試用的SQL腳本:
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
`age` tinyint(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
使用dbutils遵從以下步驟
- 載入JDBC驅動程式類,並用DriverManager來得到一個資料庫連接conn。
- 實例化 QueryRunner,得到實例化對象qRunner。
- qRunner.update()方法,執行增改刪的sql命令,qRunner.query()方法,得到結果集。
獲取連接對象
private static final String url = "jdbc:mysql://192.168.1.15:3306/test?useUnicode=true&characterEncoding=utf8";
private static final String driver = "com.mysql.jdbc.Driver";
private static final String user = "znsd_test";
private static final String password = "123456";
public static Connection getConnect() {
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
創建bean對象關聯資料庫
public class User implements Serializable {
private Integer id; // 用戶ID
private String name; // 用戶姓名
private Integer age; // 用戶年齡
// ...忽略set、get方法
}
添加
public Integer add(User user) {
QueryRunner queryRunner = new QueryRunner();
Connection connect = ConnectionUtil.getConnect();
try {
return queryRunner.update(connect, "insert into user(name, age) values(?, ?)", user.getName(), user.getAge());
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(connect);
}
return 0;
}
修改
public Integer update(User user) {
QueryRunner queryRunner = new QueryRunner();
Connection conn = ConnectionUtil.getConnect();
try {
return queryRunner.update(conn , "update user set name = ?, age = ? where id = ?", user.getName(), user.getAge(), user.getId());
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return 0;
}
刪除
public Integer delete(Integer id) {
QueryRunner queryRunner = new QueryRunner();
Connection conn = ConnectionUtil.getConnect();
try {
return queryRunner.update(conn , "delete from user where id = ?", id);
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return 0;
}
批量添加
public int[] batch(Object[][] values) {
QueryRunner queryRunner = new QueryRunner();
Connection conn = ConnectionUtil.getConnect();
try {
return queryRunner.batch(conn, "insert into user(name, age) values(?, ?)", values);
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return null;
}
查詢所有
public List<User> select() {
QueryRunner queryRunner = new QueryRunner();
Connection conn = ConnectionUtil.getConnect();
try {
return queryRunner.query(conn, "select id id1, name, age from user", new UserBeanListHandler(User.class));
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return null;
}
查詢返回map
public List<Map<String, Object>> selectAsMap() {
QueryRunner queryRunner = new QueryRunner();
Connection conn = ConnectionUtil.getConnect();
try {
List<Map<String, Object>> userMaps = queryRunner.query(conn, "select id id1, name, age from user", new MapListHandler());
return userMaps;
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return null;
}
查詢單個對象
public User selectOne(Integer id) {
QueryRunner queryRunner = new QueryRunner();
Connection conn = ConnectionUtil.getConnect();
try {
return queryRunner.query(conn, "select id id1, name, age from user where id = ? limit 1", new BeanHandler<User>(User.class) {
@Override
public User handle(ResultSet rs) throws SQLException {
if (rs.next()) {
return new User(rs.getInt("id1"), rs.getString("name"), rs.getInt("age"));
}
return null;
}
}, id);
} catch (SQLException e) {
e.printStackTrace();
} finally {
DbUtils.closeQuietly(conn);
}
return null;
}
結合c3p0數據源使用dbutils
c3p0簡介
C3P0是一個開源的JDBC連接池,它實現了數據源和JNDI綁定,支持JDBC3規範和JDBC2的標準擴展。目前使用它的開源項目有Hibernate,Spring等
資料庫連接池簡介
資料庫連接池負責分配、管理和釋放資料庫連接,它允許應用程式重覆使用一個現有的資料庫連接,而不是再重新建立一個;連接池允許多個客戶端使用緩存起來的連接對象,這些對象可以連接資料庫,它們是共用的、可被重覆使用的。
打開/關閉資料庫連接開銷很大,連接池技術允許我們在連接池裡維護連接對象,這樣可以提高資料庫的執行命令的性能。多個客戶端請求可以重覆使用相同的連接對象,當每次收到一個客戶端請求時,就會搜索連接池,看看有沒有閑置的連接對象。如果沒有閑置對象的話,要麼所有的客戶端請求都進入隊列排隊,要麼在池中創建一個新的連接對象(這取決於池裡已經有多少個連接存在以及配置支持多少連接)。一旦某個請求使用完連接對象之後,這個對象會被重新放入池中,然後會被重新分派給排隊等待的請求(分派給哪個請求要看使用什麼調度演算法)。因為大部分請求都是使用現存的連接對象,所以連接池技術大大減少了等待創建資料庫連接的時間,從而減少了平均連接時間。
使用連接池的優點
- 資源重用:
由於資料庫連接得以重用,避免了頻繁創建,釋放連接引起的大量性能開銷。在減少系統消耗的基礎上,另一方面也增加了系統運行環境的平穩性。
- 更快的系統反應速度:
資料庫連接池在初始化過程中,往往已經創建了若幹資料庫連接置於連接池中備用。此時連接的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連接,避免了資料庫連接初始化和釋放過程的時間開銷,從而減少了系統的響應時間。
- 統一的連接管理,避免資料庫連接泄露:
在較為完善的資料庫連接池實現中,可根據預先的占用超時設定,強制回收被占用連接,從而避免了常規資料庫連接操作中可能出現的資源泄露。
使用步驟
- 首先要導入c3p0和dbutils以及mysql的jar包
- c3p0-0.9.5.2.jar
- commons-dbutils-1.7.jar
- mchange-commons-java-0.2.11.jar
- mysql-connector-java-5.1.22.jar
- 編寫c3p0的配置文件c3p0-config.xml
在src目錄下存放c3p0的配置文件,配置文件是c3p0自己去識別並讀入的,我們不需要在代碼中做任何的操作,但是配置文件一定要命名為c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 這是預設配置信息 -->
<default-config>
<!-- jdbc連接四大參數配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://192.168.1.15:3306/test</property>
<property name="user">znsd_test</property>
<property name="password">123456</property>
<!-- 池參數配置 -->
<!--JDBC的標準參數,用以控制數據源內載入的PreparedStatements數量。但由於預緩存的statements
屬於單個connection而不是整個連接池。所以設置這個參數需要考慮到多方面的因素。
如果maxStatements與maxStatementsPerConnection均為0,則緩存被關閉。Default: 0
-->
<property name="acquireIncrement">3</property>
<!--初始化時獲取的連接數,取值應在minPoolSize與maxPoolSize之間。Default: 3 -->
<property name="initialPoolSize">10</property>
<!--連接池中保留的最小連接數。-->
<property name="minPoolSize">2</property>
<!--連接池中保留的最大連接數。Default: 15 -->
<property name="maxPoolSize">10</property>
</default-config>
</c3p0-config>
- 使用c3p0獲取獲取資料庫連接對象
public class C3p0ConnectionUtil {
// 配置文件的預設配置!要求你必須給出c3p0-config.xml
private static ComboPooledDataSource c3p0DataSource = new ComboPooledDataSource();
/**
* 獲取連接對象
* @return
*/
public static Connection getConnection() {
try {
// 得到連接器
return c3p0DataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 獲取數據源
*
* @return
*/
public static DataSource getDataSource() {
return c3p0DataSource;
}
}
- dbutils 使用c3p0
public Integer add(User user) {
QueryRunner queryRunner = new QueryRunner(C3p0ConnectionUtil.getDataSource());
try {
return queryRunner.update("insert into user(name, age) values(?, ?)", user.getName(), user.getAge());
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
- 返回主鍵例子
public Integer add(User user) {
DataSource dataSource = C3p0ConnectionUtil.getDataSource();
QueryRunner queryRunner = new QueryRunner(dataSource);
try {
String sql = "insert into user(name, age) values(?, ?)";
// 需要條用insert方法,指定MapHandler參數
Map<String, Object> idMap = queryRunner.insert(sql, new MapHandler() {
@Override
public Map<String, Object> handle(ResultSet rs) throws SQLException {
//rs = rs.getStatement().getGeneratedKeys();
// 獲取主鍵
int id = rs.next() ? rs.getInt(1) : -1;
// 將資料庫返回主鍵放入map中
Map<String, Object> idMap = new HashMap<String, Object>();
idMap.put("id", id);
return idMap;
}
}, user.getName(), user.getAge());
return (Integer) idMap.get("id");
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}