JDBC 常用類/接口詳解(MySQL為例)


DriverManager類

java.sql.DriverManager 是用於管理一組JDBC驅動程序的基本服務。

注意: JDBC 2.0 API中新增的DataSource接口提供了另一種連接到數據源的方法。 使用DataSource對象是連接到數據源的首選方法。

DriverManager類功能

注冊驅動

告訴程序該使用什么數據庫驅動jar

可以直接使用DriverManager類的靜態方法注冊驅動:

static void registerDriver(Driver driver)
// 注冊與給定的驅動程序 DriverManager 。 

也可以間接使用該方法,如下介紹直接和間接調用DriverManager類的靜態方法注冊驅動。

如我們要連接操作的是MySQL,那么我們就要注冊驅動,告訴程序要使用MySQL驅動架包。如下就是注冊MySQL數據庫驅動:

注冊驅動第一種方法:

Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
// 將字節碼文件Driver.java加載進內存,返回Driver.class對象。

注冊驅動第二種方法:

com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);

com.mysql.jdbc.Driver類中存在靜態代碼塊,如下:

static {
    try {
        DriverManager.registerDriver(new Driver());
    } catch (SQLException var1) {
        throw new RuntimeException("Can't register driver!");
    }
}

這里可以看出來,兩種驅動方法其實都是一樣的,都要用到靜態方法registerDriver()

備注:MySQL 5 之后的驅動jar包可以省略注冊驅動的步驟。

獲取數據庫連接

方法

static Connection getConnection(String url, String user, String password) 

方法說明

這是java.sql.DriverManager類的靜態方法,用來獲取數據庫連接。該方法的返回值是Connection對象。

參數說明:
url:指定連接的路徑
user:用戶名
password:密碼 


連接的是MySQL數據庫時,參數url格式舉例說明
語法:jdbc:mysql://ip地址(域名):端口號/數據庫名稱
例子:jdbc:mysql://localhost:3306/Study
細節:如果連接的是本機mysql服務器,並且mysql服務默認端口是3306,則url可以簡寫為:jdbc:mysql:///數據庫名稱

Connection接口

java.sql.Connection接口是一個數據庫連接對象。它與特定數據庫的連接(會話)。 執行SQL語句並在連接的上下文中返回結果。

Connection接口功能

獲取執行SQL的對象

方法:

Statement createStatement()
// 創建一個 Statement對象,用於將SQL語句發送到數據庫。
PreparedStatement prepareStatement(String sql)
// 創建一個 PreparedStatement對象,用於將參數化的SQL語句發送到數據庫。

管理事務

方法:

開啟事務

void setAutoCommit(boolean autoCommit)
// 將此連接的自動提交模式設置為給定狀態。參數為false,即開啟事務

提交事務

void commit()
// 使自上次提交/回滾以來所做的所有更改都將永久性,並釋放此 Connection對象當前持有的任何數據庫鎖。

回滾事務

void rollback()
// 撤消在當前事務中所做的所有更改,並釋放此 Connection對象當前持有的任何數據庫鎖。

Statement接口

java.sql.Statement接口,用於執行靜態SQL語句並返回其生成的結果的對象。

默認情況下,每個Statement對象只能有一個ResultSet對象同時打開。 因此,如果一個ResultSet對象的讀取與另一個對象的讀取交錯,則ResultSet對象必須由不同的Statement對象生成。 在所有執行方法Statement接口隱式關閉當前ResultSet聲明的對象,如果一個開放的存在。

Statement接口功能

執行靜態SQL語句

方法:

boolean execute(String sql)
// 執行給定的SQL語句,這可能會返回多個結果。該方法可以執行任意的SQL語句。
int executeUpdate(String sql)
// 執行給定的SQL語句。執行的是DML(insert、update、delete)語句、DDL(create,alter、drop)語句
// 返回值是一個int類型的數 ———— 執行的SQL語句影響的行數
ResultSet executeQuery(String sql)
// 執行給定的SQL語句,該語句返回單個ResultSet對象。執行DQL(select)語句

舉例

連接Study數據庫,向account表中的id=1的balance字段值加上500。表數據如下:

img

Java代碼實現:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcDemo01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        // 1、導入jar包:mysql-connector-java-5.1.48.jar
        // Add as Library ...

        // 2、注冊驅動
        Class.forName("com.mysql.jdbc.Driver");

        // 3、獲取數據庫連接對象
        Connection connection = DriverManager.getConnection(
                        "jdbc:mysql://localhost:3306/Study?useSSL=false",
                        "用戶名", "密碼");

        // 4、定義SQL語句
        // 將account表中的id=1的balance字段值加上500
        String sql = "UPDATE account Set balance = balance + 500 WHERE id = 1;";

        // 5、獲取執行sql的對象 Statement
        Statement statement = connection.createStatement();

        // 6、執行SQL語句:執行成功,返回 1
        int returnResult = statement.executeUpdate(sql);

        // 7、查看是否執行成功
        System.out.println(returnResult);

        // 8、釋放資源
        statement.close();
        connection.close();
    }
}

