當前位置:
首頁 > 知識 > JDBC02 利用JDBC連接資料庫

JDBC02 利用JDBC連接資料庫

目錄

1/2/3 Statement 和 Preparedstatement 的區別

4 讀取properties配置文件

5 資料庫連接池

6 利用資料庫連接池連接資料庫

1 使用Statement執行含有動態信息的SQL語句時有幾個不足:1.1 由於需要將動態數據拼接到SQL語句中,這導致程序複雜度高,容易出錯

1.2 拼接的數據若含有SQL語法內容就會導致拼接後的SQL語法含義改變而出現SQL注入攻擊

1.3 當大批量執行語義相同,但是含有動態數據的SQL時效率很差

2 使用Statement執行SQL語句不好的原因2.1 當執行一條SQL語句發送到資料庫時,資料庫先將該SQL解析並生成一個執行計劃(這個過程會消耗資源和性能),如果多次執行一樣的SQL語句,資料庫會重用執行計劃,但是若多次執行語義相同但是含有動態數據的SQL時,資料庫會生成不同的執行計劃,嚴重影響資料庫的開銷

2.2 例如

執行 SELECT * FROM userifo_fury 生成一個執行計劃再次執行SELECT * FROM userifo_fury 就會重用上面的執行計劃(因為這是靜態的SQL語句

但是,執行INSERT INTO userifo VALUES(1, "JACK","122314","141234@QQ.COM","FURY",15600) ) 生成一個執行計劃,再執行執行INSERT INTO userifo VALUES(2, "rose","122314","141234@QQ.COM","FURY",15600)由於內容不同,會再次生成另外一個執行計劃,若執行1000次上述情況的INSERT,資料庫會產生1000個執行計劃,這樣就嚴重影響了資料庫的效率 因此,Statement只適合執行靜態的SQL語句,不適合執行動態的SQL語句

3 利用PreparedStatement代替Statement編寫簡單沒有SQL注入問題批量執行語義相同的SQL語句會重用執行計劃

1 package cn.xiangxu.entity;
2
3 import java.io.Serializable;
4
5 public class User implements Serializable {
6
7 private static final long serialVersionUID = -5109978284633713580L;
8
9 private Integer id;
10 private String name;
11 private String pwd;
12 public User {
13 super;
14 // TODO Auto-generated constructor stub
15 }
16 public User(Integer id, String name, String pwd) {
17 super;
18 this.id = id;
19 this.name = name;
20 this.pwd = pwd;
21 }
22 @Override
23 public int hashCode {
24 final int prime = 31;
25 int result = 1;
26 result = prime * result + ((id == null) ? 0 : id.hashCode);
27 return result;
28 }
29 @Override
30 public boolean equals(Object obj) {
31 if (this == obj)
32 return true;
33 if (obj == null)
34 return false;
35 if (getClass != obj.getClass)
36 return false;
37 User other = (User) obj;
38 if (id == null) {
39 if (other.id != null)
40 return false;
41 } else if (!id.equals(other.id))
42 return false;
43 return true;
44 }
45 public Integer getId {
46 return id;
47 }
48 public void setId(Integer id) {
49 this.id = id;
50 }
51 public String getName {
52 return name;
53 }
54 public void setName(String name) {
55 this.name = name;
56 }
57 public String getPwd {
58 return pwd;
59 }
60 public void setPwd(String pwd) {
61 this.pwd = pwd;
62 }
63 @Override
64 public String toString {
65 return "User [id=" + id + ", name=" + name + ", pwd=" + pwd + "]";
66 }
67
68
69
70 }

user表對應的實體類

