JDBC複習-資料庫連線池
阿新 • • 發佈:2020-12-21
技術標籤:JDBC學習
此部落格僅為本人學習JDBC時所做記錄。
10-資料庫連線池
10.1 傳統連線的問題
這種模式開發,存在的問題:
- 普通的JDBC資料庫連線使用 DriverManager 來獲取,每次向資料庫建立連線的時候都要將 Connection 載入到記憶體中,再驗證使用者名稱和密碼(得花費0.05s~1s的時間)。需要資料庫連線的時候,就向資料庫要求一個,執行完成後再斷開連線。這樣的方式將會消耗大量的資源和時間。**資料庫的連線資源並沒有得到很好的重複利用。**若同時有幾百人甚至幾千人線上,頻繁的進行資料庫連線操作將佔用很多的系統資源,嚴重的甚至會造成伺服器的崩潰。
- **對於每一次資料庫連線,使用完後都得斷開。**否則,如果程式出現異常而未能關閉,將會導致資料庫系統中的記憶體洩漏,最終將導致重啟資料庫。(回憶:何為Java的記憶體洩漏?)
- 這種開發不能控制被建立的連線物件數,系統資源會被毫無顧及的分配出去,如連線過多,也可能導致記憶體洩漏,伺服器崩潰。
10.2 如何解決傳統開發中的資料庫連線問題
使用資料庫連線池。
10.3 使用資料庫連線池的好處
1. 資源重用
由於資料庫連線得以重用,避免了頻繁建立,釋放連線引起的大量效能開銷。在減少系統消耗的基礎上,另一方面也增加了系統執行環境的平穩性。
2. 更快的系統反應速度
資料庫連線池在初始化過程中,往往已經建立了若干資料庫連線置於連線池中備用。此時連線的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連線,避免了資料庫連線初始化和釋放過程的時間開銷,從而減少了系統的響應時間
3. 新的資源分配手段
對於多應用共享同一資料庫的系統而言,可在應用層通過資料庫連線池的配置,實現某一應用最大可用資料庫連線數的限制,避免某一應用獨佔所有的資料庫資源
4. 統一的連線管理,避免資料庫連線洩漏
在較為完善的資料庫連線池實現中,可根據預先的佔用超時設定,強制回收被佔用連線,從而避免了常規資料庫連線操作中可能出現的資源洩露
簡單總結:
- 提高程式的響應速度(減少建立連線相應的時間)
- 降低資源的消耗(可以重複使用)
- 便於連線的管理
10.4 實現的方式
- DBCP 是Apache提供的資料庫連線池。tomcat 伺服器自帶dbcp資料庫連線池。速度相對c3p0較快,但因自身存在BUG,Hibernate3已不再提供支援。
- C3P0 是一個開源組織提供的一個數據庫連線池,**速度相對較慢,穩定性還可以。**hibernate官方推薦使用
- Proxool 是sourceforge下的一個開源專案資料庫連線池,有監控連線池狀態的功能,穩定性較c3p0差一點
- BoneCP 是一個開源組織提供的資料庫連線池,速度快
- Druid 是阿里提供的資料庫連線池,據說是集DBCP 、C3P0 、Proxool 優點於一身的資料庫連線池,但是速度不確定是否有BoneCP快
10.5 C3P0
-
匯入jar包
-
測試連線的程式碼
/** * 使用C3P0的資料庫連線池技術 */ //連線池只需要提供一個 private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0"); public static Connection getConnection1() throws SQLException { Connection conn = cpds.getConnection(); return conn; }
-
配置檔案
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <named-config name="helloc3p0"> <!--提供獲取連線的4個基本資訊--> <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true</property> <property name="user">root</property> <property name="password">*****</property> <!--提供資料庫連線池管理的4個基本資訊--> <!-- 當資料庫連線池中的連線數不夠時,c3p0一次性向資料庫伺服器申請的連線數 --> <property name="acquireIncrement">5</property> <!-- c3p0資料庫連線池中初始化時的連線數 --> <property name="initialPoolSize">10</property> <!-- c3p0資料庫連線池中維護的最少的連線數 --> <property name="minPoolSize">10</property> <!-- c3p0資料庫連線池中維護的最多的連線數 --> <property name="maxPoolSize">100</property> <!-- c3p0資料庫連線池中維護的最多的statement的個數 --> <property name="maxStatements">50</property> <!-- 每個連線中可以最多使用的Statement的個數 --> <property name="maxStatementsPerConnection">2</property> </named-config> </c3p0-config>
10.6 DBCP
-
匯入jar包
-
測試連線的程式碼
/** * 使用DBCP資料庫連線池技術獲取資料庫連線 * @return * @throws Exception */ //建立一個DBCP資料庫連線池 private static DataSource source; static { try { Properties pros = new Properties(); // InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties"); FileInputStream is = new FileInputStream(new File("src/dbcp.properties")); pros.load(is); //建立DBCP資料庫連線池 source = BasicDataSourceFactory.createDataSource(pros); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection2() throws Exception { Connection conn = source.getConnection(); System.out.println(conn); return conn; }
-
配置檔案
driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true username=root password=**** initialSize=10
10.7 Druid(最常用)
-
匯入jar包
-
測試連線的程式碼
/** * 使用Druid資料庫連線池技術 */ private static DataSource source1; static { Properties pros = new Properties(); InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties"); try { pros.load(is); //獲取Druid資料庫連線池 source1 = DruidDataSourceFactory.createDataSource(pros); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection3() throws Exception { Connection conn = source1.getConnection(); return conn; }
-
配置檔案
#等號最好不要有空格,否則會產生歧義,比如說密碼是否包括空格呢? url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true username=root password=**** driverClassName=com.mysql.cj.jdbc.Driver initialSize=10 maxActive=10
11-DBUtils提供的jar包實現CRUD操作
11.1 匯入jar包
11.2 使用現有的jar中的QueryRunner測試增、刪、改的操作
//測試插入
@Test
public void testInsert() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "insert into customers(name,email,birth) values(?,?,?)";
int insertCount = runner.update(conn, sql, "蔡徐坤", "[email protected]", "1999-09-09");
System.out.println("添加了"+insertCount+"條記錄");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
11.3 使用現有的jar中的QueryRunner測試查詢的操作
//測試查詢
/**
* BeanHandler:是ResultSetHandler介面的實現類,用於封裝表中的一條記錄
* @throws Exception
*/
@Test
public void testQuery1() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ? ";
BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
Customer customer = runner.query(conn, sql, handler, 25);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/**
* BeanListHandler:是ResultSetHandler介面的實現類,用於封裝表中的多條記錄構成的集合
* @throws Exception
*/
@Test
public void testQuery2() throws Exception {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id < ? ";
BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
List<Customer> customerList = runner.query(conn, sql, handler, 25);
customerList.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/**
* MapHandler:是ResultSetHandler介面的實現類,對應表中的一條記錄,將欄位及相應欄位的值作為map中的鍵和值
* @throws Exception
*/
@Test
public void testQuery3() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ? ";
MapHandler handler = new MapHandler();
Map<String,Object> map = runner.query(conn, sql, handler, 25);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/**
* MapListHandler:是ResultSetHandler介面的實現類,對應表中的多條記錄,將欄位及相應欄位的值作為map中的鍵和值,將這些map新增到List中
*/
@Test
public void testQuery4() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ? ";
MapListHandler handler = new MapListHandler();
List<Map<String, Object>> mapList = runner.query(conn, sql, handler, 25);
mapList.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/**
* ScalarHandler:是ResultSetHandler介面的實現類,用於查詢特殊值
*/
@Test
public void testQuery5() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select count(*) from customers";
ScalarHandler handler = new ScalarHandler();
Long count = (Long) runner.query(conn, sql, handler);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
public void testQuery6() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select max(birth) from customers";
ScalarHandler handler = new ScalarHandler();
Date max = (Date) runner.query(conn, sql, handler);
System.out.println(max);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/**
* 自定義ResultSetHandler實現類
*/
@Test
public void testQuery7() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>() {
@Override
public Customer handle(ResultSet resultSet) throws SQLException {
if(resultSet.next()){
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
String email = resultSet.getString(3);
Date birth = resultSet.getDate(4);
Customer customer = new Customer(id,name,email,birth);
return customer;
}
return null;
}
};
Customer customer = runner.query(conn, sql, handler, 12);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
11.4 使用dbutils.jar包中的dbutils工具類實現連線等資源的關閉
public static void closeResource1(Connection conn, Statement ps, ResultSet rs){
// try {
// DbUtils.close(conn);
// } catch (SQLException e) {
// e.printStackTrace();
// }
// try {
// DbUtils.close(ps);
// } catch (SQLException e) {
// e.printStackTrace();
// }
// try {
// DbUtils.close(rs);
// } catch (SQLException e) {
// e.printStackTrace();
// }
DbUtils.closeQuietly(conn,ps,rs);
}