day46-JDBC和連接池02

来源:https://www.cnblogs.com/liyuelian/archive/2022/10/14/16793246.html
-Advertisement-
Play Games

JDBC和連接池02 3.ResultSet[結果集] 基本介紹 表示資料庫結果集的數據表,通常通過執行查詢資料庫的語句生成 ResultSet對象保持一個游標指向其當前的數據行,最初,游標位於第一行的之前 next方法將游標移動到下一行,並且由於在ResultSet對象中沒有更多行時返回false ...


JDBC和連接池02

3.ResultSet[結果集]

  • 基本介紹
  1. 表示資料庫結果集的數據表,通常通過執行查詢資料庫的語句生成
  2. ResultSet對象保持一個游標指向其當前的數據行,最初,游標位於第一行的之前
  3. next方法將游標移動到下一行,並且由於在ResultSet對象中沒有更多行時返回false,因此可以在while迴圈中使用迴圈來遍歷結果集

例子

首先在資料庫的actor表中添加兩行數據

INSERT INTO actor VALUES(NULL,'劉德華','男','1970-12-12','110'),
			(NULL,'jack','男','1990-11-11','112')
image-20221014173529899
package li.jdbc.resultset_;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.util.Properties;

@SuppressWarnings("all")
public class ResultSet_ {
    public static void main(String[] args) throws Exception {
        //通過Properties對象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //獲取相關的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.註冊驅動
        Class.forName(driver);//建議寫上
        //2.得到連接
        Connection connection = DriverManager.getConnection(url, user, password);

        //3.得到statement
        Statement statement = connection.createStatement();
        //4.組織sql
        String sql = "select id,name,sex,borndate from actor";
        //執行給定的sql語句,該語句返回單個ResultSet對象

        /**
         +----+-----------+-----+----------------------+
         | id | name      | sex | borndate             |
         +----+-----------+-----+----------------------+
         |  1 | 劉德華    | 男  | 1970-12-12 00:00:00   |
         |  2 | jack     | 男  | 1990-11-11 00:00:00   |
         +----+-----------+-----+----------------------+
         */
        /**
         * resultset源碼 ResultSet對象的結構
         *
         */
        ResultSet resultSet = statement.executeQuery(sql);

        //5.使用while迴圈取出數據
        //最開始時next指向表頭(第一行之前)
        while (resultSet.next()) {//讓游標向後移動,如果沒有更多行,則返回false
            int id = resultSet.getInt(1);//獲取該行的第1列數據
            String name = resultSet.getString(2);//獲取該行的第2列數據
            String sex = resultSet.getString(3);//獲取該行的第3列數據
            Date date = resultSet.getDate(4);//獲取該行的第4列數據
            System.out.println(id+"\t"+name+"\t"+sex+"\t"+date);
        }

        //6.關閉連接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

運行結果如下:

image-20221014173656930

在語句ResultSet resultSet = statement.executeQuery(sql);旁打上斷點,點擊debug,點擊step over,選擇resultset數組,再選擇rowdata。

image-20221014173946558

可以看到底層是arraylist的一個對象數組。

image-20221014173342335

4.Statement

  • 基本介紹
  1. Statement對象,用於執行靜態SQL語句並返回其生成的結果的對象
  2. 在建立連接後,需要對資料庫進行訪問,執行命名或是SQL語句,可以通過
    • Statement [存在SQL註入問題]
    • PreparedStatement [預處理]
    • CallableStatement [存儲過程]
  3. Statement對象執行SQL語句,存在SQL註入風險
  4. SQL註入是利用某些系統沒有對用戶輸入的數據進行充分的檢查,而在用戶輸入數據中註入非法的SQL語句段或命令,惡意攻擊資料庫
  5. 要防範SQL註入,只要用PreparedStatement(從Statement擴展而來)取代Statement就可以了

例子1-sqlyog演示sql註入

-- 演示sql註入
-- 創建一張表
CREATE TABLE admin( -- 管理員表
	NAME VARCHAR(32) NOT NULL UNIQUE,
	pwd VARCHAR(32) NOT NULL DEFAULT ''
)CHARACTER SET utf8;

-- 添加數據
INSERT INTO admin VALUES('tom','123');

-- 正常情況下,查找某個管理是否存在
SELECT * FROM admin
	WHERE NAME = 'tom' AND pwd = '123';
	
-- SQL註入
-- 輸入用戶名為  1' or 
-- 輸入密碼為  or '1'='1
-- 這樣就變成了下麵的語句,可以將所有的數據都查找出來
SELECT * FROM admin
	WHERE NAME = '1' OR' AND pwd = 'OR '1'='1';
image-20221014224056436

例子2-java程式演示SQL註入

package li.jdbc.statement;

//演示statement的註入問題

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

public class Statement_ {
    public static void main(String[] args) throws Exception {

        Scanner scanner = new Scanner(System.in);

        //讓用戶輸入管理員的名字和密碼
        System.out.print("請輸入管理員的名字:");
        String admin_name = scanner.nextLine();//如果希望看到SQL註入,這裡需要使用nextLine,如果用next():當接收到空格或者 '就是表示結束
        System.out.print("請輸入管理員的密碼:");
        String admin_pwd = scanner.nextLine();

        //通過Properties對象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //獲取相關的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.註冊驅動
        Class.forName(driver);
        //2.獲取連接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.得到Statement對象
        Statement statement = connection.createStatement();
        //4.組織SQL語句

        String sql = "select name,pwd from admin where name='"
                + admin_name + "' and pwd ='" + admin_pwd + "'";
        ResultSet resultSet = statement.executeQuery(sql);
        if (resultSet.next()) {//如果查詢到一條記錄,則說明該管理員存在
            System.out.println("恭喜,登錄成功");
        } else {
            System.out.println("對不起,登錄失敗");
        }

        //5.關閉連接
        resultSet.close();
        statement.close();
        connection.close();
    }
}
image-20221014182719032

5.PreparedStatement[預處理查詢]

image-20221014183841737
  • 基本介紹
  1. PreparedStatement執行的SQL語句中的 參數用問號(?)來表示,調用PreparedStatement對象的setXxx()方法來設置這些參數。

    setXxx()方法有兩個參數,第一個參數是要設置的SQL語句中的參數的索引(從1開始),第二個參數是設置的SQL語句中的參數的值

  2. 調用executeQuery(),返回ResultSet對象

  3. 調用executeUpdate():執行更新,包括增,刪,修改

  • 預處理的好處
  1. 不再使用+拼接sql語句,減少語法錯誤
  2. 有效地解決了SQL註入問題
  3. 大大減少了編譯次數,效率較高

例子-解決SQL註入問題

package li.jdbc.preparedstatement_;

import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

//演示PreparedStatement的使用
@SuppressWarnings("all")
public class PreparedStatement_ {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);

        //讓用戶輸入管理員的名字和密碼
        System.out.print("請輸入管理員的名字:");
        String admin_name = scanner.nextLine();
        System.out.print("請輸入管理員的密碼:");
        String admin_pwd = scanner.nextLine();

        //通過Properties對象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //獲取相關的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.註冊驅動
        Class.forName(driver);
        //2.獲取連接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.得到PreparedStatement對象
        //3.1組織SQL語句,sql語句的問號就相當於占位符
        String sql = "select name,pwd from admin where name= ? and pwd = ?";
        //3.2preparedStatement對象是實現了 PreparedStatement介面的 實現類的 對象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //3.3給 ? 賦值
        preparedStatement.setString(1,admin_name);
        preparedStatement.setString(2,admin_pwd);

        //4.執行select語句使用 executeQuery
        // 如果執行的是dml(update,insert,delete)語句使用executeUpdate
        // 這裡執行 executeQuery,不用再寫sql進去了
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {//如果查詢到一條記錄,則說明該管理員存在
            System.out.println("恭喜,登錄成功");
        } else {
            System.out.println("對不起,登錄失敗");
        }

        //5.關閉連接
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}
image-20221014190218693

5.1預處理DML

package li.jdbc.preparedstatement_;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Properties;
import java.util.Scanner;

//演示PreparedStatement的使用
@SuppressWarnings("all")
public class PreparedStatementDML_ {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);