1 package testJDBC;
2
3 import java.sql.Connection;
4 import java.sql.DriverManager;
5 import java.sql.PreparedStatement;
6 import java.sql.ResultSet;
7 import java.sql.SQLException;
8 import java.util.ArrayList;
9 import java.util.List;
10
11 import org.junit.Test;
12
13 import cn.xiangxu.entity.User;
14
15 public class TestCase {
16 @Test
17 public void test01 {
18 Connection conn = null;
19 PreparedStatement ps = null;
20 ResultSet rs = null;
21 try {
22 Class.forName("com.mysql.jdbc.Driver"); // 載入資料庫驅動
23
24 conn = DriverManager.getConnection( // 初始化連接對象
25 "jdbc:mysql://localhost:3306/test", "root", "182838");
26
27
28 String sql = "SELECT * FROM user WHERE pwd = ? "; // 拼接SQL語句,位置參數用?代替
29
30 ps = conn.prepareStatement(sql); // 初始化預編譯執行對象
31
32 ps.setString(1, "182838"); // 設置SQL語句中的位置位置參數(注意:是從1開始數不是從0開始數)
33
34 rs = ps.executeQuery; // 執行SQL語句
35
36 List users = new ArrayList; // 創建一個集合來存放記錄對象
37 while(rs.next) { // 遍歷結果集
38 // System.out.println("====================");
39 // System.out.println(rs.getInt("id"));
40 // System.out.println(rs.getString("name"));
41 // System.out.println(rs.getString("pwd"));
42 User user = new User;
43 user.setId(rs.getInt("id"));
44 user.setName(rs.getString("name"));
45 user.setPwd(rs.getString("pwd"));
46 users.add(user); // 向集合中添加元素
47 }
48
49 System.out.println(users); // 列印輸出集合
50 for(User user : users) {
51 System.out.println(user);
52 }
53
54 // 釋放資源
55 rs.close;
56 ps.close;
57 conn.close;
58
59 } catch (Exception e) {
60 // TODO Auto-generated catch block
61 e.printStackTrace;
62 } finally {
63 if(rs != null) {
64 try {
65 rs.close;
66 } catch (SQLException e) {
67 // TODO Auto-generated catch block
68 e.printStackTrace;
69 }
70 }
71 if(ps != null) {
72 try {
73 ps.close;
74 } catch (SQLException e) {
75 // TODO Auto-generated catch block
76 e.printStackTrace;
77 }
78 }
79 if(conn != null) {
80 try {
81 conn.close;
82 } catch (SQLException e) {
83 // TODO Auto-generated catch block
84 e.printStackTrace;
85 }
86 }
87 }
88
89 }
90
91 }

使用預編譯Statement的實例

4 利用Properties對象讀取properties配置文件中的信息4.1 Properties繼承了Hashtable類,Properties對象也是使用鍵值對的方式來保存數據,但是Properties對象的鍵和值都是字元串類型

class Properties extends Hashtable

4.2 Properties 類中的主要方法4.2.1 public synchronized void load(InputStream inStream) throws IOException

將properties屬性文件的文件輸入流載入到Properties對象

4.2.2 public void store(OutputStream out, String comments) throws IOException

將Properties對象中的屬性列表保存到輸出流文件中

注意:第二個參數表示注釋信息(注意:properties文件中不能用中文),在注釋信息後面會自動添加一個時間信息

注意:新創建的文件在項目的根目錄下面(問題:為什麼在eclipse中沒有,但是到文件夾中卻能找到???)

4.2.3 public String getProperty(String key)

獲取屬性值,參數是屬性的鍵

4.2.4 public synchronized Object setProperty(String key, String value)

修改屬性值,參數1是屬性的鍵,參數2是屬性的新值

4.3 案例

要求:讀取properties配置文件總的屬性值,將讀取到的屬性值進行修改後保存到另外一個properties配置文件中

1 package cn.xiangxu.entity;
2
3 import java.io.FileInputStream;
4 import java.io.FileOutputStream;
5 import java.io.InputStream;
6 import java.util.Iterator;
7 import java.util.Properties;
8
9 public class Test {
10 public static void main(String[] args) {
11 try {
12 Properties prop = new Properties; // 創建Properties對象
13
14 // prop.load(new FileInputStream("config.properties")); // 使用這種方式時,配置文件必須放在項目的根目錄下
15 InputStream is = Test.class.getClassLoader.getResourceAsStream("config/config.properties"); // 讀取屬性文件
16
17 prop.load(is); // 載入屬性列表
18
19 Iterator it=prop.stringPropertyNames.iterator; // 將配置文件中的所有key放到一個可迭代對象中
20 while(it.hasNext){ // 利用迭代器模式進行迭代
21 String key=it.next; // 讀取下一個迭代對象的下一個元素
22 System.out.println(key+":"+prop.getProperty(key)); // 根據key值獲取value值(獲取屬性信息)
23 }
24
25 is.close; // 關閉輸入流,釋放資源
26
27 FileOutputStream oFile = new FileOutputStream("b.properties", true);//創建一個輸出流文件,true表示追加打開
28 prop.setProperty("maxactive", "33"); // 修改屬性信息
29 prop.store(oFile, "zhe shi yi ge xin de shu xing pei zhi wen jian."); // 將Properties對象中的內容放到剛剛創建的文件中去
30 oFile.close; // 關閉輸出流,釋放資源
31
32 } catch (Exception e) {
33 // TODO Auto-generated catch block
34 e.printStackTrace;
35 }
36 }
37 }

