點擊讓手機旋轉,
即可自動調整表格格式
進行觀看
向上滑動查看更多
可以說看完這一篇基本上Java資料庫基礎JDBC必備的知識點以後會持續的為大家提供【免費]、【高質量】的全球技術行業資訊;前沿IT技術分享;一線大廠招聘、內推與筆面試準備等服務。為了方便大家下載,可以關注我們的公眾號:
回覆:【python】、【Java】、【sql】、【面試】
即可免費自助獲取對應資料下載連結。
好了,進入正題,我們來看今天的【超詳細乾貨】【收藏向】【Java面試必備】一文搞定Java資料庫基礎JDBC
1)使用第三方客戶端來訪問 MySQL:SQLyog、Navicat、SQLWave、MyDB Studio、EMS SQL Manager for MySQL
2)使用 MySQL 自帶的命令行方式
3) 通過 Java 來訪問 MySQL 資料庫,也就是今天我們要學習的內容
JDBC 規範定義接口,具體的實現由各大資料庫廠商來實現。
JDBC 是 Java 訪問資料庫的標準規範,真正怎麼操作資料庫還需要具體的實現類,也就是資料庫驅動。每個
資料庫廠商根據自家資料庫的通信格式編寫好自己資料庫的驅動。所以我們只需要會調用 JDBC 接口中的方法即可,資料庫驅動由資料庫廠商提供。
1) 程式設計師如果要開發訪問資料庫的程序,只需要會調用 JDBC 接口中的方法即可,不用關注類是如何實現的。
2) 使用同一套 Java 代碼,進行少量的修改就可以訪問其他 JDBC 支持的資料庫
package com.lqg;public class Demo1 {public static void main(String[] args) throws ClassNotFoundException {3 / 21//拋出類找不到的異常,註冊資料庫驅動Class.forName("com.mysql.jdbc.Driver"); }} com.mysql.jdbc.Driver 原始碼:// Driver 接口,所有資料庫廠商必須實現的接口,表示這是一個驅動類。public class Driver implements java.sql.Driver {public Driver() throws SQLException { }static {try {DriverManager.registerDriver(new Driver()); //註冊資料庫驅動} catch (SQLException var1) {throw new RuntimeException("Can't register driver!"); } }}
1) 管理和註冊驅動
2) 創建資料庫的連接
協議名:子協議://伺服器名或 IP 地址:埠號/資料庫名?參數=參數值
前提:必須是本地伺服器,埠號是 3306
jdbc:mysql:///資料庫名
如果資料庫出現亂碼,可以指定參數: ?characterEncoding=utf8,表示讓資料庫以 UTF-8 編碼來處理數據。
jdbc:mysql://localhost:3306/資料庫?characterEncoding=utf8
1) 使用用戶名、密碼、URL 得到連接對象
package com.lqg;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;/*** 得到連接對象*/public class Demo2 {public static void main(String[] args) throws SQLException {String url = "jdbc:mysql://localhost:3306/day24";//1) 使用用戶名、密碼、URL 得到連接對象Connection connection = DriverManager.getConnection(url, "root", "root");//com.mysql.jdbc.JDBC4Connection@68de145System.out.println(connection); }}2) 使用屬性文件和 url 得到連接對象
package com.lqg;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.util.Properties;public class Demo3 {public static void main(String[] args) throws SQLException {//url 連接字符串String url = "jdbc:mysql://localhost:3306/day24";//屬性對象Properties info = new Properties();//把用戶名和密碼放在 info 對象中5 / 21info.setProperty("user","root");info.setProperty("password","root");Connection connection = DriverManager.getConnection(url, info);//com.mysql.jdbc.JDBC4Connection@68de145System.out.println(connection); }}
Connection 接口,具體的實現類由資料庫的廠商實現,代表一個連接對象。
1) 註冊和加載驅動(可以省略)
2) 獲取連接
3) Connection 獲取 Statement 對象
4) 使用 Statement 對象執行 SQL 語句
5) 返回結果集
6) 釋放資源
代表一條語句對象,用於發送 SQL 語句給伺服器,用於執行靜態 SQL 語句並返回它所生成結果的對象。
1) 需要釋放的對象:ResultSet 結果集,Statement 語句,Connection 連接
2) 釋放原則:先開的後關,後開的先關。ResultSet Statement Connection
3) 放在哪個代碼塊中:finally 塊
4.5.1 需求:使用 JDBC 在 MySQL 的資料庫中創建一張學生表
4.5.2 代碼:
package com.lqg;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;/*** 創建一張學生表*/public class Demo4DDL {public static void main(String[] args) {//1. 創建連接Connection conn = null;Statement statement = null;try {conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");//2. 通過連接對象得到語句對象statement = conn.createStatement();//3. 通過語句對象發送 SQL 語句給伺服器//4. 執行 SQLstatement.executeUpdate("create table student (id int PRIMARY key auto_increment, " +"name varchar(20) not null, gender boolean, birthday date)");//5. 返回影響行數(DDL 沒有返回值)System.out.println("創建表成功"); } catch (SQLException e) {e.printStackTrace(); }//6. 釋放資源finally {//關閉之前要先判斷if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace(); }7 / 21}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace(); } } } }}
1) 創建連接對象
2) 創建 Statement 語句對象
3) 執行 SQL 語句:executeUpdate(sql)
4) 返回影響的行數
5) 釋放資源
package com.lqg;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;/*** 向學生表中添加 4 條記錄,主鍵是自動增長*/public class Demo5DML {public static void main(String[] args) throws SQLException {// 1) 創建連接對象Connection connection = DriverManager.getConnection("jdbc:mysql:///day24", "root","root");// 2) 創建 Statement 語句對象Statement statement = connection.createStatement();// 3) 執行 SQL 語句:executeUpdate(sql)int count = 0;// 4) 返回影響的行數count += statement.executeUpdate("insert into student values(null, '孫悟空', 1, '1993-03-24')");count += statement.executeUpdate("insert into student values(null, '白骨精', 0, '1995-03-24')");count += statement.executeUpdate("insert into student values(null, '豬八戒', 1, '1903-03-8 / 2124')");count += statement.executeUpdate("insert into student values(null, '嫦娥', 0, '1993-03-11')");System.out.println("插入了" + count + "條記錄");// 5) 釋放資源statement.close();connection.close(); }}
java.sql.Date、Time、Timestamp(時間戳),三個共同父類是:java.util.Date
4.7.3 需求:確保資料庫中有 3 條以上的記錄,查詢所有的學員信息
步驟:
1) 得到連接對象
2) 得到語句對象
3) 執行 SQL 語句得到結果集 ResultSet 對象
4) 循環遍歷取出每一條記錄
5) 輸出的控制臺上
6) 釋放資源
結果:
package com.lqg;import java.sql.*;10 / 21/*** 查詢所有的學生信息*/public class Demo6DQL { public static void main(String[] args) throws SQLException { //1) 得到連接對象 Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/day24","root","root"); //2) 得到語句對象 Statement statement = connection.createStatement(); //3) 執行 SQL 語句得到結果集 ResultSet 對象 ResultSet rs = statement.executeQuery("select * from student"); //4) 循環遍歷取出每一條記錄 while(rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); boolean gender = rs.getBoolean("gender"); Date birthday = rs.getDate("birthday"); //5) 輸出的控制臺上System.out.println("編號:" + id + ", 姓名:" + name + ", 性別:" + gender + ", 生日:" +birthday);}//6) 釋放資源rs.close();statement.close();connection.close(); }}
4.7.4 關於 ResultSet 接口中的注意事項:
1) 如果光標在第一行之前,使用 rs.getXX()獲取列值,報錯:Before start of result set
2) 如果光標在最後一行之後,使用 rs.getXX()獲取列值,報錯:After end of result set
3) 使用完畢以後要關閉結果集 ResultSet,再關閉 Statement,再關閉 Connection
如果一個功能經常要用到,我們建議把這個功能做成一個工具類,可以在不同的地方重用。
1) 有一張用戶表
2) 添加幾條用戶記錄
create table user (id int primary key auto_increment,name varchar(20),password varchar(20))insert into user values (null,'jack','123'),(null,'rose','456');-- 登錄, SQL 中大小寫不敏感select * from user where name='JACK' and password='123';-- 登錄失敗select * from user where name='JACK' and password='333';3) 使用 Statement 字符串拼接的方式實現用戶的登錄, 用戶在控制臺上輸入用戶名和密碼。
1) 得到用戶從控制臺上輸入的用戶名和密碼來查詢資料庫
2) 寫一個登錄的方法
a) 通過工具類得到連接
b) 創建語句對象,使用拼接字符串的方式生成 SQL 語句
c) 查詢資料庫,如果有記錄則表示登錄成功,否則登錄失
d) 釋放資源
package com.lqg;import com.lqg.utils.JdbcUtils;import javax.xml.transform.Result;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Scanner;public class Demo7Login {//從控制臺上輸入的用戶名和密碼public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶名:");String name = sc.nextLine();System.out.println("請輸入密碼:");String password = sc.nextLine();login(name, password);13 / 21 } /** * 登錄的方法 */public static void login(String name, String password) {//a) 通過工具類得到連接Connection connection = null;Statement statement = null;ResultSet rs = null;try {connection = JdbcUtils.getConnection();//b) 創建語句對象,使用拼接字符串的方式生成 SQL 語句statement = connection.createStatement();//c) 查詢資料庫,如果有記錄則表示登錄成功,否則登錄失敗String sql = "select * from user where name='" + name + "' and password='" + password+ "'";System.out.println(sql);rs = statement.executeQuery(sql);if (rs.next()) {System.out.println("登錄成功,歡迎您:" + name);} else {System.out.println("登錄失敗"); } } catch (SQLException e) {e.printStackTrace();} finally {//d) 釋放資源JdbcUtils.close(connection, statement, rs); } }}
請輸入用戶名:newboy請輸入密碼:a' or '1'='1select * from user where name='newboy' and password='a' or '1'='1'登錄成功,歡迎您:newboy問題分析:
select * from user where name='newboy' and password='a' or '1'='1'name='newboy' and password='a' 為假'1'='1' 真相當於select * from user where true; 查詢了所有記錄我們讓用戶輸入的密碼和 SQL 語句進行字符串拼接。用戶輸入的內容作為了 SQL 語句語法的一部分,改變了
原有 SQL 真正的意義,以上問題稱為 SQL 注入。要解決 SQL 注入就不能讓用戶輸入的密碼和我們的 SQL 語句進
行簡單的字符串拼接。
PreparedStatement 是 Statement 接口的子接口,繼承於父接口中所有的方法。它是一個預編譯的 SQL 語句
6.2 PreparedSatement 的執行原理
1) 因為有預先編譯的功能,提高 SQL 的執行效率。
2) 可以有效的防止 SQL 注入的問題,安全性更高。
6.3 Connection 創建 PreparedStatement 對象
6.4 PreparedStatement 接口中的方法:
6.5 PreparedSatement 的好處
1. prepareStatement()會先將 SQL 語句發送給資料庫預編譯。PreparedStatement 會引用著預編譯後的結果。
可以多次傳入不同的參數給 PreparedStatement 對象並執行。減少 SQL 編譯次數,提高效率。
2. 安全性更高,沒有 SQL 注入的隱患。
3. 提高了程序的可讀性
6.6 使用 PreparedStatement 的步驟:
1) 編寫 SQL 語句,未知內容使用?佔位:"SELECT * FROM user WHERE name=? AND password=?";
2) 獲得 PreparedStatement 對象
3) 設置實際參數:setXxx(佔位符的位置, 真實的值)
4) 執行參數化 SQL 語句
5) 關閉資源
package com.lqg;import com.itheima.utils.JdbcUtils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Scanner;/*** 使用 PreparedStatement*/public class Demo8Login { //從控制臺上輸入的用戶名和密碼 public static void main(String[] args) throws SQLException { Scanner sc = new Scanner(System.in); System.out.println("請輸入用戶名"); String name = sc.nextLine(); System.out.println("請輸入密碼:"); String password = sc.nextLine(); login(name, password);}/*** 登錄的方法* @param name16 / 21* @param password*/private static void login(String name, String password) throws SQLException { Connection connection = JdbcUtils.getConnection(); //寫成登錄 SQL 語句,沒有單引號 String sql = "select * from user where name=? and password=?"; //得到語句對象 PreparedStatement ps = connection.prepareStatement(sql); //設置參數 ps.setString(1, name); ps.setString(2,password); ResultSet resultSet = ps.executeQuery(); if (resultSet.next()) { System.out.println("登錄成功:" + name); } else { System.out.println("登錄失敗"); } //釋放資源,子接口直接給父接口 JdbcUtils.close(connection,ps,resultSet); } }
6.7.1 案例:使用 PreparedStatement 查詢一條數據,封裝成一個學生 Student 對象
package com.lqg;import com.lqg.entity.Student;import com.lqg.utils.JdbcUtils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class Demo9Student {public static void main(String[] args) throws SQLException { //創建學生對象 Student student = new Student(); 17 / 21 Connection connection = JdbcUtils.getConnection(); PreparedStatement ps = connection.prepareStatement("select * from student where id=?"); //設置參數 ps.setInt(1,2); ResultSet resultSet = ps.executeQuery(); if (resultSet.next()) { //封裝成一個學生對象 student.setId(resultSet.getInt("id")); student.setName(resultSet.getString("name")); student.setGender(resultSet.getBoolean("gender")); student.setBirthday(resultSet.getDate("birthday")); } //釋放資源 JdbcUtils.close(connection,ps,resultSet); //可以數據 System.out.println(student); } }
6.7.2 案例:將多條記錄封裝成集合 List<Student>,集合中每個元素是一個 JavaBean 實體類
package com.lqg;import com.lqg.entity.Student;import com.lqg.utils.JdbcUtils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;public class Demo10List {public static void main(String[] args) throws SQLException { //創建一個集合 List<Student> students = new ArrayList<>(); Connection connection = JdbcUtils.getConnection(); PreparedStatement ps = connection.prepareStatement("select * from student"); //沒有參數替換 ResultSet resultSet = ps.executeQuery(); while(resultSet.next()) { //每次循環是一個學生對象 Student student = new Student(); //封裝成一個學生對象 student.setId(resultSet.getInt("id")); 18 / 21 student.setName(resultSet.getString("name")); student.setGender(resultSet.getBoolean("gender")); student.setBirthday(resultSet.getDate("birthday")); //把數據放到集合中 students.add(student); } //關閉連接 JdbcUtils.close(connection,ps,resultSet); //使用數據 for (Student stu: students) { System.out.println(stu); } } }
6.8 PreparedStatement 執行 DML 操作
package com.lqg;import com.lqg.utils.JdbcUtils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public class Demo11DML {public static void main(String[] args) throws SQLException { //insert(); //update(); delete(); } //插入記錄 private static void insert() throws SQLException { Connection connection = JdbcUtils.getConnection(); PreparedStatement ps = connection.prepareStatement("insert into student values(null,?,?,?)"); ps.setString(1,"小白龍"); ps.setBoolean(2, true); ps.setDate(3,java.sql.Date.valueOf("1999-11-11")); int row = ps.executeUpdate(); System.out.println("插入了" + row + "條記錄"); JdbcUtils.close(connection,ps); } //更新記錄: 換名字和生日 private static void update() throws SQLException { Connection connection = JdbcUtils.getConnection(); PreparedStatement ps = connection.prepareStatement("update student set name=?, birthday=? where id=?"); ps.setString(1,"黑熊怪"); ps.setDate(2,java.sql.Date.valueOf("1999-03-23")); ps.setInt(3,5); int row = ps.executeUpdate(); System.out.println("更新" + row + "條記錄"); JdbcUtils.close(connection,ps); } 19 / 21 //刪除記錄: 刪除第 5 條記錄 private static void delete() throws SQLException { Connection connection = JdbcUtils.getConnection(); PreparedStatement ps = connection.prepareStatement("delete from student where id=?"); ps.setInt(1,5); int row = ps.executeUpdate(); System.out.println("刪除了" + row + "條記錄"); JdbcUtils.close(connection,ps); } }
之前我們是使用 MySQL 的命令來操作事務。接下來我們使用 JDBC 來操作銀行轉帳的事務。
CREATE TABLE account (id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(10),balance DOUBLE);INSERT INTO account (NAME, balance) VALUES ('Jack', 1000), ('Rose', 1000);
1) 獲取連接
2) 開啟事務
3) 獲取到 PreparedStatement
4) 使用 PreparedStatement 執行兩次更新操作
5) 正常情況下提交事務
6) 出現異常回滾事務
7) 最後關閉資源
package com.lqg;import com.lqg.utils.JdbcUtils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public class Demo12Transaction { //沒有異常,提交事務,出現異常回滾事務 public static void main(String[] args) { 20 / 21 //1) 註冊驅動 Connection connection = null; PreparedStatement ps = null; try { //2) 獲取連接 connection = JdbcUtils.getConnection(); //3) 開啟事務 connection.setAutoCommit(false); //4) 獲取到 PreparedStatement //從 jack 扣錢 ps = connection.prepareStatement("update account set balance = balance - ? where name=?"); ps.setInt(1, 500); ps.setString(2,"Jack"); ps.executeUpdate(); //出現異常 System.out.println(100 / 0); //給 rose 加錢 ps = connection.prepareStatement("update account set balance = balance + ? where name=?"); ps.setInt(1, 500); ps.setString(2,"Rose"); ps.executeUpdate(); //提交事務 connection.commit(); System.out.println("轉帳成功"); } catch (Exception e) { e.printStackTrace(); try { //事務的回滾 connection.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } System.out.println("轉帳失敗"); } finally { //7) 關閉資源 JdbcUtils.close(connection,ps); } }}版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本聲明。
本文連結:https://blog.csdn.net/qq_43674132/article/details/95171884
更多內容,歡迎標⭐公眾號,每日更新ing
最後,感謝大家對樂學偶得的關注與支持~
歡迎更多的小夥伴加入樂學偶得大家庭~
添加樂學偶得校花小姐姐,自助領取禮包與自助入群~
輸入【相應資料編號與想加入的群】,自助領取資料與進入學習交流群
(純交流,無廣告,群內福利持續更新,免費領取)
點擊左下角【閱讀原文】查看【樂學偶得】更多乾貨