目錄
1.JDBC是什么?
2.JDBC的本質是什么?
3.開發前的準備作業
1.普通的Java專案添加jar包
2.創建Maven專案添加依賴
4.JDBC編程六步(背會熟記)
5. 具體實作
1.注冊驅動
2.獲取連接
3.獲取資料庫操作物件
4.執行sql,關閉連接
6. JDBC執行洗掉與更新
1.洗掉操作
2.更新操作
7.類加載的方式注冊驅動
8.從屬性資源檔案中讀取連接資料庫資訊
9.處理查詢結果集
10.PreparedStatement的使用
1.JDBC是什么?
Java資料庫連接,(Java Database Connectivity,簡稱JDBC)是Java中用來規范客戶端程式如何來訪問資料庫的應用程式介面,提供了諸如查詢和更新資料庫中資料的方法,JDBC也是Sun Microsystems的商標,我們通常說的JDBC是面向關系型資料庫的
2.JDBC的本質是什么?
JDBC是sun公司置頂的一套介面(interface)
而這些介面都存在于java.sql.*包下

我們知道介面都有呼叫者和實作者,在JDBC中,很明顯呼叫者是我們普通的Java程式員,那么誰是這些介面的實作者呢?
沒錯,就是各大資料庫廠商,對于每一個資料庫廠商,例如mysql,oracle,SqlServer等,都必須實作sun公司制定的這套介面,而我們程式員只需要根據自己使用的資料庫,呼叫資料庫廠商實作的介面方法即可,
思考:為什么sun公司制定一套JDBC介面呢?
因為每一個資料庫的底層實作原理不一樣
Oracle資料庫有自己的原理
Mysql資料庫也有自己的原理
SqlServer資料庫也有自己的原理
...
每一個資料庫產品都有自己獨特的實作原理
原理圖如下:

思考:為什么要面向介面編程?
面向介面呼叫、面向介面寫實作類,這都屬于面向介面編程
作用:
解耦合:降低程式的耦合度,提高程式的擴展力
多型機制就是非常典型的:面向抽象編程
//建議:
Animal a = new Cat();
Animal a = new Dog();
//不建議:
Dog d = new Dog();
Cat c = new Cat();
3.開發前的準備作業
JDBC開發前的準備作業,先從官網下載對應的驅動jar包
官網下載jar包的地址
MySQL :: Download Connector/J
這里我們開發分為兩種情況
- 普通Java專案
- Maven專案
如果我們創建的是普通的java專案,我們需要將jar包配置到專案中
而如果我們創建的是maven專案,直接在pom.xml檔案中添加依賴即可
1.普通的Java專案添加jar包
上面我們下載下來的jar包檔案,只需要用到下面這個標紅的這個

然后我們在Intellij idea中創建一個普通的java專案JDBCTest
下面是匯入jar包的程序:
第一步,創建一個lib檔案,將jar包復制進去:

第二步,右鍵點擊該jar包,選擇 Add as Library...

第三步,選擇Jar Directory

第四步,選擇要將jar包匯入哪個module,我們選擇剛剛創建的JDBCTest

第五步,確定是否成功匯入,打開Project Structure...(快捷鍵Ctrl + Alt + Shift + S)

第六步,點擊Libraries,發現已經成功匯入了

2.創建Maven專案添加依賴
如果創建的是Maven專案,我們直接在pom.xml檔案中添加依賴
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
</dependencies>
對于初學Java的人可能沒有學過Maven,但我推薦沒有學過Maven的人一定要去把Maven學了,Maven不難,但是對我們專案的幫助卻特別大
4.JDBC編程六步(背會熟記)
- 第一步:注冊驅動(告訴Java程式,即將連接的是哪個品牌的資料庫)
- 第二步:獲取連接(表示JVM的行程和資料庫行程之間的通道打開了,這屬于行程之間的通信,重量級的,使用完之后一定要關閉通道)
- 第三步:獲取資料庫操作物件(專門執行sql陳述句的物件)
- 第四步:執行sql陳述句(DQL DML...)
- 第五步:處理查詢結果集(只有當第四步執行的select陳述句的時候,才由第五步處理查詢結果集)
- 第六步:釋放資源(使用完資源之后一定要關閉資源,Java和資料庫屬于行程間的通信,開啟之后一定要關閉)
5. 具體實作
1.注冊驅動
我們首先查看jdk幫助檔案,發現有兩個方法可以注冊驅動

我們查看方法具體的解釋,發現這個方法會拋出一個SQLException的例外 ,我們可以用try..catch來捕獲例外,

其實我們撰寫JDBC注冊驅動最常用的方法不是registerDriver()方法,最常用的方法是通過反射的類加載程序來注冊驅動,這個后面我們會再詳細講解,我們這里首先采用registerDriver的方法來注冊驅動
撰寫代碼:
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCTest01 {
public static void main(String[] args) throws SQLException {
try {
//1.注冊驅動
Driver driver = new com.mysql.cj.jdbc.Driver();//父型別參考指向子型別物件
DriverManager.registerDriver(driver);
} catch (SQLException e) {
e.printStackTrace();
}
//2.獲取連接
//3.獲取資料庫操作物件
//4.執行sql
//5.處理查詢結果
//6.關閉連接
}
}
可以看到這里是 new com.mysql.cj.jdbc.Driver(),那么com.mysql.cj.jdbc.Driver()和com.mysql.jdbc.Driver()有什么區別呢?
簡單來說,如果使用的是Mysql6.0之后的版本,必須使用com.mysql.cj.jdbc.Driver(),而如果使用的是Mysql5.0的版本,使用的就是com.mysql.jdbc.Driver()
2.獲取連接
我們查看jdk幫助檔案,其中有三個方法可以獲取連接

我們最常用的是第三個,查看第三個的詳細解釋
可以看到是回傳的是一個Connection物件,這個就是獲取到的連接物件,里面需要傳三個引數,分別為url,user,password
- url就是資料庫連接地址
- user就是資料庫賬號
- password就是資料庫密碼
我們來解釋一下url
url:統一資源定位符(網路中某個資源的絕對路徑)
url包括哪幾個部分?
- 協議
- IP
- PORT
- 資源名
舉例:
http://220.181.38.251:80/index.html
http:// 通信協議
220.181.38.251 服務器IP地址
80 服務器上軟體的埠
index.html 服務器上某個資源名
jdbc:mysql://127.0.0.1:3306/demodatabase2
jdbc:mysql:// 協議
127.0.0.1 IP地址
3306 mysql資料庫的埠號
demodatabase2 具體的資料庫實體名
說明:localhost和127.0.0.1都是本機IP地址
撰寫程式:
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCTest01 {
public static void main(String[] args) throws SQLException {
try {
//1.注冊驅動
Driver driver = new com.mysql.cj.jdbc.Driver();//父型別參考指向子型別物件
DriverManager.registerDriver(driver);
//2.獲取連接
/*
url:統一資源定位符(網路中某個資源的絕對路徑)
URL包括哪幾個部分?
協議
IP
PORT
資源名
http://220.181.38.251:80/index.html
http:// 通信協議
220.181.38.251 服務器IP地址
80 服務器上軟體的埠
index.html 服務器上某個資源名
jdbc:mysql://127.0.0.1:3306/demodatabase2
jdbc:mysql:// 協議
127.0.0.1 IP地址
3306 mysql資料庫的埠號
demodatabase2 具體的資料庫實體名
說明:localhost和127.0.0.1都是本機IP地址
什么是通信協議,有什么用?
通信協議是通信之前就提前定好的資料傳送格式
資料包具體怎么傳資料,格式提前定好的
*/
String url = "jdbc:mysql://127.0.0.1:3306/demodatabase2";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println("資料庫連接物件:" + connection);
} catch (SQLException e) {
e.printStackTrace();
}
//3.獲取資料庫操作物件
//4.執行sql
//5.處理查詢結果
//6.關閉連接
}
}
運行以下,控制臺輸出:

如果上面的代碼連接失敗,試著將url改成下面這個,這個設定了時區
String url = "jdbc:mysql://localhost:3306/demodatabase2?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
3.獲取資料庫操作物件
查看jdk幫助檔案

發現有三個方法,常用的是第一個方法,我們查看具體的解釋
可以發現這個方法回傳一個Statement物件,用于將sql陳述句發送到資料庫
撰寫代碼:
import java.sql.*;
public class JDBCTest01 {
public static void main(String[] args) throws SQLException {
try {
//1.注冊驅動
Driver driver = new com.mysql.cj.jdbc.Driver();//父型別參考指向子型別物件
DriverManager.registerDriver(driver);
//2.獲取連接
String url = "jdbc:mysql://127.0.0.1:3306/demodatabase2";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password);
//3.獲取資料庫操作物件
Statement stmt = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
//4.執行sql
//5.處理查詢結果
//6.關閉連接
}
}
4.執行sql,關閉連接
我們查看jdk幫助檔案

首先我們執行一次INSERT插入操作,我們可以看到用紅色標注起來的這個方法,點進去查看具體的解釋
該方法執行給定的SQL陳述句,可以執行INSERT,UPDATE,DELETE,但是不能執行SELECT,回傳的是一個int型別,表示影響資料庫中的記錄條數
這里我們用insert來對資料庫demodatabase2中student表進行插入操作
資料庫中的student表是這樣設計的

撰寫代碼:
import java.sql.*;
public class JDBCTest01 {
public static void main(String[] args) throws SQLException {
Statement stmt = null;
Connection connection = null;
try {
//1.注冊驅動
Driver driver = new com.mysql.cj.jdbc.Driver();//父型別參考指向子型別物件
DriverManager.registerDriver(driver);
//2.獲取連接
String url = "jdbc:mysql://127.0.0.1:3306/demodatabase2";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
//3.獲取資料庫操作物件
stmt = connection.createStatement();
//4.執行sql
String sql = "INSERT INTO student(id,age,name) VALUES(16,65,\"魏桑\")";
//專門指定DML陳述句的(insert delete update)
//回傳值是"影響資料庫中的記錄條數"
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "保存成功" : "保存失敗");
//5.處理查詢結果集(只有select陳述句才會使用到)
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.關閉連接
//為了保證資源一定釋放,在finally陳述句塊中關閉資源
//并且要遵循從小到大依次關閉
//分別對其try...catch
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
控制臺輸出:

我們查看student表,發現第16條資料已經插入了,

6. JDBC執行洗掉與更新
1.洗掉操作
仿照第五步的操作步驟,我們來洗掉student表中上一步添加的id為16號的資料
撰寫代碼
import com.mysql.cj.jdbc.Driver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCTest02 {
public static void main(String[] args) {
Statement stmt = null;
Connection conn = null;
try {
//1.注冊驅動
Driver driver = new Driver();
DriverManager.registerDriver(driver);
//2.獲取連接
String url = "jdbc:mysql://localhost:3306/demodatabase2";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,user,password);
//3.獲取資料庫操作物件
stmt = conn.createStatement();
//4.執行sql陳述句
String sql = "DELETE FROM student WHERE id = 16";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "洗掉成功" : "洗掉失敗");
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.釋放資源
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
控制臺輸出:

查看student的表,id為16的資料已經被洗掉了,

2.更新操作
我們直接在上一步的基礎上來更改代碼,將id為15的名字改為魏桑
撰寫代碼:
import com.mysql.cj.jdbc.Driver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCTest03 {
public static void main(String[] args) {
Statement stmt = null;
Connection conn = null;
try {
//1.注冊驅動
Driver driver = new Driver();
DriverManager.registerDriver(driver);
//2.獲取連接
String url = "jdbc:mysql://localhost:3306/demodatabase2";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url,user,password);
//3.獲取資料庫操作物件
stmt = conn.createStatement();
//4.執行sql陳述句
String sql = "UPDATE student SET name = \"魏桑\" WHERE id = 15";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "更新成功" : "更新失敗");
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.釋放資源
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
控制臺輸出:

我們查看student表,可以看到id為15的資料更新成功了

7.類加載的方式注冊驅動
我們查看mysql公司實作的Driver介面
而DriverManager.registerDriver(new Driver())在靜態代碼塊中
如果我們要想將類的靜態代碼塊加載,只需要加載這個類即可,那么顯而易見我們可以通過反射來實作,
關于反射的知識可以查看我這篇文章,寫的很清晰
java基礎之反射詳解_ypxcan的博客-CSDN博客_java基礎之反射
撰寫代碼:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCTest04 {
public static void main(String[] args) {
try {
//1.注冊驅動
//這是注冊驅動的第一種寫法
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
//這是第二種方式,也最常規的寫法,通過類加載機制
//為什么這種方式最常用? 因為引數時一個字串,字串可以寫到xxx.properties檔案中
//以下方法不需要接識訓傳值,因為我們只想用它的類加載動作
Class.forName("com.mysql.cj.jdbc.Driver");
//2.獲取連接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/demodatabase2", "root", "root");
System.out.println(conn);
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
8.從屬性資源檔案中讀取連接資料庫資訊
我們創建jdbc.properties檔案,里面填入driver,url,user,password

重新撰寫代碼
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCTest05 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
Properties properties = new Properties();
FileReader fr = null;
try {
fr = new FileReader("java-15-JDBC\\src\\main\\java\\jdbc.properties");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
properties.load(fr);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(properties.getProperty("driver"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
try {
//1.注冊驅動
Class.forName(driver);
//2.獲取連接
conn = DriverManager.getConnection(url,user,password);
//3.獲取操作物件
stmt = conn.createStatement();
//4.執行sql
String sql = "INSERT INTO student(id,age,name) VALUES(16,45,\"周星馳\")";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "插入成功" : "插入失敗");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
或者我們使用資源系結器來優化代碼
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.ResourceBundle;
public class JDBCTest06 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
try {
//1.注冊驅動
Class.forName(driver);
//2.獲取連接
conn = DriverManager.getConnection(url,user,password);
//3.獲取操作物件
stmt = conn.createStatement();
//4.執行sql
String sql = "INSERT INTO student(id,age,name) VALUES(17,45,\"周星馳\")";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "插入成功" : "插入失敗");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
9.處理查詢結果集
我們查看jdk幫助檔案,發現如果想要執行SELECT陳述句,使用的是executequery方法,該回傳一個ResultSet結果集物件

我們查看詳細的解釋

我們再去查看ResultSet類,里面有一個next方法,明確清楚著寫著ResultSet游標最初位于第一行之前,所以我們只有呼叫一次next方法后,游標才會處于結果集的第一行,
我們來完善代碼:
package com.lu.jdbc;
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCTest07 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String user = bundle.getString("user");
String url = bundle.getString("url");
String password = bundle.getString("password");
try {
//1.注冊驅動
Class.forName(driver);
//2.獲取連接
conn = DriverManager.getConnection(url,user,password);
//3.獲取資料庫操作物件
stmt = conn.createStatement();
//4.執行sql陳述句
String sql = "SELECT * FROM student";
rs = stmt.executeQuery(sql);//專門執行DQL的方法
//5.處理查詢結果集
while (rs.next()) {
String id = rs.getString("id");
String age = rs.getString("age");
String name = rs.getString("name");
System.out.print("id: " + id);
System.out.print(" age: " + age);
System.out.println(" name: " + name);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
控制臺輸出:

10.PreparedStatement的使用
解決sql注入問題,屬于預編譯的資料庫操作物件
PreparedStatement的原理是:預先對SQL陳述句的框架進行編譯,然后再給sql陳述句傳“值”
前面我們所講的獲取資料庫操作物件是通過createStatement()方法,但是對于大部分來講,createStatement方法是有漏洞的,他無法解決sql注入問題,關于PreparedStatement如何解決sql注入問題,可以查看下面這篇文章
PreparedStatement是如何防止SQL注入的? - 棲息之鷹 - 博客園
我們來撰寫代碼
package com.lu.jdbc;
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCTest08 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String user = bundle.getString("user");
String url = bundle.getString("url");
String password = bundle.getString("password");
try {
//1.注冊驅動
Class.forName(driver);
//2.獲取連接
conn = DriverManager.getConnection(url,user,password);
//3.獲取資料庫操作物件
String sql = "SELECT * FROM student WHERE id = ?";
ps = conn.prepareStatement(sql);
//給占位符?傳值(第一個問號下標是1,第二個問號下標是2,JDBC中所有下標從1開始)
ps.setInt(1,15);
//4.執行sql陳述句
rs = ps.executeQuery();
//5.處理查詢結果集
while (rs.next()) {
String id = rs.getString("id");//JDBC中所有下標都是從1開始,不是從0開始
String age = rs.getString("age");
String name = rs.getString("name");
System.out.print("id: " + id);
System.out.print(" age: " + age);
System.out.println(" name: " + name);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
Statement和PreparedStatement的區別
1.PreparedStatement是預編譯的,對于批量處理可以大大提高效率. 也叫JDBC存盤程序
2.使用 Statement 物件,在對資料庫只執行一次性存取的時侯,用 Statement 物件進行處理,PreparedStatement 物件的開銷比Statement大,對于一次性操作并不會帶來額外的好處,
3.statement每次執行sql陳述句,相關資料庫都要執行sql陳述句的編譯,preparedstatement是預編譯得, preparedstatement支持批處理
結論:
PreparedStatement使用較多,只有極少數的情況下需要使用Statement
這篇文章只是講解了如何使用JDBC,而關于更深層次的問題,比如Statement是如何產生sql注入問題的,為什么我們選擇使用PreparedStatement而不是Statement,Statement不能解決sql注入問題為什么還存在著,Statement的應用場景是什么,悲觀鎖和樂觀鎖等問題我們都沒有講解到,但這篇文章對于新手來說,足夠可以使用Java對Mysql進行上手,希望這篇文章可以幫助更多的Java新手,如果有什么問題可以在評論區指出,謝謝你的觀看!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/336182.html
標籤:其他
上一篇:Linux精簡教程
