MySQL JDBC常用知識,封裝工具類,時區問題配置,SQL隱碼攻擊問題

南城小友發表於2022-03-28

JDBC


JDBC介紹

Sun公司為了簡化開發人員的(對資料庫的統一)操作,提供了(Java運算元據庫的)規範,俗稱JDBC,這些規範的由具體由具體的廠商去做
對於開發人員來說,我們只需要掌握JDBC介面的操作即可

image

所需要的jar包

  • java.sql(預設有)
  • javax.sql(預設有)
    還需要匯入資料庫驅動包

java程式連結mySQL

注意! 增刪改操作都需要提交事務

步驟:

  1. 載入驅動
  2. 登陸連結資料庫物件
  3. 建立statement物件,用於執行sql語句 statement(清單)
  4. 執行sql語句
  5. 返回結果集,結果集中封裝了我們查詢的所有結果
  6. 釋放連結
 // 1.載入驅動
        Class.forName("com.mysql.jdbc.Driver");
                      //協議://主機:埠/資料庫名?編碼設定&使用安全的連結
        String url = "url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true";
        String use = "root";  //使用者名稱
        String password = "123456";  //密碼
        //2.登陸連結資料庫物件
        Connection connection = DriverManager.getConnection(url, use, password);
        //3.建立statement物件,用於執行sql語句   statement(清單)
        Statement statement = connection.createStatement();
        //4.執行sql語句
        String sql = "SELECT * from class"; //sql語句
        //5.返回結果集,結果集中封裝了我們查詢的所有結果
        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            System.out.println("classno:"+resultSet.getNString("classno"));
            System.out.println("classname:"+resultSet.getNString("classname"));
            System.out.println("department:"+resultSet.getNString("department"));
            System.out.println("monitor(班長):"+resultSet.getNString("monitor(班長)"));
            System.out.println("==========================================================");
        }
        //6.釋放連結
        resultSet.close();
        statement.close();
        connection.close();
    }
}

幾個重要物件

DirverManager 驅動管理

Class.forName("com.mysql.jdbc.Driver");
DriverManager.registerDriver(new Driver()); //這是Driver原始碼

URL 資源地址

//協議://主機:埠/資料庫名?時區設定&編碼設定&使用安全的連結
String url = "url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true";

Connection 連結物件,運算元據庫的物件

connection.commit();  //提交事務
connection.rollback();   //回滾事務
connection.setAutoCommit();  //自動提交事務