        //讓用戶輸入管理員的名字和密碼
        System.out.print("請輸入管理員的名字:");
        String admin_name = scanner.nextLine();
//        System.out.print("請輸入管理員的密碼:");
//        String admin_pwd = scanner.nextLine();

        //通過Properties對象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //獲取相關的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.註冊驅動
        Class.forName(driver);
        //2.獲取連接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.得到PreparedStatement對象
        //3.1組織SQL語句,sql語句的問號就相當於占位符
        //添加記錄
        //String sql = "insert into admin values (?,?)";
        //更改
        //String sql = "update admin set pwd=? where name =?";
        //刪除
        String sql = "delete from admin where name=?";

        //3.2preparedStatement對象是實現了 PreparedStatement介面的 實現類的 對象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //3.3給 ? 賦值
        preparedStatement.setString(1, admin_name);
        // preparedStatement.setString(2, admin_pwd);

        //4.執行dml(update,insert,delete)語句使用executeUpdate
        int rows = preparedStatement.executeUpdate();
        System.out.println(rows > 0 ? "執行成功" : "執行失敗");

        //5.關閉連接
        preparedStatement.close();
        connection.close();
    }
}
image-20221014192148070
  • 練習

參考上面的代碼

  1. 創建admin表
  2. 使用PreparedStatement添加5條數據
  3. 修改tom的記錄,將name改成King
  4. 刪除一條記錄
  5. 查詢全部記錄,並顯示在控制台

