鏈接池:解決資源浪費,提升代碼性能。
本小節目標:
使用DBCP,C3P0鏈接池完成基本數據庫的操做。
使用DBUtils完成CRUD的操做。
數據庫鏈接池的解決方案是:
當應用程序啓動時,系統主動創建足夠的數據庫鏈接,並將這些鏈接組成一個鏈接池。每次應用程序請求數據庫鏈接時,無須從新打開鏈接,而是從鏈接池中取出已有的鏈接使用,使用完後再也不關閉數據庫鏈接,而是直接將鏈接歸還給鏈接池。經過使用鏈接池,將大大提升程序的運行效率。
數據庫鏈接池是Connection 對象的工程。數據庫鏈接池的經常使用參數以下。
a、數據庫的初始鏈接數
b、鏈接池的最大鏈接數
c、鏈接池的最小鏈接數
d、鏈接池每次增長的容量
公共接口:javax.sql.DataSource。
常見的鏈接池:DBCP 、 C3P0 (主要)
自定義鏈接池代碼實現改進(加強close方法):
自定義鏈接池中存在的嚴重問題,用戶調用getConnection()得到鏈接後,必須使用release()方法進行鏈接的歸還,若是用戶調用conn.close()將鏈接真正的釋放,鏈接池中將出現無鏈接能夠。
方法加強的辦法:
a、繼承,子類繼承父類,將父類的方法進行復寫,從而進行加強。
使用前提:必須有父類,且存在繼承關係。
b、裝飾者設計模式,此設計模式專門用於加強方法。
使用前提:必須有接口
缺點:須要將接口的全部方法都實現
c、動態代理:在運行時動態的建立代理類,完成加強操做。與裝飾者類似
使用前提:必須有接口
難點:須要反射技術
d、字節碼加強,運行時建立目標類子類,從而進行加強
常見第三方框架:cglib 、javassist等。
鏈接池釋放資源問題(WEB_10視頻05自定義鏈接池代碼實現改進(加強close方法)):
使用 c3p0 的話,也是 java.sql.Connection,只要是 JDBC 都是這個接口的對象!
使用完後必須 con.close() 掉,使用鏈接池的話,執行 con.close 並不會關閉與數據庫的 TCP 鏈接,而是將鏈接還回到池中去,若是不 close 掉的話,這個鏈接將會一直被佔用,直接鏈接池中的鏈接耗盡爲止。
至因而如何作到 con.close 並非真正意義上的關閉鏈接?而是直接將鏈接還回到池中去?
通常有兩種方式:
一:使用裝飾器模式,在裝飾器構造中傳入一個真正的 Connection,這個裝飾器實現 Connection,使用構造 傳入 Connection 委託重寫全部方法,並改寫 close 方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class ConnectionDecorator implements Connection {
private Connection con = null;
public ConnectionDecorator(Connection con) {
this.con = con;
}
public void close() throws SQLException {
// 重寫!
}
public void commit() throws SQLException {
this.con.commit();
}
public Statement createStatement() throws SQLException {
return this.con.createStatement();
}
public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException {
return this.con.createStatement(resultSetType, resultSetConcurrency);
}
......
}
|
而後通過鏈接池控制的 Connection 對象都使用該裝飾器進行包裝
二:動態代理:
使用動態代理從新實現 close 方法,每一個得到 Connection 是一個代理後的對象。
一個完善的鏈接池,其架構設計很是複雜,Connection#close 問題就是鏈接池諸多設計難點當中的一個。
總結:
關於學習MySql 以及JDBC方面的總結!
1、MySql
MySQL基本命令
SQL(全稱)語句基礎:DML 、 DDL 、 DCL 、 DQL
數據庫約束
查詢(單表、多表 左右鏈接等)
truncate 和 delete比較?
等等等
2、JDBC編程步驟
一、加載驅動
c3p0-config.xml
db.properties
二、獲取鏈接
鏈接池概念
步驟 J3P0(XML)
三、DBUtils 完成CRUD (增刪改查)
封裝JDBC操做,簡化JDBC操做
JavaBean組件(封裝數據) 包:com.scalpet.domain
四、使用完鏈接池後:釋放資源
得出結論,DBUtils在建立QueryRunner時傳入dataSource對象每次在執行完以後都會自動關閉Connection鏈接對象~因此不再用擔憂沒有關閉對象而致使的問題了~若是沒有傳入dataSource的話 ·····須要手動關閉
3、練習
a、創建工程---java project
b、導入JDBC鏈接的jar包---jar包都添加在新文件夾lib下面
c、導入c3p0jar包
d、編寫c3p0-config.xml文件
e、編寫C3P0工具類---其核心工具類ComboPooledDataSource(命名配置、默認配置)---工具類都放在新建包com.scalpel.utils包下
f、編寫JavaBean組件User----組件在新建包com.scalpel.domain包下
g、導入DBUtils的jar包
h、編寫DBUtils的測試java類
代碼實現:
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web</property>
<property name="user">root</property>
<property name="password">12345678</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="scalpel">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web</property>
<property name="user">root</property>
<property name="password">12345678</property>
</named-config>
</c3p0-config>
C3P0Utils工具類:
package com.scalpel.jdbc.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
//使用命名配置
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("scalpel");
/*
* 得到數據源(鏈接池)
*/
public static DataSource getDataSource()
{
return dataSource;
}
/*
* 得到鏈接
*/
public static Connection getConnection()
{
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException();
}
}
}
userbean組件類:
package com.scalpel.domain;
public class User {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
鏈接測試類:
package com.scalpel.jdbc.link;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Test;
import com.scalpel.domain.User;
import com.scalpel.jdbc.utils.C3P0Utils;
public class LinkJDBC {
/*
* 添加用戶
*/
@Test
public void AddUser() {
try {
// 1.鏈接數據源鏈接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.編寫sql語句
String sql = "insert into user values( ?, ?, null )";
// 3.添加params參數
Object[] params = { "ctxixi", "123" };
// 4.執行sql語句
int rows = qr.update(sql, params);
// 5.判斷是否執行成功
if (rows > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失敗");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 查詢用戶,使用BeanListHandler
*/
@Test
public void QueryAllUserInf()
{
try {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user";
List<User> queryUser = qr.query(sql, new BeanListHandler<User>(User.class));
for (User user : queryUser)
{
System.out.println(user.getId() +"、" + user.getName() + " : " + user.getPassword());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}