MySQL中JDBC的預處理(防止sql語句的注入問題)

首先來看一下未經預處理的小程序,這個小程序是註冊和登錄功能,靜態的sql 語句,語法不確定性,通過 stmt 執行【Statement stmt 創建】,但這樣的話可能會給懂的一些語言的人輕鬆破解你賬戶的機會,所以MySQL爲了防止這種方式的發生,提供了一種預處理的機制PreparedStatement pstmt

package 未預處理的結果;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/**
 * @author Draco-_-
 * @see 未預處理的後果,stmt靜態語句,語法不確定性,可能會導致別人破解你的賬戶
 * @version
 * @date-time 2020-03-17 - 上午9:46:59
 */
public class Test {
	Scanner scanner = new Scanner(System.in);

	public static void main(String[] args) {

		Test t = new Test();
		System.out.println("歡迎來到小程序~~");
		System.out.println("1——>註冊");
		System.out.println("2——>登錄");
		System.out.println("0——>退出");
		System.out.print("請選擇功能序號:");
		int i = t.scanner.nextInt();
		switch (i) {
		case 1:
			t.zhuce();
			break;
		case 2:
			t.denglu();
			break;
		case 0:
			System.out.println("退出成功,歡迎下次再來~~");
			break;
		}

	}

	public void zhuce() {
		Connection conn;
		Statement stmt;// 不是預處理的,正常的
		ResultSet rs;

		String url = "jdbc:mysql://localhost:3308/crx654";
		String user = "root";
		String password = "mysql";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(url, user, password);
			stmt = conn.createStatement();
			System.out.println("歡迎來到註冊功能模塊");
			System.out.print("請輸入用戶名:");
			String name = scanner.next();
			System.out.print("請輸入密碼:");
			String psd = scanner.next();

			String sql = "insert into userinfo(username,psd) values('" + name + "','" + psd + "')";
			int i = stmt.executeUpdate(sql);
			if (i == 1) {
				System.out.println("操作成功");
			} else {
				System.out.println("操作失敗");
			}

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @see 此登錄方法只是簡單提供登錄失敗的信息
	 */
	public void denglu() {
		Connection conn;
		Statement stmt;// 不是預處理的,正常的
		ResultSet rs;

		String url = "jdbc:mysql://localhost:3308/user";
		String user = "root";
		String password = "mysql";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(url, user, password);
			stmt = conn.createStatement();
			System.out.println("歡迎來到登錄功能模塊");
			System.out.print("請輸入用戶名:");
			String name = scanner.next();
			System.out.print("請輸入密碼:");
			String psd = scanner.next();

			String sql = "select * from userinfo where username='" + name + "' and psd='" + psd + "'";
			rs = stmt.executeQuery(sql);
			if (rs.next()) {
				System.out.println("登錄成功");
			} else {
				System.out.println("登錄失敗");
			}

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

經過預處理之後的jdbc代碼,只需要更換【Statement stmt; 】——>【PreparedStatement pstmt;】,其他的 jdbc 順序不變

package jdbc的預處理;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * @author Draco-_-
 * @see 經過PreparedStatement預處理的jdbc語句,動態的語句,語法先確定,不會影響sql的語法,避免了sql的注入問題
 * @version 
 * @date-time 2020-03-17 - 下午7:37:25
 */
public class Test {

	Scanner scanner = new Scanner(System.in);

	public static void main(String[] args) {

		Test t = new Test();
//		t.zhuce();
		t.denglu();
		
	}

	public void zhuce() {
		Connection conn;
		PreparedStatement pstmt;// 是經過預處理的
//		Statement stmt;// 不是預處理的,正常的

		String url = "jdbc:mysql://localhost:3308/crx654";
		String user = "root";
		String password = "mysql";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(url, user, password);
			//變量用?代替
			String sql = "insert into userinfo(username,psd) values(?,?)";
			
			pstmt = conn.prepareStatement(sql);// 直接要sql語句來預編譯
			System.out.println("歡迎來到註冊功能模塊");
			System.out.print("請輸入用戶名:");
			String name = scanner.next();
			System.out.print("請輸入密碼:");
			String psd = scanner.next();
			
			//給兩個??賦值
			pstmt.setString(1, name);//第一個
			pstmt.setString(2, psd);//第二個

			int i = pstmt.executeUpdate();
			if (i == 1) {
				System.out.println("操作成功");
			} else {
				System.out.println("操作失敗");
			}

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void denglu() {
		Connection conn;
		PreparedStatement pstmt;// 是經過預處理的
//		Statement stmt;// 不是預處理的,正常的
		ResultSet rs;

		String url = "jdbc:mysql://localhost:3308/user";
		String user = "root";
		String password = "mysql";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(url, user, password);
			//變量用?代替
			String sql = "select * from userinfo where username=? and psd=?";
			
			pstmt = conn.prepareStatement(sql);// 直接要sql語句來預編譯
			System.out.println("歡迎來到登錄功能模塊");
			System.out.print("請輸入用戶名:");
			String name = scanner.next();
			System.out.print("請輸入密碼:");
			String psd = scanner.next();
			
			//給兩個??賦值
			pstmt.setString(1, name);//第一個
			pstmt.setString(2, psd);//第二個

			rs = pstmt.executeQuery();
			if(rs.next()) {
				System.out.println("登錄成功");
			}else {
				System.out.println("登錄失敗");
			}

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

}

最後,上面的兩個Java的運行的效果是一樣的,但是大家不覺得這樣寫 jdbc 代碼會冗餘嗎,所以下一篇將會寫一篇關於 jdbc 封裝的博文,到時候會給一個鏈接的。
謝謝觀看,如有錯誤,還請不吝賜教

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章