6.JDBC API

7.JDBCUtils開發

7.1封裝JDBCUtils

  • 說明

在jdbc操作中,獲取連接和釋放資源是經常使用到的,可以將其封裝為JDBC連接的工具類JDBCUtils

image-20221014213412387

例子

封裝的工具類JDBCUtils:

package li.jdbc.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
 * 這是一個工具類,完成mysql的連接和關閉資源
 */
public class JDBCUtils {
    //定義相關的屬性(4個),因為只需要一份,因此我們將其做成static屬性
    private static String user;//用戶名
    private static String password;//密碼
    private static String url;//url
    private static String driver;//驅動名

    //在static代碼塊去初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\mysql.properties"));
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (IOException e) {
            //在實際開發中往往會這樣處理
            // 1.將 編譯異常 轉為 運行異常
            // 2.這時調用者可以選擇捕獲該異常,亦可以選擇預設處理該異常,比較方便
            // (對於運行異常,程式中如果沒有處理,預設就是throw的方式處理)
            throw new RuntimeException(e);
        }
    }

    //連接資料庫,返回Connection
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            //將 編譯異常 轉為 運行異常,原因同上
            throw new RuntimeException(e);
        }
    }

    //關閉相關資源
    /**
     * 1.ResultSet 結果集
     * 2.Statement 或者 PreparedStatement
     * 3.Connection
     * 4.如果需要關閉資源,就傳入對象,否則就傳入null
     */
    //這裡用Statement作為參數接收,是因為Statement是PreparedStatement的父介面,
    // 因此Statement參數既可以接收Statement的對象實現,也可以接收PreparedStatement類型的對象實現
    public static void close(ResultSet set, Statement statement, Connection connection) {
        //判斷是否為null
        try {
            if (set != null) {
                set.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            //將 編譯異常 轉為 運行異常,原因同上
            throw new RuntimeException(e);
        }
    }
}

使用測試JDBCUtils_Use:

package li.jdbc.utils;

import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * 該類演示如何使用JDBCUtils工具類,完成 dml和 select
 */
