JDBC使用詳解
一、概述
1、什麼是JDBC
JDBC(Java Database Connectivity)是一個獨立於特定資料庫管理系統(DBMS)、通用的SQL資料庫存取和操作的公共介面(一組API),定義了用來訪問資料庫的標準Java類庫,使用這個類庫可以以一種標準的方法、方便地訪問資料庫資源JDBC為訪問不同的資料庫提供了一種統一的途徑,為開發者遮蔽了一些細節問題。JDBC的目標是使Java程式設計師使用JDBC可以連線任何提供了JDBC驅動程式的資料庫系統,這樣就使得程式設計師無需對特定的資料庫系統的特點有過多的瞭解,從而大大簡化和加快了開發過程。
2、JDBC API
JDBC API是一系列的介面,它統一和規範了應用程式與資料庫的連線、執行SQL語句,併到得到返回結果等各類操作。宣告在java.sql與javax.sql包中
3、環境準備:引入JDBC驅動程式
1)驅動程式由資料庫提供商提供下載。 MySQL的驅動下載地址:http://dev.mysql.com/downloads/
2)在Java Project專案應用中新增資料庫驅動jar:把jar拷貝到專案中目錄中lib
3)新增到專案的類路徑下在驅動jar上右鍵-->Build Path-->Add to Build Path
二、JDBC詳細步驟
1、載入並註冊驅動:
1)載入驅動,把驅動類載入到記憶體
註冊驅動,把驅動類的物件交給DriverManager管理,用於後面建立連線等使用。
2)呼叫Class類的靜態方法forName(),向其傳遞要載入的JDBC驅動的類名
//通過反射,載入與註冊驅動類,解耦合(不直接依賴)
Class.forName("com.mysql.jdbc.Driver");
2、獲取資料庫連線:DriverManager.getConnection()
1) 可以通過 DriverManager 類建立到資料庫的連線Connection,DriverManager試圖從已註冊的JDBC驅動程式集中選擇一個適當的驅動程式。
public static Connection getConnection(String url)
public static Connection getConnection(String url,String user, String password)
public static Connection getConnection(String url,Properties info)其中Properties info通常至少應該包括 "user" 和 "password" 屬性
2)JDBC URL用於標識一個被註冊的驅動程式,驅動程式管理器通過這個URL選擇正確的驅動程式,從而建立到資料庫的連線。JDBC URL的標準由三部分組成,各部分間用冒號分隔。
jdbc:<子協議>:<子名稱>
① 協議:JDBC URL中的協議總是jdbc
② 子協議:子協議用於標識一個數據庫驅動程式
③ 子名稱:一種標識資料庫的方法。子名稱可以依不同的子協議而變化,用子名稱的目的是為了定位資料庫提供足夠的資訊
3)常用資料庫URL地址的寫法:
Oracle:jdbc:oracle:thin:@localhost:1521:庫名
SqlServer:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=庫名
MySql:jdbc:mysql://localhost:3306/庫名
4)Connection()物件的常用方法:
方法 | 描述 |
createStatement() | 建立向資料庫傳送sql的statement物件 |
prepareStatement(sql) | 建立向資料庫傳送預編譯sql的PrepareSatement物件 |
prepareCall(sql) | 建立執行儲存過程的callableStatement物件 |
setAutoCommit(boolean autoCommit) | 設定事務是否自動提交 |
commit() | 在連線上提交事務 |
rollback() | 在此連線上回滾事務 |
3、執行增刪改查:
1)PreparedStatement vs Statement
① 程式碼的可讀性和可維護性. Statement的sql拼接是個難題。
② PreparedStatement 可以防止SQL注入
③ PreparedStatement 可以處理Blob型別的資料
④ PreparedStatement 能最大可能提高效能:(Oracle和PostgreSQL8是這樣,但是對於MySQL不一定比Statement高)
2)PreparedStatement概述:可以通過呼叫Connection物件的preparedStatement(String sql)方法獲取PreparedStatement物件
① PreparedStatement介面是Statement的子介面,它表示一條預編譯過的SQL語句
② PreparedStatement物件所代表的SQL語句中的引數用問號(?)來表示,呼叫PreparedStatement物件的setXX()方法來設定這些引數. setXX()方法有兩個引數,第一個引數是要設定的SQL語句中的引數的索引(從 1 開始),第
二個SQL語句中的引數的值。若不清楚資料的型別,則直接使用setObject()方法
setXX(佔位符索引,佔位符的值):設定對應索引的佔位符的值,型別為XX型別
setObject(佔位符索引,佔位符的值):設定對應索引的佔位符的值,型別為Object型別
1 @Test 2 public void add() throws Exception { 3 Scanner input = new Scanner(System.in); 4 System.out.println("請輸入使用者名稱:"); 5 String name = input.nextLine(); 6 7 System.out.println("請輸入密碼:"); 8 String gender = input.nextLine(); 9 10 //1、載入並註冊驅動 11 Class.forName("com.mysql.jdbc.Driver"); 12 13 //2、建立資料庫連線 14 String url = "jdbc:mysql://localhost:3306/girls"; 15 String user = "root"; 16 String password = ""; 17 Connection conn = DriverManager.getConnection(url, user, password); 18 19 //3、編寫帶?的SQL 20 String sql = "INSERT INTO admin VALUES(null,?,?)"; 21 22 //4、例項化PreparedStatement,對帶?的sql進行預編譯 23 PreparedStatement Statement = conn.prepareStatement(sql); 24 25 //5、把?用具體的值進行代替 26 Statement.setString(1, name); 27 Statement.setObject(2, gender); 28 29 //6、執行sql 30 int len = Statement.executeUpdate(); 31 System.out.println(len>0?"新增成功":"新增失敗"); 32 33 //7、釋放資源 34 Statement.close(); 35 conn.close(); 36 input.close(); 37 }View Code
③Statement物件常用方法:
方法 | 含義 |
executeQuery(String sql) | 用於向資料傳送查詢語句 |
executeUpdate(String sql) | 用於向資料庫傳送insert、update或delete語句 |
execute(String sql) | 用於向資料庫傳送任意sql語句 |
addBatch(String sql) | 把多條sql語句放到一個批處理中 |
executeBatch() | 向資料庫傳送一批sql語句執行 |
④ int executeUpdate():執行更新,包括增、刪、改,返回受影響的行數
⑤ ResultSet executeQuery():執行查詢,並返回該查詢生成的ResultSet物件。
ResultSet物件以邏輯表格的形式封裝了執行資料庫操作的結果集,ResultSet介面由資料庫廠商實現;ResultSet 物件維護了一個指向當前資料行的遊標,初始的時候,遊標在第一行之前,呼叫ResultSet.next()方法,可以使
遊標指向具體的資料行,進行呼叫方法獲取該行的資料。
A、獲取行:ResultSet提供了對結果集進行滾動的方法:
next():移動到下一行
Previous():移動到前一行
absolute(int row):移動到指定行
beforeFirst():移動resultSet的最前面。
afterLast() :移動到resultSet的最後面。
B、獲取值:ResultSet既然用於封裝執行結果的,所以該物件提供的都是用於獲取資料的get方法:
獲取任意型別的資料:
getObject(int index):通過索引
getObject(string columnName):通過列名,若sql語句中使用了AS關鍵字重新命名列名,則使用重新命名後的列名
獲取指定型別的資料,如獲取字串型別的資料:
getString(int index)
getString(String columnName)
1 @Test 2 public void select() throws Exception { 3 4 Scanner input = new Scanner(System.in); 5 System.out.println("請輸入姓名:"); 6 String name = input.nextLine(); 7 8 //1、載入並註冊驅動 9 Class.forName("com.mysql.jdbc.Driver"); 10 11 //2、建立資料庫連線 12 String url = "jdbc:mysql://localhost:3306/girls"; 13 String user = "root"; 14 String password = ""; 15 Connection conn = DriverManager.getConnection(url, user, password); 16 17 //3、編寫帶?的sql 18 String sql = "SELECT id,username,password FROM admin WHERE username = ?"; 19 20 //4、把帶?的sql語句進行預編譯 21 PreparedStatement statement = conn.prepareStatement(sql); 22 23 //5、把?用具體的變數的賦值 24 statement.setString(1, name); 25 26 //6、執行查詢sql 27 ResultSet set = statement.executeQuery(); 28 while (set.next()) { 29 30 int id = set.getInt("id"); 31 String username = set.getString("username"); 32 Object pwd = set.getObject("password"); 33 34 System.out.println(id + "\t" + username + "\t" + pwd); 35 } 36 37 // 6、釋放資源 38 set.close(); 39 statement.close(); 40 conn.close(); 41 input.close(); 42 }View Code
4、釋放資源:ResultSet.close()、statement.close()、connection.close()
JDBC程式執行完後,切記要釋放程式在執行過程中,建立的那些與資料庫進行互動的物件,這些物件通常是ResultSet, Statement和Connection物件。
注意:為確保資源釋放程式碼能執行,資源釋放程式碼也一定要放在finally語句中。
三、封裝JDBCUtils
1、封裝類
1 public class JDBCUtils { 2 3 static String user; 4 static String password; 5 static String url; 6 static String driver; 7 8 //程式碼塊 9 static{ 10 try { 11 //讀取配置檔案 12 Properties info = new Properties(); 13 info.load(new FileInputStream("src\\jdbc.properties")); 14 user = info.getProperty("user"); 15 password = info.getProperty("password"); 16 url = info.getProperty("url"); 17 driver = info.getProperty("driver"); 18 //1.註冊驅動 19 Class.forName(driver); 20 } catch (Exception e) { 21 //將編譯異常轉換為執行異常 22 throw new RuntimeException(e); 23 } 24 } 25 /** 26 * 功能:獲取可用的連線物件 27 * @return 連線 28 * @throws Exception 29 */ 30 public static Connection getConnection(){ 31 32 try { 33 return DriverManager.getConnection(url, user, password); 34 } catch (Exception e) { 35 throw new RuntimeException(e); 36 } 37 } 38 /** 39 * 功能:釋放資源 40 * @param set 41 * @param statement 42 * @param connection 43 * @throws Exception 44 */ 45 public static void close(ResultSet set,Statement statement,Connection connection){ 46 try { 47 if (set!=null) { 48 set.close(); 49 } 50 if (statement!=null) { 51 statement.close(); 52 } 53 if (connection!=null) { 54 connection.close(); 55 } 56 } catch (SQLException e) { 57 throw new RuntimeException(e); 58 } 59 } 60 }View Code
2、示例
1 public class TestPreparedStatementByUtils { 2 3 @Test 4 public void testUpdate() { 5 6 Scanner input = new Scanner(System.in); 7 8 System.out.println("請輸入待修改的編號:"); 9 int id = input.nextInt(); 10 11 System.out.println("請輸入新使用者名稱:"); 12 String name = input.next(); 13 14 //----------------------連線資料庫的步驟---------------- 15 Connection connection = null; 16 PreparedStatement statement = null; 17 try { 18 //1.獲取連線 19 connection = JDBCUtils.getConnection(); 20 21 //2.執行修改 22 String sql = "update admin set username=? where id=?"; 23 statement = connection.prepareStatement(sql); 24 statement.setString(1, name); 25 statement.setInt(2, id); 26 int update = statement.executeUpdate(); 27 System.out.println(update>0?"修改成功!":"修改失敗!"); 28 } catch (SQLException e) { 29 e.printStackTrace(); 30 31 }finally{ 32 33 //3.關閉連線 34 JDBCUtils.close(null, statement, connection); 35 } 36 } 37 38 }View Code
四、事務
1、JDBC程式中當一個連線物件被建立時,預設情況下是自動提交事務:每次執行一個SQL語句時,如果執行成功,就會向資料庫自動提交,而不能回滾。
2、JDBC程式中為了讓多個SQL語句作為一個事務執行:(重點)
1)呼叫Connection物件的setAutoCommit(false); 以取消自動提交事務
2)在所有的SQL語句都成功執行後,呼叫commit(); 方法提交事務
3)在其中某個操作失敗或出現異常時,呼叫rollback(); 方法回滾事務
4)若此時Connection沒有被關閉, 則需要恢復其自動提交狀態setAutoCommit(true);
注意:要求開啟事務的連線物件和獲取命令的連線物件必須是同一個!否則事務無效。如果多個操作,每個操作使用的是自己單獨的連線,則無法保證事務。即同一個事務的多個操作必須在同一個連線下
3、使用步驟:
1)開啟新事務
取消隱式事務自動提交的功能:setAutoCommit(false);
2)編寫組成事務的一組sql語句
3)結束事務
commit();提交
rollback();回滾
4、例項
1 @Test 2 public void testTransaction(){ 3 4 Connection connection = null; 5 PreparedStatement statement = null; 6 7 try { 8 //1.獲取連線 9 connection = JDBCUtils.getConnection(); 10 11 //①事務的使用步驟1:開啟事務 12 connection.setAutoCommit(false); 13 14 //②事務的使用步驟2:編寫sql語句,並且執行 15 statement = connection.prepareStatement("update admin set password = ? where id=?"); 16 17 //操作1:張三丰的錢-5000 18 statement.setInt(2, 1); 19 statement.setString(1, "888"); 20 statement.executeUpdate(); 21 22 //模擬異常 23 int i = 1/0; 24 25 //操作2:張三丰的錢-5000 26 statement.setInt(2, 50053); 27 statement.setString(1, "111"); 28 statement.executeUpdate(); 29 30 //③事務的使用步驟3:結束事務 31 connection.commit(); 32 33 } catch (SQLException e) { 34 try { 35 //回滾事務 36 connection.rollback(); 37 } catch (SQLException e1) { 38 e1.printStackTrace(); 39 } 40 }finally{ 41 42 JDBCUtils.close(null, statement, connection); 43 } 44 45 }View Code
五、批處理
1、需要成批插入或者更新記錄時。可以採用Java的批量更新機制,這一機制允許多條語句一次性提交給資料庫批量處理。通常情況下比單獨提交處理更有效率。
2、JDBC的批量處理語句包括下面兩個方法:
addBatch():新增需要批量處理的SQL語句或引數
executeBatch():執行批量處理語句;
clearBatch():清空批處理包的語句
4、注意:
1)JDBC連線MySQL時,如果要使用批處理功能,請再url中加引數?rewriteBatchedStatements=true。url=jdbc:mysql://localhost:3306/girls?rewriteBatchedStatements=true
2)PreparedStatement作批處理插入時使用values(使用value沒有效果)
3)批處理往往和PreparedStatement一起搭配使用,可以既減少編譯次數,又減少執行次數,效率大大提高
1 //沒有使用批處理:耗時長 2 @Test 3 public void testNoBatch() throws SQLException{ 4 5 //1.獲取連線 6 Connection connection = JDBCUtils.getConnection(); 7 8 //2.執行批量插入 9 PreparedStatement statement = connection.prepareStatement("insert into admin values(null,?,?)"); 10 11 for(int i=1;i<=50000;i++){ 12 statement.setString(1,"john"+i); 13 statement.setString(2, "0000"); 14 statement.executeUpdate();//執行 15 } 16 //3.釋放資源 17 JDBCUtils.close(null, statement, connection); 18 } 19 20 //使用批處理 21 @Test 22 public void testBatch() throws SQLException{ 23 24 //1.獲取連線 25 Connection connection = JDBCUtils.getConnection(); 26 27 //2.執行批量插入 28 PreparedStatement statement = connection.prepareStatement("insert into admin values(null,?,?)"); 29 30 for(int i=1;i<=50000;i++){ 31 statement.setString(1,"john"+i); 32 statement.setString(2, "0000"); 33 34 statement.addBatch();//新增sql語句到批處理包中 35 if(i%1000==0){ 36 statement.executeBatch();//執行批處理包中的sql語句 37 statement.clearBatch();//清空批處理包中的sql語句 38 } 39 } 40 41 //3.釋放資源 42 JDBCUtils.close(null, statement, connection); 43 }View Code