執行成功,控制台輸出:1,說明影響的行數是一行。

查看表中現在的數據:

img

ResultSet接口

表示數據庫結果集的數據表,通常通過執行查詢數據庫的語句生成。即該接口是結果集對象,用來封裝查詢結果。

ResultSet對象保持一個光標指向其當前的數據行。 最初,光標位於第一行之前。 next方法將光標移動到下一行,並且由於在ResultSet對象中沒有更多行時返回false ,因此可以在while循環中使用循環來遍歷結果集。

下面介紹幾個具代表性的方法

ResultSet接口功能

游標向下移動一行

boolean next()
// 將光標從當前位置向前移動一行。

獲取數據

getXxx(參數列表) 方法

String getString(int columnIndex)
// 這個檢索的當前行中指定列的值 ResultSet對象為 String的Java編程語言。
// int columnIndex:列的索引,索引從1開始,1對應第一列

String getString(String columnLabel)
// 這個檢索的當前行中指定列的值 ResultSet對象為 String的Java編程語言。
// String columnLabel:指定的列名稱
int getInt(int columnIndex)
// 這個檢索的當前行中指定列的值 ResultSet作為對象 int在Java編程語言。
// int columnIndex:列的索引

舉例

題目:查看account表中的記錄,account表位於本地mysql的Study數據庫下,端口號為3306

account表

account表如下:
CREATE TABLE account (
    id INT PRIMARY KEY AUTO_INCREMENT,   -- id
    NAME VARCHAR(10),                    -- 名字
    balance DOUBLE                       -- 余額
);
INSERT INTO account (NAME, balance) VALUES ('LeeHua', 1500), ('Tom', 1000);

Java程序實現:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;

public class JdbcDemo03 {
    public static void main(String[] args) {
        Statement statement = null;
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            // 1. 注冊驅動
            Class.forName("com.mysql.jdbc.Driver");

            // 2. 定義SQL語句
            String sql = "SELECT * FROM account;";

            // 3.獲取Connection對象
            connection = DriverManager.getConnection(
                    "jdbc:mysql:///Study?useSSL=false", "LeeHua", "qq562246926"
            );

            // 4.獲取執行sql的對象 Statement
            statement = connection.createStatement();

            // 5.執行sql,返回查詢結果(一個表),用ResultSet對象來封裝。
            resultSet = statement.executeQuery(sql);

            // 6.處理結果
            // 6.1 循環判斷游標是否是最后一行末尾。
            while(resultSet.next()){
                // 獲取數據
                // 6.2 獲取數據
                // 獲取 ID 字段的值
                int id = resultSet.getInt(1);
                // 獲取name字段的值
                String name = resultSet.getString("name");
                // 獲取balance字段的值
                double balance = resultSet.getDouble(3);
                // 輸出
                System.out.println(id + " --- " + name + " --- " + balance);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7. 釋放資源
            releaseResources(resultSet);
            releaseResources(statement);
            releaseResources(connection);
        }
    }