public class JDBCUtils_Use {

    @Test
    public void testSelect() {//insert update delete
        //1.得到連接
        Connection connection = null;

        //2.組織一個sql語句
        String sql = "Select * from actor";

        //3.創建PreparedStatement對象
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        try {
            connection = JDBCUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);

            //執行sql,得到結果集
            set = preparedStatement.executeQuery();
            //遍歷該結果集
            while (set.next()) {
                int id = set.getInt("id");
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //關閉資源
            JDBCUtils.close(set, preparedStatement, connection);
        }
    }

    @Test
    public void testDML() {//insert update delete
        //1.得到連接
        Connection connection = null;

        //2.組織一個sql語句
        String sql = "update actor set name=? where id=?";

        //3.創建PreparedStatement對象
        PreparedStatement preparedStatement = null;
        try {
            connection = JDBCUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            //給占位符賦值
            preparedStatement.setString(1, "周星星");//第1個占位符的值為周星星
            preparedStatement.setInt(2, 1);//第2個占位符的值為1
            //執行sql
            preparedStatement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //關閉資源
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

運行結果:

image-20221014222311448 image-20221014223453320 image-20221014222329046
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 需要工具: 1、apktool:獲取資源文件,提取圖片文件,佈局文件,還有一些XML的資源文件 2、dex2jar:將APK反編譯成Java源碼(將classes.dex轉化為jar文件) 3、**jd-gui:**查看轉換後的jar文件 1、使用apktool獲得資源文件以及xml文件 1.1、下 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 1.起因 最近有一個需求,需要使用自定義插件,來對接硬體功能,需要配合對手機的許可權進行判斷和提示,併在對接後對本地文件進行操作,這裡給大家分享下我的碰到的問題,廢話不多說,開搞 2.對接自定義插件,製作自定義基座 manifest.jso ...
  • 在 《JS 模塊化》系列開篇中,曾提到前端技術的發展不斷融入很多後端思想,形成前端的“四個現代化”:工程化、模塊化、規範化、流程化。在該系列文章中已詳細介紹了模塊化的發展及四種模塊化規範。本文簡單聊聊規範化中的 git 規範。 ...
  • 這段時間在開發一個騰訊文檔全品類通用的 HTML 動態服務,為了方便各品類接入的生成與部署,也順應上雲的趨勢,考慮使用 Docker 的方式來固定服務內容,統一進行製品版本的管理。本篇文章就將我在服務 Docker 化的過程中積累起來的優化經驗分享出來,供大家參考。 以一個例子開頭,大部分剛接觸 D ...
  • 1 什麼是流程引擎 流程引擎是一個底層支撐平臺,是為提供流程處理而開發設計的。流程引擎和流程應用,以及應用程式的關係如下圖所示。 常見的支撐場景有:Workflow、BPM、流程編排等。本次分享,主要從BPM流程引擎切入,介紹流程引擎的架構設計方法。 1.1 什麼是流程 簡單來說,流程就是一系列活動 ...
  • 顧名思義,迭代器就是用於迭代操作的對象,其能夠像有序序列一樣迭代獲取集合中對象,並且能夠記錄下當前所在位置,因此也稱游標。 ...
  • emqx連接啟用jwt令牌認證 jwt令牌 概述 JWT 即 JSON Web Tokens 是一種開放的,用於在兩方之間安全地表示聲明的行業標準的方法(RFC 7519)。 組成 令牌的形式 xxx.yyy.zzz eyJhbGciOiJIUzI1NiJ9 .eyJleHAiOjE2NjU0Nzc ...
  • 原文:JavaFx 使用字體圖標記錄 - Stars-One的雜貨小窩 之前其實也是研究過關於字體圖標的使用,還整了個庫Tornadofx學習筆記(4)——IconTextFx開源庫,整合5000+個字體圖標 - Stars-one - 博客園 由於之前並不是太過於講解字體圖標,最近又是抽空研究了一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...