溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

發(fā)布時間:2020-07-31 10:18:13 來源:網(wǎng)絡(luò) 閱讀:473 作者:yrgw 欄目:數(shù)據(jù)庫

1 使用Statement執(zhí)行含有動態(tài)信息的SQL語句時有幾個不足:

  1.1 由于需要將動態(tài)數(shù)據(jù)拼接到SQL語句中,這導(dǎo)致程序復(fù)雜度高,容易出錯
  1.2 拼接的數(shù)據(jù)若含有SQL語法內(nèi)容就會導(dǎo)致拼接后的SQL語法含義改變而出現(xiàn)SQL注入***
  1.3 當(dāng)大批量執(zhí)行語義相同,但是含有動態(tài)數(shù)據(jù)的SQL時效率很差

 

2 使用Statement執(zhí)行SQL語句不好的原因

  2.1 當(dāng)執(zhí)行一條SQL語句發(fā)送到數(shù)據(jù)庫時,數(shù)據(jù)庫先將該SQL解析并生成一個執(zhí)行計劃(這個過程會消耗資源和性能),如果多次執(zhí)行一樣的SQL語句,數(shù)據(jù)庫會重用執(zhí)行計劃,但是若多次執(zhí)行語義相同但是含有動態(tài)數(shù)據(jù)的SQL時,數(shù)據(jù)庫會生成不同的執(zhí)行計劃,嚴(yán)重影響數(shù)據(jù)庫的開銷
  2.2 例如

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

    但是,執(zhí)行INSERT INTO userifo VALUES(1, 'JACK','122314','141234@QQ.COM','FURY',15600) ) 生成一個執(zhí)行計劃,再執(zhí)行執(zhí)行INSERT INTO userifo VALUES(2, 'rose','122314','141234@QQ.COM','FURY',15600)由于內(nèi)容不同,會再次生成另外一個執(zhí)行計劃,若執(zhí)行1000次上述情況的INSERT,數(shù)據(jù)庫會產(chǎn)生1000個執(zhí)行計劃,這樣就嚴(yán)重影響了數(shù)據(jù)庫的效率
    因此,Statement只適合執(zhí)行靜態(tài)的SQL語句,不適合執(zhí)行動態(tài)的SQL語句

    

