一: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 }