javaweb-day06-jdbc連線池
阿新 • • 發佈:2021-01-18
JDBC連線池&JDBCTemplate
- jdbc連線池
- 程式和資料庫之間的連線是底層技術,每一次連線都比較耗時,而用完後又得關閉連線釋放資源,這樣反覆連線和釋放其實是很浪費時間的,因此引出一個連線池技術,來管理這些連線物件。連線物件被使用完後,會歸還給連線池,等待分配給下一次使用,而不是銷燬。
- jdbcTemplate
- jdbc操作中,很多的程式碼大量重複出現,其實我們寫熟練以後,發現只需要關注sql怎麼寫就可以,所以對重複出現的程式碼進行封裝來簡化jdbc的操作。
一.資料庫連線池
1. 概述
-
打個比方,過獨木橋。
沒有連線池時,一人一個獨木橋,過河就拆,所以每來一個人過河就要搭建一個新的獨木橋。
有了連線池後,就相當於建了一座大橋,可以同時讓多個人通過,不需要一直建,一直拆。
-
畫圖理解。
2. 程式碼實現介紹
-
java.sql.DataSuorce 介面,就是表示連線池
- getConnection()方法 可以獲取連線物件
-
資料來源介面的實現由連線池廠商實現
- c3p0 古老的,常被hibernate框架使用
- druid 阿里的產品,效率很高
-
如果連線物件是由連線池得到的,那麼它的Connection.close方法將不再表示關閉連線,而是歸還連線物件到連線池。
3. c3p0連線池
3.1 基本使用
- 導jar包 – 兩個連線池 一個數據庫驅動 共3個
- 配置檔案簡介
<?xml version="1.0" encoding="utf-8" ?>
<c3p0-config>
<!-- 使用預設的配置讀取連線池物件 -->
<default-config>
<!-- 連線引數 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db1</property>
<property name=" user">root</property>
<property name="password">root</property>
<!-- 連線池引數 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="myc3p0">
<!-- 連線引數 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 連線池引數 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
<property name="checkoutTimeout">5000</property>
</named-config>
</c3p0-config>
-
注意事項:
- c3p0-config.xml 檔名必須這麼命名
- c3p0-config.xml 檔案必須放在src目錄下,不能放在子目錄
-
可能會出錯的地方
- 配置檔案中書寫錯誤
- 檔名或路徑錯誤
- 資料庫連線四大引數書寫錯誤,或多加空格
- 忘記匯入驅動jar包
public static void main(String[] args) throws SQLException { //建立連線池資料來源物件 ComboPooledDataSource ds = new ComboPooledDataSource(); //獲得連線物件 Connection con = ds.getConnection(); //輸出連線物件的地址值表示連線正常 System.out.println(con); }
- 配置檔案中書寫錯誤
3.2 熟悉配置檔案
-
測試最大連線數
//不給引數,預設使用default-config配置的資料來源 ComboPooledDataSource ds = new ComboPooledDataSource(); //迴圈建立11個連線物件 for (int i=1;i<=11;i++){ Connection con = ds.getConnection(); System.out.println(i+":"+con); if(i==6){ con.close();//歸還第6個物件給連線池 } }
-
測試超時時間
-
測試命名的資料來源
ComboPooledDataSource ds = new ComboPooledDataSource("otherc3p0");
4. druid連線池
4.1 基本使用
-
匯入jar包-- 1個
-
定義配置檔案 druid.properties
-
程式碼演示
//1.匯入jar包,定義配置檔案 //2.載入配置檔案 Properties pro = new Properties(); InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(is); //3.獲取連線池物件 DataSource ds = DruidDataSourceFactory.createDataSource(pro); //4.獲取連線物件 Connection con = ds.getConnection(); System.out.println(con);
4.2 工具類
-
程式碼演示
public class JDBCUtil { //1.定義一個數據源成員屬性 private static DataSource ds; //2.在靜態程式碼塊中載入配置檔案 static { try { Properties pro = new Properties(); InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(is); //3.建立連線池物件 ds = DruidDataSourceFactory.createDataSource(pro); } catch (Exception e) { e.printStackTrace(); } } //獲取連線物件的方法 public static Connection getConnection() throws SQLException { return ds.getConnection(); } //獲取連線池物件的方法 public static DataSource getDataSource(){ return ds; } //釋放資源的方法 public void close(Statement stmt, Connection con, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stmt!=null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(con!=null){ try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
4.3 工具類測試
-
程式碼演示–向account表中新增一條資料
public static void main(String[] args) { Connection con=null; PreparedStatement pstmt=null; try { //1.獲取連線物件 con = JDBCUtil.getConnection(); //2.定義sql String sql="insert into account values (null,?,?)"; //3.建立pstmt物件 pstmt = con.prepareStatement(sql); //4.給?賦值 pstmt.setString(1,"曹操"); pstmt.setDouble(2,3000); //5.執行sql int count = pstmt.executeUpdate(); System.out.println(count); } catch (SQLException e) { e.printStackTrace(); }finally { //6.釋放資源 JDBCUtil.close(pstmt,con); } }
總結:
1.什麼是連線池
1.就是一個容器
2.容器中裝的是connection連線物件
3.這些連線物件建立後可以反覆被使用,並不會銷燬
4.它們是共享的
2.連線物件和連線池物件
connection 連線
DataSource 連線池 -- 資料來源
獲取;
DataSource ds=new DruidDataSource();
ds.getConnection();
-- 通過資料來源獲取資料,其實就是通過連線池獲取連線
3.常用的連線池
c3p0 hibernate 傳統的orm框架
druid 國產的 阿里
4.連線池的好處
1.節約資源 提高效率
二.jdbcTemplate
1. 簡介
- Spring框架對jdbc的簡單封裝,提供了一個JdbcTemplate物件
- jdbcTemplate的若干方法
- update 執行 dml增刪改
- queryForMap() 查詢結果,將結果集封裝為map集合
- queryForList() 查詢結果,將結果集封裝為list集合
- queryForObject() 查詢結果集,將結果集封裝成某個資料型別
- query() 查詢結果集,將結果集封裝為Javabean物件
2. 快速入門
-
程式碼演示–修改曹操的金額為5000
public static void main(String[] args) { //1.匯入jar包 //2.建立jdbcTemplate物件 JdbcTemplate template = new JdbcTemplate(JDBCUtil.getDataSource()); //3.定義sql語句 String sql="update account set balance=5000 where id=?"; // 4.呼叫update方法,並給?賦值 int count = template.update(sql, 3); System.out.println(count); }
3. jdbcTemplate綜合練習
- 修改id為1的資料
- 新增一條資料
- 刪除一條資料
- 查詢id為1的一條記錄,封裝成map
- 查詢id為1的一條記錄,封裝成Account
- 查詢所有記錄,封裝成list
- 查詢所有記錄,封裝成泛型為Account的List
- 查詢總記錄數
public class DruidDemo3 {
private JdbcTemplate template= new JdbcTemplate(JDBCUtil.getDataSource());
@Test//修改
public void test1(){
int count = template.update("update account set balance=? where id=?",888,1);
System.out.println(count);
}
@Test//新增
public void test2(){
int count = template.update("insert account values (null,?,?)","哪吒",666);
System.out.println(count);
}
@Test//刪除
public void test3(){
int count = template.update("delete from account where id=?",3);
System.out.println(count);
}
@Test//查詢一條 封裝map
public void test4(){
Map<String, Object> map = template.queryForMap("select * from account where id=?", 1);
System.out.println(map);
}
@Test//查詢一條 封裝javaBean
public void test5(){
Account account = template.queryForObject("select * from account where id=?", new BeanPropertyRowMapper<Account>(Account.class),2);
System.out.println(account);
}
@Test//查詢所有,封裝成List中泛型為Map
public void test6(){
List<Map<String, Object>> list = template.queryForList("select * from account ");
System.out.println(list);
}
@Test//查詢所有,封裝成List中泛型為JavaBean
public void test7(){
List<Account> list = template.query("select * from account ", new BeanPropertyRowMapper<Account>(Account.class));
System.out.println(list);
}
@Test//查詢總記錄數
public void test8(){
Integer a = template.queryForObject("select count(*) from account ", Integer.class);
System.out.println(a);
}
}
補充
1.部門表和員工表的查詢並關聯封裝
@Test//每一個員工和他對應得部門資訊
public void test2(){
List<Emp> emps = template.query("select * from emp ", new BeanPropertyRowMapper<Emp>(Emp.class));
//關聯每個部門下 的多個員工資訊
for (Emp emp : emps) {
emp.setDept(template.queryForObject("select * from dept where id=?",new BeanPropertyRowMapper<Dept>(Dept.class),emp.getDept_id()));
}
//輸出
System.out.println(emps);
}
@Test//查詢所有的部門下所有的員工
public void test1(){
List<Dept> depts = template.query("select * from dept ", new BeanPropertyRowMapper<Dept>(Dept.class));
//關聯每個部門下 的多個員工資訊
for (Dept dept : depts) {
dept.setEmps(template.query("select * from emp where dept_id=?",new BeanPropertyRowMapper<Emp>(Emp.class),dept.getId()));
}
//輸出
System.out.println(depts);
}
2.三層架構
controller 控制層
service 業務層 --包含介面和實現類
dao 執行層 --包含介面和實現類
controller層 --呼叫--> service層 --呼叫--> dao層
注意:
介面和實現類的正確命名
3.template結合BeanPropertyRowMapper封裝的模擬實現
@Test
public void testQuery1(){
List<Emp> emps = myQuery("SELECT * FROM EMP WHERE ID> ?", Emp.class, 3);
System.out.println(emps);
}
// 結合反射和原始的jdbc模擬查詢和封裝的實現
public <T> List<T> myQuery(String sql, Class<T> c,Object ...args){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql:///db3","root","root");
//3.獲取執行sql的物件
PreparedStatement pstm = con.prepareStatement(sql);
//4.給佔位符賦值
for (int i = 0; i < args.length; i++) {
pstm.setObject(i+1,args[i]);
}
//5.執行sql
ResultSet rs = pstm.executeQuery();
//6.處理結果集--拆開rs
//元資料--可以獲取結果集中的列數,列名,列型別
ResultSetMetaData md = rs.getMetaData();
//獲取總列數
int columnCount = md.getColumnCount();
ArrayList<T> ts = new ArrayList<>();
while (rs.next()){//外層迴圈遍歷每一行
T t = c.newInstance();
for (int i = 1; i <= columnCount; i++) {//外層迴圈遍歷每一行的每一個單元格
Object value = rs.getObject(i);
String columnName = md.getColumnName(i).toLowerCase();//獲取每一個列的列名--和T中的屬性名一致的
String columnName1 = md.getColumnLabel(i);//獲取每一個列的列名--和T中的屬性名一致的
String columnName2 = md.getColumnClassName(i);//獲取每一個列的列名--和T中的屬性名一致的
System.out.println(columnName+"--"+columnName1+"--"+columnName2);
Field f = c.getDeclaredField(columnName);
f.setAccessible(true);//開啟私有屬性的操作許可權
f.set(t,value);
}
ts.add(t);
}
return ts;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}