JDBC 編程學(xué)習(xí)

前言

將最近學(xué)習(xí)的JDBC編程整理成筆記,做次記錄。

mysql 安裝

首先安裝mysql 8.0.19 版本數(shù)據(jù)庫(kù)。
下載地址 https://downloads.mysql.com/archives/community/
下載完成后點(diǎn)擊默認(rèn)安裝即可。

image.png
image.png

默認(rèn)安裝到了C:\Program Files\MySQL\MySQL Server 8.0\bin目錄下。
關(guān)于mysql的一些命令:

mysqld.exe --initialize-insecure 初始化數(shù)據(jù)庫(kù),執(zhí)行后會(huì)生成data文件夾
mysqld.exe --install  安裝mysql服務(wù)
net start mysql  啟動(dòng)mysql服務(wù)
set password for root@localhost = password('password');  修改密碼
flush privileges 刷新權(quán)限

JDBC 簡(jiǎn)介

JDBC全稱是Java DataBase Connectivity的縮寫,是Java程序訪問(wèn)數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)接口。
使用java里面提供的一些類和方法,利用程序鏈接數(shù)據(jù)庫(kù),進(jìn)行增刪改查,這個(gè)過(guò)程叫JDBC編程。
要實(shí)現(xiàn)JDBC編程,除了java.sql標(biāo)準(zhǔn)庫(kù),還需要找一個(gè)MySQL的JDBC驅(qū)動(dòng)。其實(shí)就是一個(gè)第三方j(luò)ar包。

這里下載mysql-connector-java-8.0.23 版本的jar包。 https://dev.mysql.com/downloads/connector/j/

下載后在eclipse 引入jar包。

image.png

并添加到項(xiàng)目庫(kù)。

image.png

JDBC 編程

JDBC編程主要分為六步操作:

  1. 加載驅(qū)動(dòng)程序
  2. 連接數(shù)據(jù)庫(kù)
  3. 獲取數(shù)據(jù)庫(kù)操作對(duì)象
  4. 執(zhí)行sql語(yǔ)句
  5. 處理查詢結(jié)果集
  6. 釋放連接

舉個(gè)栗子:
實(shí)現(xiàn)最簡(jiǎn)單的查詢語(yǔ)句

package jdbc_test;

import java.sql.*;

public class jdbcdemo01 {
    /**
     * 
     * @param username
     * @param password
     * @throws SQLException 
     */
    public static void main(String[] args) throws SQLException {
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");//加載驅(qū)動(dòng)
            
            String url = "jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF8&userSSL=true";
            String user = "root";
            String pass = "";
            conn = DriverManager.getConnection(url,user,pass);//獲取連接
            stmt = conn.createStatement();//獲取數(shù)據(jù)庫(kù)操作對(duì)象
            String sql = "select * from user";
            rs = stmt.executeQuery(sql);//執(zhí)行sql語(yǔ)句
            
            while(rs.next()) {
                System.out.print(rs.getInt(1)+","+rs.getString("username")+","+rs.getString(3)+","+rs.getString(4));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //釋放資源
            rs.close();
            stmt.close();
            conn.close();
        }
    }
}

注意:url地址的完整度,執(zhí)行查詢語(yǔ)句用的是executeQuery方法,以及驅(qū)動(dòng)連接用的是Class.forName()
還有一種方式也可以實(shí)現(xiàn)。

DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());// 第二種

new com.mysql.cj.jdbc.Driver()創(chuàng)建對(duì)象的時(shí)候本質(zhì)上也執(zhí)行了DriverManager.registerDriver(driver),這樣一來(lái)就重復(fù)了,所以我們更習(xí)慣使用Class.forName()

第二個(gè)例子,更新語(yǔ)句

package jdbc_test;

import java.sql.*;

public class jdbcdemo01 {
    /**
     * 
     * @param username
     * @param password
     * @throws SQLException 
     */
    public static void main(String[] args) throws SQLException {
        Connection conn=null;
        Statement stmt=null;
        
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");//加載驅(qū)動(dòng)
            String url = "jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF8&userSSL=true";
            String user = "root";
            String pass = "";
            conn = DriverManager.getConnection(url,user,pass);//獲取連接
            stmt = conn.createStatement();//獲取數(shù)據(jù)庫(kù)操作對(duì)象
            String sql = "update user set loginpwd=123456789 where id=1";
            int count = stmt.executeUpdate(sql);//執(zhí)行sql語(yǔ)句
            System.out.println(count == 1 ? "更新成功" : "更新失敗");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //釋放資源
            stmt.close();
            conn.close();
        }
    }
}

注意:更新方法用的是executeUpdate,包括插入、刪除、更新,并返回一個(gè)int值,所以自然也沒(méi)有查詢記過(guò)集
區(qū)分一下這兩個(gè)方法。