    public static <T> void releaseResources (T t){
        if(t != null){
            try {
                // 利用反射,獲取class對象
                Class<?> aClass = t.getClass();
                // 獲取class對象中的方法對象
                Method close = aClass.getMethod("close");
                // 執行方法
                close.invoke(t);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

PreparedStatement接口

PreparedStatement接口 extends Statement接口,表示預編譯的SQL語句的對象。SQL語句已預編譯並存儲在PreparedStatement對象中。 然后可以使用該對象多次有效地執行此語句。

預編譯的SQL:參數使用?作為占位符

如:

new Statement.executeQuery(sql1);

new PreparedStatement.executeQuery(sql2);

兩個對象都執行SQL語句,Statement接口是執行靜態SQL的,即已經拼接好的SQL,而PreparedStatement接口是執行預編譯的SQL語句的。

如:

sql1 = "SELECT * FROM account WHERE id = ID AND balance = 賬戶余額;"

sql2 = "SELECT * FROM account WHERE id = ? AND balance = ?;"

sql1是靜態的SQL語句,sql2是預編譯SQL語句。

PreparedStatement接口的用法和其父接口Statement的用法差不多,只是父接口是執行靜態SQL語句的,而PreparedStatement接口是傳入並執行預編譯的SQL語句的。

給?賦值

方法: setXxx(參數1,參數2)

參數說明:

參數1:?的位置編號 從1 開始
參數2:?的值

如:

void setInt(int parameterIndex, int x)
// 將指定的參數設置為給定的Java int值。
void setString(int parameterIndex, String x)
// 將指定的參數設置為給定的Java String值。

舉例

需求:獲取數據庫中字段的記錄,對比用戶輸入,模擬登陸。

實現

自定義一個注解,用於獲取部分值:

package my.view.util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) // 注解能作用於類上
@Retention(RetentionPolicy.RUNTIME) // 當前被描述的注解,會保留到class字節碼文件中,並被JVM讀取到
public @interface PropertiesAnnotation {

    /* URL */
    public abstract String url();

    /* 用戶 */
    public abstract String user();

    /* 密碼 */
    public abstract String password();

    /* 驅動包 */
    public abstract String driver();
}

創建一個MySQL表格:

CREATE TABLE login (
    id INT PRIMARY KEY AUTO_INCREMENT,             -- id
    user VARCHAR(30),                              -- 用戶名
    password VARCHAR(30)                           -- 密碼
);

向表格中傳入數據:

INSERT INTO login (user, password) VALUES ('LeeHua', '123456'), ('Tom', 'abcdef');

創建一個Jdbc工具類,用來注冊驅動和獲取連接對象:

img

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

@PropertiesAnnotation(
        url = "jdbc:mysql:///Study", user = "mysql賬號", password = "mysql密碼", driver = "com.mysql.jdbc.Driver"
)
public class JdbcUtils02 {

    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    /* 文件的讀取,只需要讀取一次即可拿到這些值。利用反射和注解、使用靜態代碼塊 */
    static{
        // 讀取資源文件,獲取值。

        try {
            // 1. 解析注解
            // 1.1 獲取JdbcUtils02類的字節碼文件對象
            Class<JdbcUtils02> jdbcUtils02Class = JdbcUtils02.class;

            // 2. 獲取上邊的注解對象
            PropertiesAnnotation annotation = jdbcUtils02Class.getAnnotation(PropertiesAnnotation.class);

            // 3. 調用注解中定義的抽象方法,獲取返回值,賦值給靜態成員變量
            url = annotation.url();
            user = annotation.user();
            password = annotation.password();
            driver = annotation.driver();

            // 4. 注冊驅動
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    /**
     * 獲取連接
     * @return 連接對象
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);
    }

}

View Code

使用Statement接口,創建一個登錄類:

public boolean login(String user, String password) {
    if (user == null || password == null) {
        return false;
    }
    Connection connection =null;
    Statement statement = null;
    ResultSet resultSet = null;
    try {
        // 獲取數據庫連接
        connection = JdbcUtils02.getConnection();
        // 定義SQL
        String sql = "SELECT * FROM login WHERE user = '" + user + "' AND password = '" + password + "';";
        // 獲取執行SQL對象
        statement = connection.createStatement();
        // 執行查詢
        resultSet = statement.executeQuery(sql);
        // 判斷是否存在下一行數據
        return resultSet.next();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return false;
}

使用PreparedStatement接口,創建一個登錄類:

public boolean login(String user, String password) {
    if (user == null || password == null) {
        return false;
    }
    Connection connection =null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
        // 獲取數據庫連接
        connection = JdbcUtils02.getConnection();
        // 定義SQL
        String sql = "SELECT * FROM login WHERE user = ? AND password = ?;";
        // 獲取執行SQL語句對象
        preparedStatement = connection.prepareStatement(sql);
        // 給?賦值
        preparedStatement.setString(1, user);
        preparedStatement.setString(2, password);
        // 執行SQL語句
        resultSet = preparedStatement.executeQuery();
        // 判斷是否存在下一行數據
        return resultSet.next();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return false;
}

模擬測試:登錄方法在Demo類中。

public class Demo {

    public static void main(String[] args) {

        // 鍵盤錄入,接收用戶名和密碼
        Scanner scn = new Scanner(System.in);
        System.out.print("請輸入用戶名:");
        String userName = scn.nextLine();
        System.out.print("請輸入密碼:");
        String password = scn.nextLine();

        // 調用登錄確認方法
        Demo demo08 = new Demo();
        if (demo.login(userName, password)) {
            System.out.println("登錄成功!");
        } else {
            System.out.println("登錄失敗!用戶名或密碼額錯誤。");
        }

    }

}
  • 調用使用Statement接口創建的登錄方法測試:

如果正常情況下輸入,那么該方法判斷用戶賬號密碼是否正確是有效的。如果輸入恆等式,那么該方法就失效了,無論輸入什么恆等式,都可以登錄,舉例如:

請輸入用戶名:LeeHua
請輸入密碼:abc' OR 'abc' = 'abc

那么這個時候,被拼接好的SQL語句就如下:

SELECT * FROM login WHERE user = 'LeeHua' AND password = 'abc' OR 'abc' = 'abc';

這是一條恆等式,不論 password是否正確,都可以登錄成功,這是相當危險的,就像別人能夠隨隨便便登錄個人微信一樣,安全隱患很大,所以我們使用預編譯的SQL語句,不使用靜態SQL語句。

運行,控制台輸出:登錄成功!
  • 調用使用PreparedStatement接口創建的登錄方法測試:

這個時候無論輸入什么,都會判斷正確,因為這里傳入的是一條預編譯的SQL語句,並不是拼接的SQL語句。

舉例如:

請輸入用戶名:LeeHua
請輸入密碼:abc' OR 'abc' = 'abc

那么這個時候實質傳入的SQL語句是:

SELECT * FROM login WHERE user = 'LeeHua' AND password = 'abc' OR 'abc' = 'abc';
運行,控制台輸出:登錄失敗!用戶名或密碼額錯誤。

所以,判斷用戶名和密碼是准確的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM