JDBC數據庫的連接
-
概述
- JDBC(Java DataBase Connectivity,java數據庫連接)是一種用於執行SQL語句的Java API
-
核心組件
-
DriverManager–此類管理數據庫驅動程序列表
- 這一類可以不寫或使用映射方式Class.forName()
- 使用通信子協議將來自java應用程序的連接請求與適當的數據庫驅動程序匹配。
-
Driver --此接口處理與數據庫服務器的通信
-
Connection --用於聯繫數據庫的所有方法
-
Statement – 使用從此接口創建的對象將SQL語句提交到數據庫
- 增,刪,改 executeUpdate==>int
- 查 executeQuery()==>result
- execute==>true-Result(查詢的結果)/false- int (增刪改)
String sql="select * from tb_name where name='"+uname+"'" " Statement stmt=conn.createConnection(sql); ResultSet=stmt.executeQuery(); /* * 有SQL注入問題 ---- ' or '3'='3; ' or '1'='1 * 預防SQL注入問題--PreparedStatement */
-
PreparedStatement
-
Statement 的升級版
-
String sql="select * from tb_name where name = ?"; PreparedStatement ptmt= conn.preparedStatement(sql); ptmt.setString(1,name);//和Result查詢第一列一致,默認第一個爲1 ResultSet=ptmt.executeQuery();
-
-
ResultSet–查詢結果集
-
在使用Statement對象執行SQL查詢後,這些對象保存從數據庫檢索的數據。它作爲一個迭代器,允許我們移動其數據。
-
表示數據庫結果集的數據表,通常通過執行查詢數據庫的語句生成。
-
ResultSet
對象具有指向其當前數據行的光標。最初,光標被置於第一行之前。 -
next
方法將光標移動到下一行;因爲該方法在ResultSet
對象沒有下一行時返回false
-
所以可以在 while循環中使用它來迭代結果集。
-
默認的
ResultSet
對象不可更新,僅有一個向前移動的光標。因此,只能迭代它一次,並且只能按從第一行到最後一行的順序進行
-
-
SQLException --此類處理數據庫應用程序中發生的任何錯誤
-
-
數據庫連接標程
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo01{
public static void main(String[] args) throws SQLException,ClassNotFindException {
//1、獲取驅動
Class.forName("com.mysql.jdbc.Driver");
//2 創建連接
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/api_db?user=root&password=123456");
//3獲取執行sql語句對象
Statement stmt=conn.createStatement();
//4編寫SQL語句
String sql="select * from a_doc";
//5運行SQL語句並返回結果集
ResultSet result=stmt.executeQuery(sql);
//6解析結果
//while(result.next()){
System.out.println(result);
//}
//7關閉
result.close();
stmt.close();
conn.close();
}
}
補充
- 步驟2 -多種寫法
Thread.currentThread().getContextClassLoader().getResourceAsStream("");
properties.load(new FileInputStream("db.properties"));
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/table?user=root&password=root");
DriverManager.getConnection("jdbc:mysql://localhost:3306/java1908", "root", "root");
----------------------------------------
//第三種 --直接賦值
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password", "root");
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/java1908?useSSL=false", info);
-------------------------------------------
//第四種-- 調用文件
Properties propertieds = new Properties();
propertieds.load(new FileInputStream("db.properties"));
/*如上述語句失效,
FileInputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
properties.load(in);
*/
String user = propertieds.getProperty("user");
String url = propertieds.getProperty("url");
String password = propertieds.getProperty("password");
Connection conn = DriverManager.getConnection(url, user,password);
事務
- 定義
- 事務(Transaction),一般是指要做的或所做的事情。在計算機[術語]中是指訪問並可能更新數據庫中各種[數據項]的一個程序執行單元(unit)
- 對數據庫而已,一個SQL語句就是一個事務
- 意義
- 保證數據的完整性和一致性
事務的四大特性–(原子,一致,持久,隔離)
- 1、原子性
- 事務是一個最小的操作單元,不可再被分割,即事務中的sql語句要麼同時生效,要麼同時不生效。
- 2、一致性
- 事務中的數據在事務提交之前,或者回滾以後,是一致的。
- 3、持久性
- 事務一旦提交,對數據的影響是持久的(寫入到磁盤中)。
- 4、隔離性
- 一個事務,在併發訪問的情況下,不同隔離級別會出現不同效果。
事務的隔離級別***
-
一個事務,在併發訪問的情況下,不同隔離級別會出現不同效果。
-
併發: 在同一時刻,有多個客戶在操作同一張表。同一時刻發生(前提條件)
- 並行:在一定的時間段內運行
-
1.read uncommitted
- 一個事務中讀到了另一個事務並未提交的結果。
- A 轉賬但未提交,B取讀到A提交後的結果,但數據可能有誤(A中途回滾,結果也會改變)
- 這種隔離級別就會導致: 髒讀、不可重複讀、虛讀(幻讀)。
-
2.read committed——oracle的默認隔離級別–
- 一個事務中能讀到另一個事務已經提交的結果,但是不能讀到另一個事務沒有提交的結果。
- A給B轉賬,只有A提交後B才能讀到更新的數據,否則不論A如何操作,查詢的結果都是原始數據
-
這種隔離級別解決了髒讀問題。但出現了不可重複讀和幻讀的問題,
- 所謂不可重複讀,就是不能重複讀,一重複讀數據就不一樣。
- 所謂的幻讀,在一個事務中,兩次讀到的數據的條數不相同。
- 髒讀:讀取未提交數據
- 不可重複讀:前後多次讀取,數據內容不一致
- 幻讀:前後多次讀取,數據總量不一致
3.repeatable read——mysql的默認隔離級別
- 一個事務中可以重複的讀,每次讀到的數據都是一樣的
- 在並行的過程中,只要一開啓事務,只要事務不結束,讀取的值始終是一致的
- 無論其他事務對數據進行怎樣的操作(添加數據、修改數據、提交事務)。當前事務每次讀到的數據內容都不會有變化。
- 這種隔離級別解決了: 髒讀、不可重複讀、幻讀。
-
4.serializable 串行化–排隊執行
- 最嚴苛的隔離級別。將並行變成串行。效率非常低,沒有使用場景。
-
注:
- repeatable read 和read committed隔離本質一樣
- 讀到的數據=事務沒有開始之前的數據,當事務提交話,讀到的數據=遞交後的數據
-
查看和設置隔離級別
- 查看當前數據庫事務隔離級別
- select @@tx_isolation;
- 設置隔離級別
- set session transaction isolation level read uncommitted;
- set session transaction isolation level read committed;
- set session transaction isolation level repeatable read;
- set session transaction isolation level serializable;
- 查看當前數據庫事務隔離級別
使用方式
- 1、設置隔離級別
- 2、開啓事務
- 3、提交事務
事務的開啓
- 數據庫中
- start transaction
- java 中
- conn.setAutoCommit(false)
事務的結束
- 提交 :commit();//conn.commit();
- 回滾:rollback();//conn.rollback();
補充-擴展_設置事務的回滾點
-
設置事務的回滾點
- Savepoint point = conn.setSavepoint();
-
回滾到具體位置
- conn.rollback(point);
package com.qianfeng.demos;
import java.io.IOException;
import java.sql.Connection;
import java.sql.Savepoint;
import java.sql.Statement;
import com.qianfeng.utils.JDBCUtil;
public class Demo14 {
public static void main(String[] args) throws IOException, Exception {
// 獲取連接對象
Connection conn = JDBCUtil.getConnection();
// 創建statment對象
String sql01 = "update account set money=money-1000 where name='zhangsan'";
String sql02 = "update account set money=money+1000 where name='lisi'";
// PreparedStatement pstmt01 = conn.prepareStatement(sql01);
// PreparedStatement pstmt02 = conn.prepareStatement(sql02);
Statement stmt = conn.createStatement();
conn.setAutoCommit(false);
Savepoint point = null;
try {
int ret01 = stmt.executeUpdate(sql01);
System.out.println("張三轉出成功....");
point = conn.setSavepoint();
System.out.println("已經保存當前狀態...");
int i = 10/0;
int ret02 = stmt.executeUpdate(sql02);
System.out.println("李四接收成功");
// 如果代碼能執行到這兒,說明沒有問題,可以提交
conn.commit();
}catch (Exception e) {
// 如果代碼執行到這裏,說明遇到了異常,回滾到zhangsan轉出的狀態
conn.rollback(point);
System.err.println("已經回滾到張三轉出的狀態,繼續向lisi轉賬... ...");
int ret02 = stmt.executeUpdate(sql02);
conn.commit();
System.out.println("再次嘗試向李四轉賬成功... ");
}
JDBCUtil.releaseSource(stmt, conn);
}
}