3 利用PreparedStatement代替Statement

  編寫簡單

  沒有SQL注入問題

  批量執(zhí)行語義相同的SQL語句會重用執(zhí)行計劃

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 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 stub15     }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     @Override23     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     @Override30     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     @Override64     public String toString() {65         return "User [id=" + id + ", name=" + name + ", pwd=" + pwd + "]";66     }67     68     69 70 }

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 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     @Test17     public void test01() {18         Connection conn = null;19         PreparedStatement ps = null;20         ResultSet rs = null;21         try {22             Class.forName("com.mysql.jdbc.Driver"); // 加載數(shù)據(jù)庫驅(qū)動23             24             conn = DriverManager.getConnection( // 初始化連接對象25                     "jdbc:mysql://localhost:3306/test", "root", "182838");26             27             28             String sql = "SELECT * FROM user WHERE pwd = ? "; // 拼接SQL語句,位置參數(shù)用?代替29             30             ps = conn.prepareStatement(sql); // 初始化預(yù)編譯執(zhí)行對象31             32             ps.setString(1, "182838"); // 設(shè)置SQL語句中的位置位置參數(shù)(注意:是從1開始數(shù)不是從0開始數(shù))33             34             rs = ps.executeQuery(); // 執(zhí)行SQL語句35             36             List<User> users = new ArrayList<User>(); // 創(chuàng)建一個集合來存放記錄對象37             while(rs.next()) { // 遍歷結(jié)果集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 block61             e.printStackTrace();62         } finally {63             if(rs != null) {64                 try {65                     rs.close();66                 } catch (SQLException e) {67                     // TODO Auto-generated catch block68                     e.printStackTrace();69                 }70             }71             if(ps != null) {72                 try {73                     ps.close();74                 } catch (SQLException e) {75                     // TODO Auto-generated catch block76                     e.printStackTrace();77                 }78             }79             if(conn != null) {80                 try {81                     conn.close();82                 } catch (SQLException e) {83                     // TODO Auto-generated catch block84                     e.printStackTrace();85                 }86             }87         }88         89     }90     91 }

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 

4 利用Properties對象讀取properties配置文件中的信息

  4.1 Properties繼承了Hashtable類,Properties對象也是使用鍵值對的方式來保存數(shù)據(jù),但是Properties對象的鍵和值都是字符串類型

    class Properties extends Hashtable<Object,Object>

  4.2 Properties 類中的主要方法

    4.2.1 public synchronized void load(InputStream inStream) throws IOException

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

     JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

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

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

      JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

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

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

    4.2.3 public String getProperty(String key)

      獲取屬性值,參數(shù)是屬性的鍵

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

      修改屬性值,參數(shù)1是屬性的鍵,參數(shù)2是屬性的新值

  4.3 案例

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

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 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(); // 創(chuàng)建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<String> it=prop.stringPropertyNames().iterator(); // 將配置文件中的所有key放到一個可迭代對象中20             while(it.hasNext()){ // 利用迭代器模式進行迭代21                 String key=it.next(); // 讀取下一個迭代對象的下一個元素22                 System.out.println(key+":"+prop.getProperty(key)); // 根據(jù)key值獲取value值(獲取屬性信息)23             }24             25             is.close(); // 關(guān)閉輸入流,釋放資源26             27             FileOutputStream oFile = new FileOutputStream("b.properties", true);//創(chuàng)建一個輸出流文件,true表示追加打開28             prop.setProperty("maxactive", "33"); // 修改屬性信息29             prop.store(oFile, "zhe shi yi ge xin de shu xing pei zhi wen jian."); // 將Properties對象中的內(nèi)容放到剛剛創(chuàng)建的文件中去30             oFile.close(); // 關(guān)閉輸出流,釋放資源31             32         } catch (Exception e) {33             // TODO Auto-generated catch block34             e.printStackTrace();35         } 
36     }37 }

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

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

      JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 

5 數(shù)據(jù)庫連接池

  5.1 什么是數(shù)據(jù)庫連接池

    程序啟動時就創(chuàng)建足夠多的數(shù)據(jù)庫連接,并將這些連接組成一個連接池,由程序自動地對池中的連接進行申請、使用、釋放

  5.2 數(shù)據(jù)庫連接池的運行機制

    》程序初始化時創(chuàng)建連接池

    》需要操作數(shù)據(jù)庫時向數(shù)據(jù)庫連接池申請一個可用的數(shù)據(jù)庫連接

    》使用完畢后就將數(shù)據(jù)庫連接還給數(shù)據(jù)庫連接池(注意:不是關(guān)閉連接,而是交給連接池)

    》整個程序退出時,斷開所有連接,釋放資源(即:管理數(shù)據(jù)庫連接池的那個線程被殺死后才關(guān)閉所有的連接)

     JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

  5.3 數(shù)據(jù)庫連接池的編程步驟

    5.3.1 導(dǎo)包

      JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

    5.3.2 聲明ThreadLocal、BasicDataSource成員變量(注意:這兩個成員變量是靜態(tài)的)

      JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

    5.3.3 在靜態(tài)代碼塊中實例化那兩個成員變量,并通過Properties對象讀取配置文件信息,利用這些配置文件信息給BasicDataSource對象進行初始化處理

  JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

    5.3.4 編寫創(chuàng)建連接靜態(tài)方法

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

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

      JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

    5.3.5 編寫釋放連接靜態(tài)方法

      從ThreadLocal對象中獲取連接對象

      清空ThreadLocal對象

      判斷連接對象是否釋放

      JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 