/* Statemen 清單,執行sql的物件  */
```java
statement.executeQuery("sql");   //執行查詢,返回結果集
statement.executeUpdate("sql");  //執行更新(插入和刪除也算更新),返回受影響的行數
statement.execute("sql");  //執行全部的sql語句

ResultSet:查詢後的結果集

獲取資料:

resultSet.getNString();
resultSet.getObject();  //不知道什麼型別的情況下使用
resultSet.getInt();
resultSet.getDate();
resultSet.getFloat();

指標移動:

resultSet.next();
resultSet.previous();
resultSet.absolute();
resultSet.beforeFirst();
resultSet.afterLast();

關閉連結

resultSet.close();
statement.close();
connection.close();

SQL隱碼攻擊的問題

SQL隱碼攻擊即是指web應用程式對使用者輸入資料的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程式中事先定義好的查詢語句的結尾上新增額外的SQL語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙資料庫伺服器執行非授權的任意查詢,從而進一步得到相應的資料資訊。
即:通過sql語句的漏洞來實現一些非法操作.

// 欲根據使用者id來進行獲取使用者的其他資訊,但是使用如下語句就會將所有使用者的資訊都查詢到
select * from db01.user where (id =' 'or 1=1)";   --sql注入
PreparedStatement物件

可以防止sql注入,並且效率更高,如:在編輯sql語句時使用?代表佔位符,並且預編譯sql語句,隨後在設定引數防止sql注入

常用方法:
preparedStatement.executeQuery();
preparedStatement.executeUpdate();
preparedStatement.setString(); //給引數傳遞字串型別的值
preparedStatement.setInt();  //給引數傳遞 int 型別的值
preparedStatement.setDate();  //給引數傳遞 Date 型別的值
... 等等

例子:

//帶引數的sql語句
String sql = "select * from db01.user where(id = ?)" ;
//預編譯sql語句並且返回一個PreparedStatement物件
preparedStatement = con.prepareStatement(sql);
//給引數傳遞值(適當的使用對應型別的方法能提高效率)
preparedStatement.setString(1,id);  //注意下標從1開始
//執行sql語句
resultSet = preparedStatement.executeQuery();

解藕,封裝工具類

我們可以將配置資訊編寫成配置檔案(xxx.properties),然後通過Properties類讀取檔案內容對應引數來配置資訊

配置檔案db.properties, 我們需要將此配置檔案放入位元組碼的相同路徑(maven專案的resources目錄下)

# 驅動類名
driver=com.mysql.cj.jdbc.Driver
# //協議://主機:埠/資料庫名?設定時區&編碼設定&使用安全的連結協議
url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true
user=root
password=123456

JdbcUtil類

package SQL_injection;

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

public class JdbcUtility {
// 初始化變數,並且避免作用域問題
    static Properties properties = new Properties();
    static Connection con = null;
    static PreparedStatement preparedStatement = null;
    static ResultSet resultSet = null;
    static String username = null;
    static String password = null;

    //初始化配置
    static {
        // 獲取輸入流, 通過此類的類載入器獲取類載入路徑,進而獲取到配置檔案的輸入流
        InputStream in = JdbcUtility.class.getClassLoader().getResourceAsStream("db.properties");
        try {
            // 通過properties物件載入配置檔案的輸入流
            properties.load(in);
//相當於載入驅動Class.forName("com.mysql.jdbc.Driver"); 只不過是將配置檔案的driver引數獲取出來           
            JdbcUtility.class.forName(properties.getProperty("driver"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     //使用配置檔案內容資訊連結資料庫
    public JdbcUtility(){
        try {
            //獲取配置檔案資訊
            String url = properties.getProperty("url");
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            // 根據引數連結資料庫
             con = DriverManager.getConnection(url,user,password);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

     //使用自定義的使用者名稱和密碼登陸資料庫
     public JdbcUtility(String username,String password){
        try {
            con = DriverManager.getConnection(properties.getProperty("url"), username, password);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    public boolean select(String id){
        String sql = "select * from db01.user where(id = ?)" ;

        //執行查詢語句
        try {
            preparedStatement = con.prepareStatement(sql);
            preparedStatement.setString(1,id);
            resultSet = preparedStatement.executeQuery();
            if(!resultSet.next()) {
                System.out.println("查詢失敗!");
                return false;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return true;
    }

    public void getResult(){
        try {
            do {
                System.out.print("id:"+resultSet.getString(1)+"\t");
                //System.out.println("password:"+resultSet.getString(0)+"\t");
                System.out.print("name:"+resultSet.getString(3)+"\t");
                System.out.print("sex:"+resultSet.getString(4)+"\t");
                System.out.print("birthday:"+resultSet.getString(5)+"\t");
                System.out.println();
            }
            while (resultSet.next());
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }

    public void insert(String id ,String name,String sex ){
            String sql = "insert into db01.user (id,name,sex,birthday) " +
                    "values(?,?,?,?)" ;
        try {
            preparedStatement = con.prepareStatement(sql);

            preparedStatement.setString(1,id);
            preparedStatement.setString(2,name);
            preparedStatement.setString(3,sex);
            Date date = new Date(new java.util.Date().getTime());
            preparedStatement.setDate(4,date);

            int n = preparedStatement.executeUpdate();
            if (n == 0) System.out.println("插入失敗!");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    //刪除
    public void delete(String id){
        String sql = "delete from db01.user where(id = ?);" ;
        try {
            preparedStatement  = con.prepareStatement(sql);
            preparedStatement.setString(1,id);
            if (preparedStatement.executeUpdate()==0) System.out.println("刪除失敗!");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    public void update(String id,String columnname,String value){
        String sql = "update db01.user set "+columnname +" = ? where (id = ? )" ;
        try {
            preparedStatement = con.prepareStatement(sql);
            //preparedStatement.setString(1,columnname);
            preparedStatement.setString(1,value);
            preparedStatement.setString(2,id);

            if(preparedStatement.executeUpdate()==0) System.out.println("更新失敗");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }


    }

    //關閉
    public void  close(){
        try {
            resultSet.close();
            con.close();
            preparedStatement.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }


}

JDBC操作事務

注意! 增刪改操作都需要提交事務

常用方法
connection.setAutoCommit(boolean flag); //設定事務是否自動提交,預設是提交的
connection.commit(); //提交事務
connection.rollback(); //回滾事務,一般不用設定,事務一般傳送錯誤會自動回滾

下面程式碼是模擬一筆轉賬操作,A賬戶減少100元,B賬戶增加100元,兩個sql操作為一個事務,同時執行成功或者失敗(失敗事務發生回滾)

 JdbcUtility jdbc = new JdbcUtility();
 try {
     //關閉自動提交事務
     jdbc.con.setAutoCommit(false);
     //進行一筆轉賬操作,其中update()方法,引數1代表付款或者收款人,引數2代表是否收款
     jdbc.update("A",true);
     jdbc.update("B",false);
     //提交一筆轉賬事務
     jdbc.con.commit();
     
 } catch (SQLException throwables) {
     try {
         //實際上事務會自動回滾當出現錯誤時
         jdbc.con.rollback();
     } catch (SQLException e) {
         e.printStackTrace();
     }
     throwables.printStackTrace();
 }

相關文章