讀取屬性配置文件信息

等待讀取的properties配置文件的位置如下圖所示

JDBC02 利用JDBC連接資料庫

5 資料庫連接池5.1 什麼是資料庫連接池

程序啟動時就創建足夠多的資料庫連接,並將這些連接組成一個連接池,由程序自動地對池中的連接進行申請、使用、釋放

5.2 資料庫連接池的運行機制

》程序初始化時創建連接池

》需要操作資料庫時向資料庫連接池申請一個可用的資料庫連接

》使用完畢後就將資料庫連接還給資料庫連接池(注意:不是關閉連接,而是交給連接池)

》整個程序退出時,斷開所有連接,釋放資源(即:管理資料庫連接池的那個線程被殺死後才關閉所有的連接)

JDBC02 利用JDBC連接資料庫

5.3 資料庫連接池的編程步驟5.3.1 導包5.3.2 聲明ThreadLocal、BasicDataSource成員變數(注意:這兩個成員變數是靜態的)5.3.3 在靜態代碼塊中實例化那兩個成員變數,並通過Properties對象讀取配置文件信息,利用這些配置文件信息給BasicDataSource對象進行初始化處理

JDBC02 利用JDBC連接資料庫

5.3.4 編寫創建連接靜態方法

利用BasicDataSource對象實例化一個連接對象

將這個連接對象放到ThreadLocal對象中

JDBC02 利用JDBC連接資料庫

5.3.5 編寫釋放連接靜態方法

從ThreadLocal對象中獲取連接對象

清空ThreadLocal對象

判斷連接對象是否釋放

JDBC02 利用JDBC連接資料庫

6 利用資料庫連接池操作資料庫

項目結構圖

JDBC02 利用JDBC連接資料庫

1 # zhe shi zhu shi , yi ban bu yong zhong wen
2 # deng hao liang bian mei you kong ge, mo wei mei you fen hao
3 # hou mian bu neng you kong ge
4 driverClassName=com.mysql.jdbc.Driver
5 url=jdbc:mysql://localhost:3306/test
6 username=root
7 password=182838
8 maxActive=100
9 maxWait=3000

properties配置文件

1 2 4.0.0
3 cn.xiangxu
4 testJDBC
5 0.0.1-SNAPSHOT
6
7
8 mysql
9 mysql-connector-java
10 5.1.37
11

12
13 junit
14 junit
15 4.12
16

17
18 commons-dbcp
19 commons-dbcp
20 1.4
21

22

23

maven依賴文件

1 package cn.xiangxu.tools;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.sql.Connection;
6 import java.sql.SQLException;
7 import java.util.Properties;
8
9 import org.apache.commons.dbcp.BasicDataSource;
10
11 public class DBUtil {
12 /*
13 * ThreadLocal用於線程跨方法共享數據使用
14 * ThreadLocal內部有一個Map, key為需要共享數據的線程本身,value就是其需要共享的數據
15 */
16 private static ThreadLocal tl; // 聲明一個類似於倉庫的東西
17 private static BasicDataSource dataSource; // 聲明一個資料庫連接池對象
18
19 // 靜態代碼塊,在類載入的時候執行,而且只執行一次
20 static {
21 tl = new ThreadLocal; // 實例化倉庫對象
22 dataSource = new BasicDataSource; // 實例資料庫連接池對象
23
24 Properties prop = new Properties; // 創建一個Properties對象用(該對象可以用來載入配置文件中的屬性列表)
25 InputStream is = DBUtil.class.getClassLoader.getResourceAsStream("config/mysql.properties"); // 讀取配置文件信息
26 try {
27 prop.load(is); // 載入配置文件中的屬性列表
28
29 String driverClassName = prop.getProperty("driverClassName"); // 獲取屬性信息
30 String url = prop.getProperty("url");
31 String username = prop.getProperty("username");
32 String password = prop.getProperty("password");
33 Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
34 Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));
35
36 dataSource.setDriverClassName(driverClassName); // 初始化資料庫連接池(即:配置資料庫連接池的先關參數)
37 dataSource.setUrl(url);
38 dataSource.setUsername(username);
39 dataSource.setPassword(password);
40 dataSource.setMaxActive(maxActive);
41 dataSource.setMaxWait(maxWait);
42
43 is.close; // 關閉輸入流,釋放資源
44 } catch (IOException e) {
45 // TODO Auto-generated catch block
46 e.printStackTrace;
47 }
48
49 }
50
51 /**
52 * 創建連接對象(注意:靜態方法可以直接通過類名來調用)
53 * @return 連接對象
54 * @throws Exception
55 */
56 public static Connection getConnection throws Exception {
57 try {
58 Connection conn = dataSource.getConnection; // 創建連接對象(利用資料庫連接池進行創建)
59 tl.set(conn); // 將連接對象放到倉庫中
60 return conn;
61 } catch (Exception e) {
62 // TODO Auto-generated catch block
63 e.printStackTrace;
64 throw e;
65 }
66 }
67
68 /**
69 * 關閉連接對象(注意:靜態方法可以通過類名直接調用)
70 * @throws Exception
71 */
72 public static void closeConnection throws Exception {
73 Connection conn = tl.get; // 從倉庫中取出連接對象
74 tl.remove; // 清空倉庫
75 if(conn != null) { // 判斷連接對象是否釋放資源
76 try {
77 conn.close;
78 } catch (Exception e) {
79 // TODO Auto-generated catch block
80 e.printStackTrace;
81 throw e;
82 }
83 }
84 }
85
86 }

資料庫連接池類

1 package testJDBC;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6
7 import org.junit.Test;
8
9 import cn.xiangxu.tools.DBUtil;
10
11 public class TestDBUtil {
12 @Test
13 public void test01 {
14 try {
15 Connection conn = DBUtil.getConnection; // 創建連接對象
16 String sql = "SELECT * FROM user "; // 拼接SQL語句
17 PreparedStatement ps = conn.prepareStatement(sql); // 創建執行對象
18 ResultSet rs = ps.executeQuery(sql); // 執行SQL語句
19 while(rs.next) { // 遍歷結果集
20 System.out.println(rs.getString("name"));
21 }
22 } catch (Exception e) {
23 e.printStackTrace;
24 } finally { // 關閉連接,釋放資源
25 try {
26 DBUtil.closeConnection;
27 } catch (Exception e) {
28 e.printStackTrace;
29 }
30 }
31 }
32 }

資料庫連接池的應用

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 達人科技 的精彩文章:

14:40-15:00博客站點web伺服器雪崩似的CPU 100%
Elasticsearch學習隨筆(一)——原理理解與5.0核心插件部署過程
net 中web.config一個配置文件解決方法 (其他配置文件引入方式)
MVC通過遞歸+部分視圖實現評論

TAG:達人科技 |

您可能感興趣

ACCESS資料庫
HTML5 Web SQL 資料庫
SAS-你還在手動配置ODBC連接資料庫嗎
FC5新資料篇前瞻 RX 580 PK GTX 1060
3D建模軟體史話之一 「CG類」BIM收藏資料
小米MIX 3現身GeekBench資料庫:驍龍845+8G運存
ICDE:POLARDB定義雲原生資料庫
專訪百勝軟體CTO:30萬家門店,從MySQL到阿里雲POLARDB雲原生資料庫
雲資料庫TencentDBforCTSDB
TCGA資料庫mRNA&lncRNA數據提取
從Dell EMC vs.HPE的HCI資料中看到華為首次進入IDC全球TOP5……
SAP S/4 HANA Cloud資料庫加強AI能力
TCGA、GEO及SEER資料庫挖掘與應用學習會
GPU資料庫公司Zilliz完成1000萬美元A1輪融資,加速GPU資料庫商業化進程
阿里雲POLARDB榮膺2019中國資料庫年度最佳創新產品
CFPS和CHARLS資料庫分析技巧大指南
AMD新款速龍CPU現身資料庫;小米MIX 2S大曝光
阿里雲POLARDB獲選2019中國資料庫年度最佳創新產品
金融級資料庫 TDSQL:已支持日 3.6億+的交易量,TPS 10萬+
「DTCC 2018」為雲而生!解密華為 Cloud Native 分散式資料庫