6 利用數(shù)據(jù)庫連接池操作數(shù)據(jù)庫

  項目結(jié)構(gòu)圖

    JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

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 hao3 # hou mian bu neng you kong ge4 driverClassName=com.mysql.jdbc.Driver5 url=jdbc:mysql://localhost:3306/test6 username=root7 password=1828388 maxActive=1009 maxWait=3000

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 2   <modelVersion>4.0.0</modelVersion> 3   <groupId>cn.xiangxu</groupId> 4   <artifactId>testJDBC</artifactId> 5   <version>0.0.1-SNAPSHOT</version> 6   <dependencies> 7       <dependency> 8           <groupId>mysql</groupId> 9           <artifactId>mysql-connector-java</artifactId>10           <version>5.1.37</version>11       </dependency>12       <dependency>13           <groupId>junit</groupId>14           <artifactId>junit</artifactId>15           <version>4.12</version>16       </dependency>17       <dependency>18           <groupId>commons-dbcp</groupId>19           <artifactId>commons-dbcp</artifactId>20           <version>1.4</version>21       </dependency>22   </dependencies>23 </project>

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 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用于線程跨方法共享數(shù)據(jù)使用14      * ThreadLocal內(nèi)部有一個Map,  key為需要共享數(shù)據(jù)的線程本身,value就是其需要共享的數(shù)據(jù)15      */16     private static ThreadLocal<Connection> tl; // 聲明一個類似于倉庫的東西17     private static BasicDataSource dataSource; // 聲明一個數(shù)據(jù)庫連接池對象18     19     // 靜態(tài)代碼塊,在類加載的時候執(zhí)行,而且只執(zhí)行一次20     static {21         tl = new ThreadLocal<Connection>(); // 實例化倉庫對象22         dataSource = new BasicDataSource(); // 實例數(shù)據(jù)庫連接池對象23 24         Properties prop = new Properties(); // 創(chuàng)建一個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); // 初始化數(shù)據(jù)庫連接池(即:配置數(shù)據(jù)庫連接池的先關(guān)參數(shù))37             dataSource.setUrl(url);38             dataSource.setUsername(username);39             dataSource.setPassword(password);40             dataSource.setMaxActive(maxActive);41             dataSource.setMaxWait(maxWait);42             43             is.close(); // 關(guān)閉輸入流,釋放資源44         } catch (IOException e) {45             // TODO Auto-generated catch block46             e.printStackTrace();47         } 
48         49     }50     51     /**52      * 創(chuàng)建連接對象(注意:靜態(tài)方法可以直接通過類名來調(diào)用)53      * @return 連接對象54      * @throws Exception55      */56     public static Connection getConnection() throws Exception { 
57         try {58             Connection conn = dataSource.getConnection(); // 創(chuàng)建連接對象(利用數(shù)據(jù)庫連接池進行創(chuàng)建)59             tl.set(conn); // 將連接對象放到倉庫中60             return conn; 
61         } catch (Exception e) {62             // TODO Auto-generated catch block63             e.printStackTrace();64             throw e;65         }66     }67     68     /**69      * 關(guān)閉連接對象(注意:靜態(tài)方法可以通過類名直接調(diào)用)70      * @throws Exception71      */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 block80                 e.printStackTrace();81                 throw e;82             }83         }84     }85 86 }

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

JDBC02 利用JDBC連接數(shù)據(jù)庫【使用數(shù)據(jù)庫連接池】

 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     @Test13     public void test01() {14         try {15             Connection conn = DBUtil.getConnection(); // 創(chuàng)建連接對象16             String sql = "SELECT * FROM user "; // 拼接SQL語句17             PreparedStatement ps = conn.prepareStatement(sql); // 創(chuàng)建執(zhí)行對象18             ResultSet rs = ps.executeQuery(sql); // 執(zhí)行SQL語句19             while(rs.next()) { // 遍歷結(jié)果集20                 System.out.println(rs.getString("name"));21             }22         } catch (Exception e) {23             e.printStackTrace();24         } finally {  // 關(guān)閉連接,釋放資源25             try {26                 DBUtil.closeConnection();27             } catch (Exception e) {28                 e.printStackTrace();29             }30         }31     }32 }


向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI