MYSQL的Java操作器——JDBC 在學習了Mysql之後,我們就要把Mysql和我們之前所學習的Java所結合起來 而JDBC就是這樣一種工具:幫助我們使用Java語言來操作Mysql資料庫 JDBC簡介 首先我們先來瞭解一下JDBC JDBC概念: JDBC是使用Java語言操作關係資料庫的 ...
MYSQL的Java操作器——JDBC
在學習了Mysql之後,我們就要把Mysql和我們之前所學習的Java所結合起來
而JDBC就是這樣一種工具:幫助我們使用Java語言來操作Mysql資料庫
JDBC簡介
首先我們先來瞭解一下JDBC
JDBC概念:
- JDBC是使用Java語言操作關係資料庫的一套API
- 全稱:(Java DataBase Connectivity)Java資料庫連接
JDBC本質:
- 官方(sun公司)定義的一套操作所有關係型資料庫的規則,即介面
- 各個資料庫廠商去實現這套介面,提供資料庫驅動jar包
- 我們可以使用這套介面(JDBC)編程,真正運行的代碼時驅動jar包中的實現類
JDBC優點:
- 各資料庫廠商使用相同的介面,Java代碼不需要針對不同資料庫分別開發
- 可隨時替代基層資料庫,訪問資料庫的Java代碼基本不變
JDBC快速入門
下麵我們通過JDBC的基本步驟和一段實例代碼來帶大家體驗一下JDBC
基本步驟:
// 0.創建工程,導入驅動jar包 (資源可以在網路搜索)
// 1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
// 2.獲得連接
Connection conn = DriverManager.getConnection(url,username,password);
// 3.定義MYSQL語句
String sql = "~~~";
// 4.獲得執行對象
Statement stmt = conn.createStatement();
// 5.執行SQL語句
stmt.executeUpdate(sql);
// 6.處理返回結果
// 7.釋放資源
實例代碼:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
// JDBC快速入門
public class Demo1 {
public static void main(String[] arg) throws Exception{
// 1.註冊驅動(這裡是固定語法,是Java中的反射)
Class.forName("com.mysql.jdbc.Driver");
// 2.獲得連接(Connection是類,最後需要釋放資源)
// (url前面固定jdbc:mysql://127.0.0.1:3306/,最後加上你所需要的資料庫test,username為資料庫賬號,password為資料庫密碼)
String url = "jdbc:mysql://127.0.0.1:3306/test";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 3.定義SQL語句(這裡SQL語句與MYSQL語句相同)
String sql = "update jdbc_test set age = 20 where id = 1";
// 4.獲得執行SQL對象(這裡也是類)
Statement stmt = conn.createStatement();
// 5.執行SQL(註意這裡返回的是count,是sql中受影響的行數)
int count = stmt.executeUpdate(sql);
// 6.返回執行結果
System.out.println(count);
// 7.釋放記憶體
stmt.close();
conn.close();
}
}
JDBC API詳解
JDBC中的API主要有四種,我們將在下麵一一介紹:
DriverManager
DriverManager主要包含兩個作用:
- 註冊驅動
// 註冊驅動是JDBC使用的第一步
Class.forName("com.mysql.jdbc.Driver");
// 上述的操作雖然是Class類的forName操作,但實際上是由Driver類的static函數組成的,如果含興趣可以上網搜索該代碼
註意:
- MYSQL5之後的版本,我們可以省略註冊驅動的步驟
- 自動載入jar包中的META-INF/services/java.sql.Driver文件中的驅動類
- 獲取連接
// 2.獲得連接
// (url前面固定jdbc:mysql://127.0.0.1:3306/,最後加上你所需要的資料庫test,username為資料庫賬號,password為資料庫密碼)
String url = "jdbc:mysql://127.0.0.1:3306/test";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
這裡getConnection包含三個參數,username和password分別表示賬號和密碼,不需要解釋
我們主要關註url的構造:
// 語法: jdbc:mysql://ip地址(功能變數名稱):埠號/資料庫名稱?參數鍵值對1&參數鍵值對2...
// 實例: String url = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false";
註意:
- 當我們是主機併在主機進行MYSQL操作時,127.0.0.1:3306可以省略不寫
- 當我們正常書寫時,會有warning警告,我們可以採用useSSL=false來消除警告
最後我們給出整體代碼來展現DriverManager所學到的部分:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
// JDBC_DriverManager
public class Demo2 {
public static void main(String[] arg) throws Exception{
// 我們在MYSQL5.0以上版本可以省略註冊驅動的步驟
// Class.forName("com.mysql.jdbc.Driver");
// 當我們在主機使用MYSQL時,可以省略27.0.0.1:3306
// 如果我們希望省略SSL警告語言可以設置關閉
String url = "jdbc:mysql:///test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
String sql = "update jdbc_test set age = 20 where id = 1";
Statement stmt = conn.createStatement();
int count = stmt.executeUpdate(sql);
System.out.println(count);
stmt.close();
conn.close();
}
}
Connection
Connection主要包含兩個作用:
- 獲得執行SQL對象
我們有三種方法可以獲得SQL執行對象,這裡先做出語法介紹,在後續我們會進行詳細解釋:
- 普通執行SQL對象
Statement stmt = conn.createStatement();
- 預編譯SQL的執行SQL對象:防止SQL註入
PreparedStatement pstmt = conn.prepareStatement(sql);
- 執行存儲過程的對象
CallableStatement cstmt = conn,prepareCall(sql);
- 事務管理
我們可以通過Connection來進行MYSQL中的事務管理
我們通過對比MYSQL的事務來解釋:
# 開啟事務
BEGIN;
# 提交事務
COMMIT;
# 回滾事務
ROLLBACK;
-- mysql自動提交事務
我們的JDBC也同樣提供三種方法來對應mysql事務:
// 開啟事務 boolean autoCommit有兩種選擇:true為自動提交,false為手動提交(如果希望手動提交設置為false)
conn.setAutoCommit(boolean autoCommit)
// 提交事務
conn.commit();
// 回滾事務
conn.rollback();
最後我們給出整體代碼來展現Connection所學到的部分:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
// JDBC_Connection
public class Demo3 {
public static void main(String[] arg) throws Exception{
String url = "jdbc:mysql:///test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 我們來研究事務的執行 (我們希望下麵兩條語句在一個事務中同時執行)
String sql1 = "update jdbc_test set age = 16 where id = 1";
String sql2 = "update jdbc_test set age = 16 where id = 2";
Statement stmt = conn.createStatement();
// 我們需要在try中進行,因為為了當出錯時可以採用回滾方法
try {
// 開啟事務
conn.setAutoCommit(false);
int count1 = stmt.executeUpdate(sql1);
System.out.println(count1);
int count2 = stmt.executeUpdate(sql2);
System.out.println(count2);
// 提交事務
conn.commit();
} catch (Exception e){
// 出錯時回滾事務
conn.rollback();
}
stmt.close();
conn.close();
}
}
Statement
Statement只有一個作用:執行SQL語句
Statement的執行方式主要分為兩種:
- executeUpdate(DML,DDL)
Statement可以執行Update操作,主要針對mysql的DML和DDL操作
// 下述是Statement執行DML和DDL操作的語法,sql為String類型的mysql語句
int count = stmt.executeUpdate(sql);
// 註意:返回值是DML和DDL語句所影響的行數
下麵我們給出整體案例解釋Statement的executeUpdate操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
// JDBC_DriverManager
public class Demo4 {
public static void main(String[] arg) throws Exception{
}
public static void test_DML() throws SQLException {
String url = "jdbc:mysql:///test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
String sql = "update jdbc_test set age = 20 where id = 1";
Statement stmt = conn.createStatement();
int count = stmt.executeUpdate(sql);
// 我們在實際頁面製作時,需要給用戶反饋是否成功
// 對於DML語句,當count>0時基本為操作成功
if(count>0){
System.out.println("操作成功!");
}else {
System.out.println("操作失敗~");
}
stmt.close();
conn.close();
}
public static void test_DDL() throws SQLException {
String url = "jdbc:mysql:///test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
String sql = "update jdbc_test set age = 20 where id = 1";
Statement stmt = conn.createStatement();
int count = stmt.executeUpdate(sql);
// 我們在實際頁面製作時,需要給用戶反饋是否成功
// 對於DDL語句,DROP時count為0,所以不能用count判斷,基本情況下不報錯即為成功
stmt.close();
conn.close();
}
}
- executeQuery(DQL)
Statement可以執行Query操作,主要針對mysql的DQL操作
// 下述是Statement執行DQL操作的語法,sql為String類型的mysql語句
ResultSet resultSet = stmt.executeQuery(sql);
// 註意:ResultSet是stmt.executeQuery的返回類型,下麵我們將著重介紹一下
ResultSet的作用:
- 封裝了DQL查詢語句的結果
那麼如何獲得ResultSet所儲存的值:
// ResultSet具有next()方法,其作用是:將當前游標向前移動一行,並判斷當前行是否為有效行並返回true或false
// ResultSet在獲得結果後的游標指向目錄行,移動一行後得到第一行數據,
boolean next():
/*
true:表示當前行有數據,可以提取或者直接輸出搜索成功
false:表示當前行沒有數據,表示搜索失敗
*/
// ResultSet具有getXxx(參數)方法,其作用是獲得當前行保存的數據
Xxx name = resultSet.getXxx(參數);
/*
Xxx 表示數據類型:Int,Double,String等
參數有兩種:
1.數字參數,表示列數
2.字元串參數,表示列名
*/
// 具體遍歷採用while語法
while(rs.next()){
//獲得數據
int i = rs.getInt(1);
}
下麵我們給出整體案例解釋Statement的executeQuery操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
// JDBC_SQL
public class Demo5 {
public static void main(String[] arg) throws Exception{
String url = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 我們接下來講解SQL,因為SQL所獲得的數據類型為ResultSet,所以我們單獨講解
// 先設置SQL語句
String sql = "select * from jdbc_test";
// 然後獲得對象
Statement stmt = conn.createStatement();
// 然後開始執行語句
ResultSet resultSet = stmt.executeQuery(sql);
// 然後我們迴圈得到數據
// next最開始指向非數據行,然後開始執行:向下運行一行,並且判斷是否為有效行
while (resultSet.next()){
// 當為有效行,獲得數據(可以通過列數,也可以通過列名)
int id = resultSet.getInt("id");
String string = resultSet.getString(2);
int age = resultSet.getInt("age");
System.out.println(id);
System.out.println(string);
System.out.println(age);
System.out.println("----------------");
}
// 釋放資源
resultSet.close();
stmt.close();
conn.close();
}
}
我們再給出一個mysql和Java結合的常用案例:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import pojo.Student;
// JDBC_SQL案例演示
// 查詢jdbc_test資料庫,封裝進Student對象,並存儲到ArrayList集合中
public class Demo6 {
public static void main(String[] arg) throws Exception{
// 創建集合
List<Student> list = new ArrayList<>();
String url = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,username,password);
// 先設置SQL語句
String sql = "select * from jdbc_test";
// 然後獲得對象
Statement stmt = conn.createStatement();
// 然後開始執行語句
ResultSet resultSet = stmt.executeQuery(sql);
// 然後我們迴圈得到數據
while (resultSet.next()){
// 創建對象
Student s = new Student();
int id = resultSet.getInt("id");
String string = resultSet.getString(2);
int age = resultSet.getInt("age");
// 賦值
s.setId(id);
s.setName(string);
s.setAge(age);
// 把對象插入集合
list.add(s);
}
// 我們查看結果
System.out.println(list);
// 釋放資源
resultSet.close();
stmt.close();
conn.close();
}
}
PreparedStatement
PreparedStatement的作用有兩個:
- 預防SQL註入問題
首先我們先來介紹SQL註入問題:
我們給出一段Web端之前的賬號登錄匹配代碼:
import com.itheima.pojo.Account;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 用戶登錄
*/
public class JDBCDemo6_UserLogin {
@Test
public void testLogin() throws Exception {
//2. 獲取連接:如果連接的是本機mysql並且埠是預設的 3306 可以簡化書寫
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用戶輸入 用戶名和密碼(這裡直接寫入,我們會在JavaWeb部分學到交互)
String name = "zhangsan";
String pwd = "fhsjkfhdsk";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
// 獲取stmt對象
Statement stmt = conn.createStatement();
// 執行sql
ResultSet rs = stmt.executeQuery(sql);
// 判斷登錄是否成功
if(rs.next()){
System.out.println("登錄成功~");
}else{
System.out.println("登錄失敗~");
}
//7. 釋放資源
rs.close();
stmt.close();
conn.close();
}
}
我們可以註意到上述的sql語句採用的是字元串拼接,
因而當我們採用一些特殊字元時,就會導致mysql的搜索語句變為true,搜索到所有的mysql內容然後進入第一個賬號
import com.itheima.pojo.Account;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 用戶登錄
*/
public class JDBCDemo6_UserLogin {
/**
* 演示SQL註入
* @throws Exception
*/
@Test
public void testLogin_Inject() throws Exception {
//2. 獲取連接:如果連接的是本機mysql並且埠是預設的 3306 可以簡化書寫
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用戶輸入 用戶名和密碼
String name = "hfkjsfhskj";
// 註意這裡"' or '1' = '1"帶入到sql語句中就會導致變為select * from tb_user where true
String pwd = "' or '1' = '1";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
System.out.println(sql);
// 獲取stmt對象
Statement stmt = conn.createStatement();
// 執行sql
ResultSet rs = stmt.executeQuery(sql);
// 判斷登錄是否成功
if(rs.next()){
System.out.println("登錄成功~");
}else{
System.out.println("登錄失敗~");
}
//7. 釋放資源
rs.close();
stmt.close();
conn.close();
}
因而我們採用PreparedStatement來預防SQL註入問題
我們先來介紹PreparedStatement的語法:
// 獲得PreparedStatement對象
// 首先我們需要設置sql語句,並且將參數用?代替
String sql = "select * from table where usename = ? and password = ?";
// 我們在創建PreparedStatement對象時需要直接將sql語句帶入
PreparedStatement pstmt = conn.PreparedStatement(sql);
// 然後我們需要設置參數值
pstmt.setXxx(參數1,參數2);
/*
Xxx: 數據類型,包括Int,Double,String等
參數1:?的位置編號,從1開始
參數2:?的值
*/
// 最後執行SQL
pstmt.executeQuery();
下麵我們給出整體案例解釋PreparedStatement操作:
import org.junit.Test;
import java.sql.*;
import java.util.Date;
/**
* API詳解:PreparedStatement
*/
public class JDBCDemo7_PreparedStatement {
@Test
public void testPreparedStatement() throws Exception {
//2. 獲取連接:如果連接的是本機mysql並且埠是預設的 3306 可以簡化書寫
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用戶輸入 用戶名和密碼
String name = "zhangsan";
String pwd = "' or '1' = '1";
// 定義sql
String sql = "select * from tb_user where username = ? and password = ?";
// 獲取pstmt對象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 設置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
// 執行sql
ResultSet rs = pstmt.executeQuery();
// 判斷登錄是否成功
if(rs.next()){
System.out.println("登錄成功~");
}else{
System.out.println("登錄失敗~");
}
//7. 釋放資源
rs.close();
pstmt.close();
conn.close();
}
}
然後我們稍微拓展一下為什麼PreparedStatement為什麼不會導致字元串拼接錯誤:
- 因為PreparedStatement將?直接看作字元串的內容來帶入,
- 你所寫入的’或者“相當於/'和/",不會被當作java代碼的一部分識別
- 預編譯SQL,提高性能
PreparedStatement預編譯原理:
- 在獲得PreparedStatement對象時,將sql語句發送給mysql伺服器進行檢查編譯(耗時)
- 執行後將不再執行這些步驟,因而速度變快
- 如果sql模板一樣,則只需進行一次檢查,編譯
資料庫連接池
首先我們對資料庫連接池做出簡單介紹:
- 資料庫連接池是一個容器,負責分配,管理資料庫連接(Connction)
- 它允許應用程式重覆使用一個現有的資料庫連接,而不是重新建立一個
- 釋放空閑時間超過最大空閑時間的資料庫連接來避免因為沒有釋放資料庫連接而引起的資料庫連接遺漏
資料庫連接池優點:
- 資源重用
- 提高系統響應速度
- 避免資料庫連接遺漏
我們採用通俗解釋來說:
- 正常情況:
我們的資料庫會有很多人訪問,每當來一個人操作資料庫,MYSQL創建一個Connection,在這個人使用後,再將Connection刪除,
這種資源重覆創造刪除,導致資料庫效率低下
- 資料庫連接池:
我們的資料庫具有一定的Connection數量,當每來一個人,MYSQL分配給它一個Connection,併在使用後回收;
如果這個人的使用時間超過正常時間,MYSQL將會自動回收
資料庫連接池實現
我們從三個方法講解資料庫連接池的實現:
-
標準介面:DataSource
- 官方(SUN)提供的資料庫連接池標準介面,由第三方組織實現此介面
- 功能:獲得連接
Connection conn = DataSource.getConnection();
-
常見資料庫連接池:
- DBCP
- C3P0
- Druid
-
Druid(德魯伊)
- Druid連接池是阿裡巴巴開發的資料庫連接池
- 功能強大,性能優秀,是Java語言最好的資料庫連接池之一
Druid(德魯伊)使用
Druid的使用分為五步:
- 導入jar包
- 定義配置文件
- 載入配置文件
- 獲得資料庫連接池對象
- 獲得連接
我們給出實例代碼:
# 定義配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化連接數量
initialSize=5
# 最大連接數
maxActive=10
# 最大等待時間
maxWait=3000
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
/**
* Druid資料庫連接池演示
*/
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1.導入jar包(在網上可以找到,同JDBC包一樣)
//2.定義配置文件
//3. 載入配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
//4. 獲取連接池對象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5. 獲取資料庫連接 Connection
Connection connection = dataSource.getConnection();
System.out.println(connection);
//System.out.println(System.getProperty("user.dir"));
}
}
結束語
好的,關於JDBC的內容我們就講解到這裡!
附錄
該文章屬於學習筆記,主要學習B站黑馬JDBC視頻
這裡附上鏈接:黑馬JDBC視頻全套視頻教程,快速入門jdbc原理+jdbc實戰,一套掌握_嗶哩嗶哩_bilibili