好久沒用原生鏈接池,最近想寫個小功能,結果發現不少地方不太懂,而後網上搜了半天的 c3p0 相關內容,全不符合我想要的。相同內容太多 並且沒什麼,因此我本身來總結下吧。mysql
從如下來總結spring
首先咱們操做數據庫都須要鏈接,平時獲取鏈接、關閉鏈接若是頻繁,就會浪費資源,佔用CPU。因此這裏咱們用一個池子來存放鏈接。 先自定義一個本身的鏈接池,這些內容太簡單,我直接上代碼。相信你們很容易看懂。sql
public class CustomConnectionUtils {
private static LinkedList<Connection> pool = new LinkedList<Connection>();
/**
* 初始化鏈接池 添加3個鏈接到池子中去
*/
static {
try {
Class.forName("com.mysql.jdbc.Driver");
for(int i=0;i<3;i++){
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test1", "root", "root");
pool.add(connection);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取鏈接
* @return
*/
public static Connection getConnection(){
try {
if(!pool.isEmpty()){
Connection connection = pool.removeFirst();
return connection;
}
//若是沒有鏈接 等待 100 毫秒 而後繼續
Thread.sleep(100);
return getConnection();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
/**
* 歸還鏈接 其實就是從新將鏈接添加到池子中去
* @param connection
*/
public static void release(Connection connection){
if(connection != null){
pool.add(connection);
}
}
}
複製代碼
免費的鏈接池有不少,若是不配合 spring 。單獨使用,我我的仍是喜歡使用 c3p0。數據庫
第一步 添加依賴api
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
複製代碼
第二步 配置文件 配置文件命名只能 c3p0-config.xml
,位置放在 idea-->src-->resources-->c3p0-config.xml 而後就是它的配置,有兩種狀況bash
<!-- This is default config! -->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mylink2mv?characterEncoding=utf8</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</default-config>
複製代碼
還有種方式就是設定配置名字,以下 test1框架
<!-- This is my config for mysql-->
<named-config name="test1">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test1</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</named-config>
複製代碼
剩下就是代碼中的事情了。ide
第三步代碼中初始化配置文件工具
//加載默認配置文件
//private static final ComboPooledDataSource DATA_SOURCE_DEFAULT =new ComboPooledDataSource();
//加載命名配置文件
private static final ComboPooledDataSource DATA_SOURCE_TEST1 =new ComboPooledDataSource("test1");
複製代碼
兩種加載方式,都比較簡單。稍微注意,就是這一行代碼就已經讀取配置文件了,不用作其餘操做。這裏已經獲得的就是鏈接池了。這裏咱們寫個方法來獲取,顯得專業點,否則直接經過類名獲取也沒事。通常大部分舉例都是採用讀取默認名字的配置,這裏我讀取自定義的,將上面的代碼註釋掉。測試
第四步 獲取鏈接
這裏我寫個簡單的從鏈接池獲取鏈接的方法。
public static ComboPooledDataSource getDataSource(){
return pooledDataSource;
}
public static Connection getCoonection(){
try {
Connection connection = getDataSource().getConnection();
return connection;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
複製代碼
第五步 測試
這裏由於還沒開始用 DBUtils ,因此都是原生的 jdbc 方法。寫了個簡單的查詢語句演示。
public static void main(String[] args) {
try {
Connection connection = C3P0Utils.getCoonection();
PreparedStatement preparedStatement = null;
ResultSet rs = null;
String sql = "select * from my_movie;";
preparedStatement = connection.prepareStatement(sql);
rs = preparedStatement.executeQuery();
while(rs.next()){
String mName = rs.getString("mName");
System.out.println(mName);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
複製代碼
如今開始使用 DBUtils ,注意它並非鏈接池 ,最開始學的時候二者老是分不清,它是結合鏈接池 C3P0 使用的工具類。如上面代碼,發現沒,就算不使用 DBUtils 也是能夠的,只不過操做數據庫那一塊,增刪改查太過於複雜,特別對於「查」來講。對於返回的數據,處理很原生。可是有了 DBUtils 就不同了。它有三個核心功能,恰好用於解決項目實踐中很容易碰到的問題。
如上所說,這三個核心功能都是解決「痛點」問題的。
**QueryRunner **
一個個來看。首先 QueryRunner 類的構造方法有好三個,可是經常使用的能夠分紅兩類
首先來看不帶 connection 的,也就是說直接傳入鏈接池的。DBUtils 底層自動維護鏈接 connection 。
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
複製代碼
這種是你們用的最多的,還有種就是默認的不帶參數。
QueryRunner queryRunner = new QueryRunner();
複製代碼
這兩種有什麼區別呢? 爲何涉及 connection
呢? 主要仍是事務!
這裏先將結果丟出來,若是涉及事務,不能使用第一種構造。
再來看 QueryRunner 的方法 api 。兩個操做數據庫的 api 。
**ResultSetHandler **
第二部分中的查詢語句中能夠看出,對於查詢語句要解析到實體類,特別麻煩,特別結果集是集合時,更加麻煩。可是實踐中查詢用的最多。因此 DBUtils 有專門的類來處理結果集。很是多,可是經常使用三個。
增刪改操做都比較簡單,比較特殊一點就是 **獲取插入成功後的主鍵值 **,這點後再說,先將簡單的寫完。
/**
* 添加
*/
public void A() throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "insert into my_movie (mId,mName,mPrice,mDirector,mShowDate,cId) values (?,?,?,?,?,?)";
Object params[] = {null, "邪惡力量", 20, "Haha", "2017-08-23", 2};
int i = queryRunner.update(sql,params);
System.out.println(i);
}
複製代碼
/**
* 刪除
*/
public void B() throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "delete from my_movie where mId = ?";
Object params[] = {7};
int i = queryRunner.update(sql,params);
System.out.println(i);
}
複製代碼
/**
* 改
*/
public void C() throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "update my_movie set mName = ? where mId = ?";
Object params[] = {"綠箭俠",1};
int i = queryRunner.update(sql,params);
System.out.println(i);
}
複製代碼
上面三個方法我都試過,運行是沒問題的。接下來就是 獲取插入成功後的主鍵值。由於我碰到過這個需求,結果搜索 c3p0 dbutils 插入成功主鍵值
找到的相關文章都沒解決個人問題。查了好久 踩了不少坑,這裏總結下。
/**
* 獲取插入成功後的主鍵值
*/
public void D() throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "insert into my_movie (mId,mName,mPrice,mDirector,mShowDate,cId) values (?,?,?,?,?,?)";
Object params[] = {null, "邪惡力量", 20, "Haha", "2017-08-23", 2};
//這裏不能使用 update 而是 insert 使用以下參數
Long i = (Long) queryRunner.insert(sql,new ScalarHandler(),params);
System.out.println(i);
}
複製代碼
接下來是查詢
@Test
/**
* 查詢 獲取單個結果集
*/
public void E() throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from my_movie where mId = ? ";
Object params[] = {1};
Movie movie = queryRunner.query(sql, new BeanHandler<Movie>(Movie.class), params);
System.out.println(movie);
}
@Test
/**
* 查詢 獲取單個結果集
*/
public void F() throws SQLException {
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from my_movie ";
Object params[] = {};
List<Movie> movieList = queryRunner.query(sql, new BeanListHandler<Movie>(Movie.class), params);
System.out.println(movieList.toString());
}
複製代碼
到這裏爲止,一切都很美好,沒啥問題。可是若是涉及 事務 呢。
若是一個方法中不止一個 sql 操做,而都在一個事務中。採用如上辦法是不行的。由於這些 sql 語句的操做前提須要保證使用的是同一個鏈接
可是使用 QueryRunner
如上的構造方法是不行的。每個操做queryRunner.query
可能都使用的不是同一個鏈接。因此咱們的作法是本身獲取鏈接,而後做爲參數傳入。
/**
* 事務
*/
@Test
public void G() {
Connection connection = null;
try {
QueryRunner queryRunner = new QueryRunner();
connection = C3P0Utils.getCoonection();
//開啓事務
connection.setAutoCommit(false);
//全部的操做都帶上參數 connection
String sql01 = "insert into my_movie (mId,mName,mPrice,mDirector,mShowDate,cId) values (?,?,?,?,?,?)";
Object params01[] = {null, "邪惡力量", 20, "Haha", "2017-08-23", 2};
int i = queryRunner.update(connection,sql01,params01);
String sql02 = "select * from my_movie ";
Object params02[] = {};
List<Movie> movieList = queryRunner.query(connection,sql02, new BeanListHandler<Movie>(Movie.class), params02);
System.out.println(movieList);
} catch (SQLException e) {
//若是報錯 回滾
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
try {
//無論成功 失敗 都提交
connection.commit();
//關閉鏈接
DbUtils.closeQuietly(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
複製代碼
上面代碼我只是舉例了插入和查詢。其餘都同樣,帶了 connection 參數便可。
基本 c3p0 dbutils 事務 全部問題都搞清楚了。之後可能也用不着這些框架,可是但願能幫到一些用到了朋友吧。