int executeUpdate(insert/delete/update)
Resultset executeQuery(select)

PreparedStatement 對(duì)象

在了解PreparedStatement對(duì)象之前,先設(shè)計(jì)一個(gè)登錄的demo,并嘗試一種工具類提取的方式編寫代碼。
首先新建db.properties文件,提取出連接數(shù)據(jù)庫(kù)的信息。

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/web?useUnicode=true&characterEncoding=UTF8&userSSL=true
username=root
password=

再提取出jdbc連接工具類JdbcUtils.java

package jdbc_test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.*;

// 提取工具類
public class JdbcUtils {
    private static String driver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;
    
    
    static {
        InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties = new Properties();
        try {
            properties.load(in);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            
            // 加載驅(qū)動(dòng)
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 獲取連接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }
    
    // 釋放連接資源
    public static void release(Connection conn,Statement st,ResultSet rs) {
            if(rs!=null) {try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }}
            if(st!=null) {try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }}
            if(conn!=null) {try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }}
    }

}

最后再編寫jdbcDemo3.java,來(lái)實(shí)現(xiàn)用戶登錄。
jdbcDemo3.java

package jdbc_test;

import java.sql.*;
import java.util.*;


public class jdbcdemo3 {
    
    public static void main(String[] args) {
        Map userlogininfo = loginit();
        String loginName = (String) userlogininfo.get("username");
        String loginPwd = (String) userlogininfo.get("password");
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            stmt = conn.createStatement();
            String sql = "select * from user where loginName='"+loginName+"' and loginPwd='"+loginPwd+"' ";
            rs = stmt.executeQuery(sql);
            if(rs.next()) {
                System.out.print("login success");
            }else {
                System.out.print("login false");
            }
        }catch (Exception e) {
             e.printStackTrace();
        }finally {
            JdbcUtils.release(conn, stmt, rs);
        }
    }
     private static Map loginit() {
            Scanner s = new Scanner(System.in);
            System.out.print("username:");
            String username = s.nextLine();
            System.out.print("password:");
            String password = s.nextLine();
            Map userlogininfo = new HashMap();
            userlogininfo.put("username",username);
            userlogininfo.put("password",password);
            return userlogininfo;
            
        }
}

嘗試登錄。

image.png

但是該編寫方式存在sql注入問(wèn)題,當(dāng)用戶輸入特殊的用戶名、密碼時(shí),也可以登錄成功。
a' or 1='1

image.png

這是因?yàn)檎嬷?or 真值 and 假值 or 真值,結(jié)果即為真值。會(huì)查詢出所有結(jié)果。

image.png

那么該如何解決sql注入的問(wèn)題呢?這就有了PreparedStatement 對(duì)象。
該對(duì)象用來(lái)防止sql注入,是Statement的子類,可對(duì)sql進(jìn)行預(yù)編譯,從而提高數(shù)據(jù)庫(kù)的執(zhí)行效率。
修改jdbcDemo3.java

package jdbc_test;

import java.sql.*;
import java.util.*;


public class jdbcdemo3 {
    
    public static void main(String[] args) {
        Map userlogininfo = loginit();
        String loginName = (String) userlogininfo.get("username");
        String loginPwd = (String) userlogininfo.get("password");
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            String sql = "select * from user where loginName = ? and loginPwd= ? ";
            //?代表占位符,不能使用單引號(hào)括起來(lái)
            stmt = conn.prepareStatement(sql);//sql語(yǔ)句的預(yù)先編譯
            //再給占位符傳值,即使再注入,sql語(yǔ)句也沒(méi)有編譯
            stmt.setString(1, loginName);
            stmt.setString(2, loginPwd);
            rs = stmt.executeQuery();//執(zhí)行sql語(yǔ)句
            if(rs.next()) {
                System.out.print("login success");
            }else {
                System.out.print("login false");
            }
        }catch (Exception e) {
             e.printStackTrace();
        }finally {
            JdbcUtils.release(conn, stmt, rs);
        }
    }
     private static Map loginit() {
            Scanner s = new Scanner(System.in);
            System.out.print("username:");
            String username = s.nextLine();
            System.out.print("password:");
            String password = s.nextLine();
            Map userlogininfo = new HashMap();
            userlogininfo.put("username",username);
            userlogininfo.put("password",password);
            return userlogininfo;
            
        }
}

注意:無(wú)法sql注入就是因?yàn)镻reparedStatement 對(duì)象在執(zhí)行sql語(yǔ)句時(shí)先進(jìn)行了預(yù)編譯

image.png

總結(jié)

學(xué)習(xí)了JDBC的基本過(guò)程,復(fù)習(xí)了db.properties文件、代碼層的sql注入,蠻有收獲,繼續(xù)加油。

參考資料

https://www.bilibili.com/video/BV1NJ411J79W?p=36

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容