JDBC知識點總結


一:JDBC 概述

    一、簡介

       1. JDBC(Java DataBase Connection,Java 數據庫連接)Java語言中用來規范客戶端程序如何來訪問數據庫的應用程序接口,提供了諸如查詢和更新數據庫中數據的方法。

       2. JDBC 是一個標准 SQL(Structured Query Language,結構化查詢語言)數據庫訪問接口,可以為多種關系數據庫提供統一訪問。也提供一種基准,據此可以構建更高級的工具和接口。

       3. JDK(Java Development Kit,Java 開發工具包)軟件捆綁包括 JDBC 和 JDBC-ODBC(Open DataBase Connection,開放式數據庫連接)橋。

          

 

    二、API

     

 

二:JDBC 開發步驟

    一、配置依賴 jar 包

       1. 下載

           1. MySQL

              

 

           2. Oracle

              

 

       2. 配置

           1. 導入 jar 包

              

 

           2. Maven 配置

 1 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
 2 <dependency>
 3     <groupId>mysql</groupId>
 4     <artifactId>mysql-connector-java</artifactId>
 5     <version>8.0.20</version>
 6 </dependency>
 7 
 8 <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc10 -->
 9 <dependency>
10     <groupId>com.oracle.database.jdbc</groupId>
11     <artifactId>ojdbc10</artifactId>
12     <version>19.3.0.0</version>
13 </dependency>

 

    二、注冊驅動

 1 public class DriverTest {
 2     /**
 3      * 通過反射機制,加載數據庫驅動,類初始化的時候執行靜態代碼塊
 4      *   優點1:此方式由於參數為字符串,因此很容易修改,移植性強。
 5      *   優點2:不依賴特定的Driver庫,很容易改造成從配置文件讀取JDBC配置,從而可以在運行時動態更換數據庫連接驅動。
 6      */
 7     static {
 8         try {
 9             /**
10              * MySQL:8.0版本,5.0版本為:com.mysql.jdbc.Driver
11              */
12             Class.forName("com.mysql.cj.jdbc.Driver");
13             
14             /**
15              * Oracle
16              */
17             Class.forName("oracle.jdbc.driver.OracleDriver");
18         } catch (ClassNotFoundException e) {
19             // TODO Auto-generated catch block
20             e.printStackTrace();
21         } // 8版本
22     }
23 }

 

    三、獲取連接

 1 public class ConnectionTest {
 2     /**
 3      * MySQL
 4      */
 5     public Connection getMysqlConnection() {
 6         // 本地連接URL:jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
 7         // 遠程連接URL:jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
 8         final String url = "jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC";
 9         // 連接用戶名
10         final String user = "root";
11         // 連接密碼
12         final String password = "000000";
13         Connection conn = null;
14         if (conn == null) {
15             try {
16                 conn = DriverManager.getConnection(url, user, password);
17             } catch (SQLException e) {
18                 // TODO Auto-generated catch block
19                 System.err.println("Oracle數據庫連接出錯");
20                 e.printStackTrace();
21             }
22         }
23         return conn;
24     }
25 
26     /**
27      * Oracle
28      */
29     public Connection getOracleConnection() {
30         /**
31          * 1. 使用thin連接:jdbc:oracle:thin:@<host>:<port>:<database>
32          *    優點:thin完全由Java代碼編寫,與平台無關,不需要Oracle客戶端。
33          *    缺點:thin性能一般,達不到如OCI方式的企業級的要求,一般適合一台主機連接。
34          * 
35          * 2. 使用oci連接:jdbc:oracle:oci:@<host>:<port>:<database>
36          *    優點:用OCI連接數據庫是企業級的做法,適應於單個數據庫和集群數據庫,性能優越,尤其是連接池功能大大提高了應用程序的性能和並發量。
37          *    缺點:若想使用OCI必須要安裝Oracle客戶端。
38          */
39         final String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
40         // 連接用戶名
41         final String user = "scott";
42         // 連接密碼
43         final String password = "tiger";
44         // 連接對象
45         Connection conn = null;
46         if (conn == null) {
47             try {
48                 conn = DriverManager.getConnection(url, user, password);
49             } catch (SQLException e) {
50                 // TODO Auto-generated catch block
51                 System.err.println("Oracle數據庫連接出錯");
52                 e.printStackTrace();
53             }
54         }
55         return conn;
56     }
57 }

 

    四、創建Statement、PreparedStatement、CallableStatement接口,執行SQL語句

 1 package pers.mj.test;
 2 
 3 import java.sql.CallableStatement;
 4 import java.sql.Connection;
 5 import java.sql.PreparedStatement;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 import java.sql.Statement;
 9 import java.sql.Types;
10 
11 public class MysqJDBClTest {
12     /**
13      * Statement 的作用:用於執行靜態 SQL 語句並返回它所生成結果的對象,完成對數據庫的增刪改查。
14      * Statement 的優點:語法簡單,對於只執行一次的 SQL 語句,使用 Statement 比 PreparedStatement 對象的開銷更小。
15      * Statement 的缺點:每次執行時相似SQL都會進行編譯  ,采用硬編碼效率低,安全性較差,字符串拼接方式的 SQL 語句是非常繁瑣的,中間有很多的單引號和雙引號的混用,極易出錯。
16      * Statement 的適用場景:普通的不帶參的查詢SQL 
17      */
18     public void testStatement() {
19         try {
20             // 獲取數據庫連接
21             Connection conn = DBUtil.getMysqlConnection();
22             // 創建 Statement 對象
23             Statement st = conn.createStatement();
24             // 定義SQL語句
25             String sql = "insert into student(stu_id, stu_name) values(20200626, " + " '張三')"; // 字符串拼接麻煩
26             /**
27              * 演示SQL注入問題:如果此時傳遞給字段的值為:or 1 = 1,那么不論如何條件都成立,導致結果都成功,這就是SQL注入
28              */
29             String SQL = "select * from student where stu_name="+"'張三' and stu_id= "+"'or 1 = 1' ";
30             // 執行SQL語句
31             if (st.execute(sql)) {
32                 System.out.println("信息插入成功");
33             }
34         } catch (SQLException e) {
35             System.err.println("插入語句執行失敗");
36             e.printStackTrace();
37         }
38     }
39     
40     /**
41      * PreparedStatement 的作用:用於執行動態 SQL 語句並返回它所生成結果的對象,完成對數據庫的增刪改查。繼承Statement
42      * PreparedStatement 的優點:相似SQL只編譯一次,減少編譯次數,代碼的可讀性和可維護性更高,提高了安全性(阻止了SQL注入)。
43      * PreparedStatement 的缺點:執行非相似SQL語句時,速度較慢。
44      * PreparedStatement 的適用場景:支持可變參數的SQL 
45      */
46     public void testPreparedStatement() {
47         try {
48             // 獲取數據庫連接
49             Connection conn = DBUtil.getMysqlConnection();
50             // 定義SQL語句
51             String sql = "insert into student(stu_id, stu_name) values(?, ?)"; 
52             /**
53              * 解決SQL注入問題:PreparedStatement不是將參數簡單拼湊成sql,而是做了一些預處理,將參數轉換為string,兩端加單引號,將參數內的一些特殊字符(換行,單雙引號,斜杠等)做轉義處理,這樣就很大限度的避免了sql注入。
54              */
55             String SQL = "select * from student where stu_name=? and stu_id= ? ";
56             // 預編譯SQL語句,防止SQL注入
57             PreparedStatement ps = conn.prepareStatement(sql);
58             // 給占位符(?)賦值:索引從1開始,數據類型需要相對應
59             ps.setInt(1, 20180627);
60             ps.setString(2, "李四");
61             // 執行SQL語句
62             if (ps.execute()) {
63                 System.out.println("信息插入成功");
64             }
65         } catch (SQLException e) {
66             System.err.println("插入語句執行失敗");
67             e.printStackTrace();
68         }
69     }
70     
71     /**
72      * CallableStatement 的作用:實現了存儲過程函數調用的方法以及對於輸出的處理。繼承PreparedStatement
73      * CallableStatement 的使用場景:支持調用存儲過程,提供了對輸出和輸入/輸出參數(INOUT)的支持
74      */
75     public void testCallableStatement(){
76         try {
77             // 獲取數據庫連接
78             Connection conn = DBUtil.getMysqlConnection();
79             // 定義SQL語句
80             String sql = "call p3(?,?)";
81             // 預編譯SQL
82             CallableStatement cs = conn.prepareCall(sql);
83             // 給站位符賦值
84             cs.setString(1, "王五"); 
85             cs.registerOutParameter(2, Types.INTEGER);  // 注冊一個輸入參數
86             // 執行SQL
87             cs.execute();
88             // 獲取結果集對象
89             ResultSet resultSet = cs.getResultSet();
90             while (resultSet.next()) {
91                 System.out.println(resultSet.getString("name")+" ");                
92             }
93             // 獲取輸出參數
94             System.out.println(cs.getInt(2));
95         } catch (Exception e) {
96             // TODO: handle exception
97         }
98     }
99 }

 

    五、execute、executeQuery和executeUpdate詳解

  1 public class ExecuteTest {
  2     // 數據庫連接對象
  3     Connection conn = null;
  4     // 預處理對象
  5     PreparedStatement ps = null;
  6     // 結果集對象
  7     ResultSet rs = null;
  8     
  9     /**
 10      * executeQuery()
 11      *   作用:只能執行DQL(SELECT語句),是使用最多的查詢語句。
 12      *   返回值:單個結果及對象(ResultSet)
 13      */
 14     public void testExecuteQuery() {
 15         try {
 16             // 獲取數據庫連接
 17             conn = DBUtil.getMysqlConnection();
 18             // 定義SQL語句
 19             String sql = "SELECT stu_id,stu_name FROM student WHERE stu_id=? ";
 20             // 預編譯SQL
 21             ps = conn.prepareStatement(sql);
 22             // 給占位符賦值
 23             ps.setInt(1, 20200626);
 24             // 執行SQL語句
 25             rs = ps.executeQuery();
 26             while (rs.next()) {
 27                 System.out.println("學號:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
 28             }
 29         } catch (Exception e) {
 30             // TODO: handle exception
 31         }
 32     }
 33 
 34     /**
 35      * executeUpdate()
 36      *   作用:執行DML(除去SELECT語句)和DDL,修改表中零行或多行中的一列或多列。
 37      *   返回值:受影響的行數(整數)
 38      */
 39     @Test
 40     public void testExecuteUpdate() {
 41         try {
 42             // 獲取數據庫連接
 43             conn = DBUtil.getMysqlConnection();
 44             // 定義SQL語句
 45             String sql = "UPDATE student SET stu_name=? WHERE stu_id=?";
 46             // 預編譯SQL
 47             ps = conn.prepareStatement(sql);
 48             // 給占位符賦值
 49             ps.setString(1, "王五");
 50             ps.setInt(2, 20200626);
 51             // 執行SQL語句
 52             if (ps.executeUpdate() != 0) {
 53                 System.out.println("信息修改成功");
 54             }
 55         } catch (Exception e) {
 56             // TODO: handle exception
 57         }
 58     }
 59 
 60     /**
 61      * execute()
 62      *   作用:用於執行返回多個結果集、多個更新計數或二者組合的語句。例如:執行某個已存儲過程或動態執行未知 SQL 字符串。
 63      *   返回值:多個ResultSet對象、多個更新計數或ResultSet對象與更新計數。
 64      *   使用
 65      *    多個結果集
 66      *      1. 執行完execute()方法后,使用CallableStatement對象調用getResultSet()方法獲取第一個結果集,調用適當的getXXX方法獲取值
 67      *      2. 如果存在第二個結果集,則必須調用getMoreResults()方法,然后再調用getResultSet()方法來獲取結果集,依次類推。
 68      *    多個更新計數
 69      *      1. 執行完execute()方法后,則首先調用方法 getUpdateCount,然后調用 getMoreResults,並再次調用 getUpdateCount,依次類推。
 70      *   
 71      */
 72     public void testExecute() {
 73         List<List<Map<String, Object>>> resultList = new ArrayList<>();
 74         try {
 75             // 獲取數據庫連接
 76             conn = DBUtil.getMysqlConnection();
 77             // 定義SQL語句
 78             String sql = "sp_help 'test.student'";
 79             // 預編譯SQL
 80             CallableStatement cs = conn.prepareCall(sql);
 81              // 外循環獲取結果集的個數
 82             boolean oprFlg  = cs.execute(sql);
 83             while (oprFlg) {
 84                 List<Map<String, Object>> result = new ArrayList<>();
 85                 // 獲取第一個結果集
 86                 rs = cs.getResultSet();
 87                 // 內循環獲取每個結果集的記錄
 88                 while (rs.next()) {
 89                     ResultSetMetaData rsmd = rs.getMetaData();
 90                     int columnCount = rsmd.getColumnCount();
 91                     Map<String, Object> map = new HashMap<String, Object>();
 92                     for (int i = 0; i < columnCount; i++) {
 93                         map.put(rsmd.getColumnName(i + 1).toLowerCase(), rs.getObject(i + 1));
 94                     }
 95                     result.add(map);
 96                 }
 97                 resultList.add(result);
 98                 // 獲取更多的結果集
 99                 oprFlg = cs.getMoreResults();
100             }
101         } catch (Exception e) {
102             // TODO: handle exception
103         }
104     }

 

    六、處理結果集

      1. ResultSet:在線

 1 public class ResultSetTest {
 2     // 數據庫連接對象
 3     Connection conn = null;
 4     // 預處理對象
 5     PreparedStatement ps = null;
 6     // 結果集對象
 7     ResultSet rs = null;
 8 
 9     /**
10      * 可滾動,可更新
11      *    ResultSet.TYPE_FORWARD_ONLY:該常量控制ResultSet記錄指針只能向前移動(默認)。
12      *    ResultSet.TYPE_SCROLL_INSENSITIVE:該常量控制ResultSet記錄指針可以自由移動(可滾動結果集),但底層數據的改變不會受ResultSet的內容。
13      *    ResultSet.TYPE_SCROLL_SENSITIVE:該常量控制ResultSet記錄指針可以自由移動(可滾動結果集),並且底層數據的改變會影響ResultSet的內容。
14      *    ResultSet.CONCUR_READ_ONLY:該常量指示ResultSet是只讀的並發模式(默認)。
15      *    ResultSet.CONCUR_UPDATABLE: 該常量指示ResultSet是可更新的並發默認。
16      *   
17      */
18     public void testScrollAndUpdate() {
19         try {
20             // 獲取數據庫連接
21             conn = DBUtil.getMysqlConnection();
22             // 定義SQL語句
23             String sql = "SELECT stu_id,stu_name FROM student";
24             // 預編譯SQL
25             ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
26             // 執行SQL語句
27             rs = ps.executeQuery();
28             // 處理結果集
29             while (rs.next()) {
30                 System.out.println("學號:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
31             }
32         } catch (Exception e) {
33             // TODO: handle exception
34         }
35     }
36     
37     /**
38      * ResultSetMetaData:分析結果集,當不清楚該ResultSet里包含哪些數據列,以及每個數據列的數據類型,那么可以通過ResultSetMetaData來獲取關於ResultSet的描述信息。
39      *   getMetaData():獲取ResultSetMetaData對象。
40      *   int getColumnCount():返回該ResultSet的列數量。
41      *   String getColumnName(int columnIndex):返回對應列的名稱。
42      *   int getColumnType(int columnIdex):返回對應列的數據類型。
43      */
44     public void testResultSetMetaData() {
45         try {
46             // 獲取數據庫連接
47             conn = DBUtil.getMysqlConnection();
48             // 定義SQL語句
49             String sql = "SELECT stu_id,stu_name FROM student";
50             // 預編譯SQL
51             ps = conn.prepareStatement(sql);
52             // 執行SQL語句
53             rs = ps.executeQuery();
54             // 處理結果集
55             while (rs.next()) {
56                 // 獲取結果集元數據對象
57                 ResultSetMetaData rsmd = rs.getMetaData();
58                 // 獲取結果集列數
59                 int columnCount = rsmd.getColumnCount();
60                 for (int i = 0; i < columnCount; i++) {
61                     // 獲取結果集對應列名稱
62                     System.out.println(rsmd.getColumnName(i + 1));
63                     // 獲取結果集對應數據類型
64                     System.out.println(rsmd.getColumnType(i + 1));
65                 }
66             }
67         } catch (Exception e) {
68             // TODO: handle exception
69         }
70     }
71 }

 

      2. RowSet:離線

  1 public class RowSetTest {
  2     // 數據庫連接對象
  3     Connection conn = null;
  4     // 預處理對象
  5     PreparedStatement ps = null;
  6     // 結果集對象
  7     ResultSet rs = null;
  8 
  9     /**
 10      * RowSet:實現了ResultSet接口,並且有子接口CachedRowSet(離線查詢)
 11      *   概念:離線查詢:在本地搞一個結果集的副本,關閉結果集、數據庫連接,使用本地的這個副本。
 12      *   作用:RowSet默認是可滾動,可更新,可序列化的結果集,並且作為對JavaBean使用,因此能方便地在網絡上傳輸,用於同步兩端的數據。
 13      *   優點:程序在創建RowSet時已把底層數據讀取到了內存中,因此可以充分利用計算機的內存,從而減低數據庫的負載,提高程序的性能。
 14      */
 15     @Test
 16     public void testRowSetOffline() {
 17         try {
 18             // 獲取數據庫連接
 19             conn = DBUtil.getMysqlConnection();
 20             // 定義SQL語句
 21             String sql = "SELECT stu_id,stu_name FROM student";
 22             // 預編譯SQL
 23             ps = conn.prepareStatement(sql);
 24             // 執行SQL語句
 25             rs = ps.executeQuery();
 26             /**
 27              * 離線查詢
 28              */
 29             // 通過RowSetProvider的靜態方法創建RowSetFactory對象
 30             RowSetFactory rsf = RowSetProvider.newFactory();
 31             // 創建CachedRowSet對象
 32             CachedRowSet crs = rsf.createCachedRowSet(); 
 33             // 使用結果集填充CachedRowSet
 34             crs.populate(rs); //  使用給定的ResultSet裝填RowSet,從ResultSet的第startRow條記錄開始裝填。
 35             /**
 36              * 關閉數據庫資源
 37              */
 38             rs.close();
 39             ps.close();
 40             conn.close();
 41             // 離線處理結果集:CachedRowSet是ResultSet的孫接口,使用的方法都相同。
 42             while (crs.next()) {
 43                 System.out.println("學號:" + crs.getInt("stu_id") + " 姓名:" + crs.getString("stu_name"));
 44             }
 45         } catch (Exception e) {
 46             // TODO: handle exception
 47         }
 48     }
 49     
 50     /**
 51      * 分頁:不推薦使用每個數據庫特有的分頁,追求跨數據庫,代碼可用性更高
 52      *   1. 使用游標實現
 53      *   2. 使用離線查詢實現
 54      */
 55     public void pagination() {
 56         try {
 57             /**
 58              * 使用游標實現
 59              */
 60             // 獲取數據庫連接
 61             conn = DBUtil.getMysqlConnection();
 62             // 定義SQL語句
 63             String sql = "SELECT stu_id,stu_name FROM student";
 64             // 預編譯SQL
 65             ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
 66             // 執行SQL語句
 67             rs = ps.executeQuery();
 68             // 定義分頁
 69             int start = 0;  // 起始頁
 70             int pageSize = 10;  // 分頁大小
 71             // 定義游標
 72             rs.absolute(start);  // 游標指向起始位
 73             while (rs.next()) {
 74                 // ......
 75                 if (rs.getRow() == pageSize) { // getRow()是獲取當前記錄是結果集中的第幾條記錄,第一條就是1。也可以設置計數器來判斷
 76                     break;
 77                 }
 78             }
 79             
 80             /**
 81              * 使用離線查詢實現
 82              */
 83             // 創建RowSetFactory對象
 84             RowSetFactory rsf = RowSetProvider.newFactory();
 85             // 創建CachedRowSet對象
 86             CachedRowSet crs = rsf.createCachedRowSet(); 
 87             // 設置分頁大小
 88             crs.setPageSize(10);
 89             // 使用結果集填充CachedRowSet
 90             crs.populate(rs);
 91             // 釋放資源
 92             rs.close();
 93             ps.close();
 94             conn.close();
 95             while (crs.next()) {
 96                 // ......
 97             }
 98         } catch (Exception e) {
 99             // TODO: handle exception
100         }
101     }
102 }

   

    七、釋放資源

 1 public class CloseTest {
 2     // 數據庫連接對象
 3     Connection conn = null;
 4     // 預處理對象
 5     PreparedStatement ps = null;
 6     // 結果集對象
 7     ResultSet rs = null;
 8 
 9     /**
10      * 手動釋放
11      */
12     public void handMovement() {
13         try {
14             // 獲取數據庫連接
15             conn = DBUtil.getMysqlConnection();
16             // 定義SQL語句
17             String sql = "SELECT stu_id,stu_name FROM student ";
18             // 預編譯SQL
19             ps = conn.prepareStatement(sql);
20             // 執行SQL語句
21             rs = ps.executeQuery();
22             // 處理結果集
23             while (rs.next()) {
24                 System.out.println("學號:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
25             }
26         } catch (Exception e) {
27             // TODO: handle exception
28         } finally {
29             if (rs != null) {
30                 try {
31                     rs.close();
32                 } catch (SQLException e) {
33                     // TODO Auto-generated catch block
34                     e.printStackTrace();
35                 }
36             }
37             if (ps != null) {
38                 try {
39                     ps.close();
40                 } catch (SQLException e) {
41                     // TODO Auto-generated catch block
42                     e.printStackTrace();
43                 }
44             }
45             if (conn != null) {
46                 try {
47                     conn.close();
48                 } catch (SQLException e) {
49                     // TODO Auto-generated catch block
50                     e.printStackTrace();
51                 }
52             }
53         }
54     }
55 
56     /**
57      * 自動釋放
58      */
59     public void autoregula() {
60         try(
61             // 獲取數據庫連接
62             conn = DBUtil.getMysqlConnection();
63             // 定義SQL語句
64             String sql = "SELECT stu_id,stu_name FROM student ";
65             // 預編譯SQL
66             ps = conn.prepareStatement(sql);
67             // 執行SQL語句
68             rs = ps.executeQuery();
69             // 處理結果集
70             while (rs.next()) {
71                 System.out.println("學號:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
72             }    
73           ){
74         }catch (Exception e) {
75             // TODO: handle exception
76         }
77     }
78 }

 

三:封裝

    一、封裝配置文件

 1 # MySQL
 2 mysql.jdbc.driver=com.mysql.cj.jdbc.Driver
 3 mysql.jdbc.url=jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&serverTimezone=UTC
 4 mysql.jdbc.username=<user>
 5 mysql.jdbc.password=<password>
 6 # Oracle
 7 oracle.jdbc.driver=oracle.jdbc.driver.OracleDriver
 8 oracle.jdbc.url=jdbc:oracle:thin:@<host>:<port>:<database>
 9 oracle.jdbc.username=<user>
10 oracle.jdbc.password=<password>

 

    二、封裝工具類

 1 public class DBUtil {
 2     /**
 3      * MySQL和Oracle連接屬性
 4      */
 5     private static String mysqlDriver;
 6     private static String mysqlUrl;
 7     private static String mysqlUser;
 8     private static String mysqlPassword;
 9     private static String oracleDriver;
10     private static String oracleUrl;
11     private static String oracleUser;
12     private static String oraclePassword;
13 
14     /**
15      * 讀取配置文件並加載驅動
16      */
17     private static Properties pros = new Properties();
18     static {
19         try {
20             // 加載配置文件
21             pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
22             // 屬性賦值
23             mysqlDriver = pros.getProperty("mysql.jdbc.driver");
24             mysqlUrl = pros.getProperty("mysql.jdbc.url");
25             mysqlUser = pros.getProperty("mysql.jdbc.username");
26             mysqlPassword = pros.getProperty("mysql.jdbc.password");
27             oracleDriver = pros.getProperty("oracle.jdbc.driver");
28             oracleUrl = pros.getProperty("oracle.jdbc.url");
29             oracleUser = pros.getProperty("oracle.jdbc.username");
30             oraclePassword = pros.getProperty("oracle.jdbc.password");
31             // 注冊驅動
32             try {
33                 Class.forName(mysqlDriver);
34             } catch (ClassNotFoundException e) {
35                 // TODO Auto-generated catch block
36                 e.printStackTrace();
37             }
38         } catch (IOException e) {
39             // TODO Auto-generated catch block
40             e.printStackTrace();
41         }
42     }
43 
44     /**
45      * 數據庫連接
46      */
47     public static Connection getConnection(String dbManufacturer) {
48         Connection conn = null;
49         if (conn == null) {
50             try {
51                 if (dbManufacturer.startsWith("mysql")) {
52                     conn = DriverManager.getConnection(mysqlUrl, mysqlUser, mysqlPassword);
53                 } else {
54                     conn = DriverManager.getConnection(oracleUrl, oracleUser, oraclePassword);
55                 }
56             } catch (Exception e) {
57                 System.err.println("數據庫連接出錯,請檢查");
58             }
59         }
60         return conn;
61     }
62 
63     /**
64      * 釋放資源
65      */
66     public static void release(Connection conn, PreparedStatement ps, ResultSet rs) {
67         if (rs != null) {
68             try {
69                 rs.close();
70             } catch (SQLException e) {
71                 e.printStackTrace();
72             }
73         }
74         if (ps != null) {
75             try {
76                 ps.close();
77             } catch (SQLException e) {
78                 e.printStackTrace();
79             }
80         }
81         if (conn != null) {
82             try {
83                 conn.close();
84             } catch (SQLException e) {
85                 e.printStackTrace();
86             }
87         }
88     }
89 }

 

    三、封裝查詢和更新

  1 public class BaseDao<T> {
  2     /**
  3      * 封裝增、刪、改功能
  4      * 
  5      * @param sql  需要執行的sql語句
  6      * @param args 不定參數,是對sql語句中的占位符“?”傳入的參數
  7      * @return 返回操作所影響的行數
  8      */
  9     public int executeUpdate(String sql, Object... args) {
 10         Connection conn = null;
 11         PreparedStatement ps = null;
 12         int rows = 0;
 13         try {
 14             conn = DBUtil.getConnection("mysql");
 15             ps = conn.prepareStatement(sql);
 16             for (int i = 0; i < args.length; i++) {
 17                 ps.setObject(i + 1, args[i]);
 18             }
 19             rows = ps.executeUpdate();
 20         } catch (SQLException e) {
 21             e.printStackTrace();
 22         } finally {
 23             DBUtil.release(conn, ps, null);
 24         }
 25         return rows;
 26     }
 27 
 28     /**
 29      * 查詢一條記錄
 30      * 
 31      * @param sql  需要執行的sql語句
 32      * @param cls  實體類對象類型,例如Student.class,如果類未知,則使用 Class<?>
 33      * @param args 不定參數,是對sql語句中的占位符“?”傳入的參數
 34      * @return 返回操作所影響的行數
 35      */
 36     public T selectOne(String sql, Class<T> cls, Object... args) {
 37         List<T> list = this.selectMany(sql, cls, args);
 38         return list.isEmpty() ? null : list.get(0);
 39     }
 40 
 41     /**
 42      * 查詢所有記錄
 43      * 
 44      * @param sql  需要執行的sql語句
 45      * @param cls  實體類對象類型,例如Student.class,如果類未知,則使用 Class<?>
 46      * @param args 不定參數,是對sql語句中的占位符“?”傳入的參數
 47      * @return 返回結果集
 48      */
 49     public List<T> selectMany(String sql, Class<T> cls, Object... args) {
 50         Connection conn = null;
 51         PreparedStatement ps = null;
 52         ResultSet rs = null;
 53         List<T> list = new ArrayList<T>();
 54         try {
 55             conn = DBUtil.getConnection("mysql");
 56             ps = conn.prepareStatement(sql);
 57             for (int i = 0; i < args.length; i++) {
 58                 ps.setObject(i + 1, args[i]);
 59                 rs = ps.executeQuery();
 60                 // 分析結果集對象
 61                 ResultSetMetaData metaData = rs.getMetaData();
 62                 while (rs.next()) {
 63                     T obj = cls.getDeclaredConstructor().newInstance();
 64                     // 獲取結果集列數
 65                     for (int j = 1; j <= metaData.getColumnCount(); j++) {
 66                         // 獲取結果集列名
 67                         String columnLabel = metaData.getColumnLabel(j);
 68                         // 動態拼接成該屬性對應實體中的setter方法的方法名
 69                         String name = "set" + StringUtil.toUpper(columnLabel);
 70                         // 獲取實體中所有聲明的屬性
 71                         Field field = cls.getDeclaredField(columnLabel);
 72                         // 獲取實體中所有聲明的方法,形參為field.getType()類型
 73                         Method method = cls.getDeclaredMethod(name, field.getType());
 74                         // 通過結果集獲取字段值名
 75                         Object realParam = rs.getObject(columnLabel);
 76                         // 執行obj對象中的method方法,傳入的實參為realParam
 77                         method.invoke(obj, realParam);
 78                     }
 79                     list.add(obj);
 80                 }
 81             }
 82         } catch (SQLException | InstantiationException | IllegalAccessException e) {
 83             e.printStackTrace();
 84         } catch (NoSuchMethodException e) {
 85             e.printStackTrace();
 86         } catch (SecurityException e) {
 87             e.printStackTrace();
 88         } catch (IllegalArgumentException e) {
 89             e.printStackTrace();
 90         } catch (InvocationTargetException e) {
 91             e.printStackTrace();
 92         } catch (NoSuchFieldException e) {
 93             e.printStackTrace();
 94         } finally {
 95             DBUtil.release(conn, ps, rs);
 96         }
 97         return list;
 98     }
 99 
100     /**
101      * 查詢總記錄數
102      * 
103      * @param sql  需要執行的sql語句
104      * @param args 需要對sql語句中的占位符“?”傳入的參數數組
105      * @return 返回操作所影響的行數
106      */
107     public int selectCount(String sql, Object... args) {
108         Connection conn = null;
109         PreparedStatement ps = null;
110         ResultSet rs = null;
111         int count = 0;
112         try {
113             conn = DBUtil.getConnection("mysql");
114             ps = conn.prepareStatement(sql);
115             for (int i = 0; i < args.length; i++) {
116                 ps.setObject(i + 1, args[i]);
117                 rs = ps.executeQuery();
118                 if (rs.next()) {
119                     count = rs.getInt(1);
120                 }
121             }
122         } catch (SecurityException e) {
123             e.printStackTrace();
124         } catch (IllegalArgumentException e) {
125             e.printStackTrace();
126         } catch (SQLException e) {
127             e.printStackTrace();
128         } finally {
129             DBUtil.release(conn, ps, rs);
130         }
131         return count;
132     }
133 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM