使用PreparedStatement實現CRUD操作

qq_45126061發表於2020-09-28

操作和訪問資料庫

資料庫連線被用於向資料庫伺服器傳送命令和 SQL 語句,並接受資料庫伺服器返回的結果。其實一個資料庫連線就是一個Socket連線。

在 java.sql 包中有 3 個介面分別定義了對資料庫的呼叫的不同方式:

  • Statement:用於執行靜態 SQL 語句並返回它所生成結果的物件。
  • PrepatedStatement:SQL 語句被預編譯並儲存在此物件中,可以使用此物件多次高效地執行該語句。
  • CallableStatement:用於執行 SQL 儲存過程

使用Statement運算元據表的弊端

通過呼叫 Connection 物件的 createStatement() 方法建立該物件。該物件用於執行靜態的 SQL 語句,並且返回執行結果。

Statement介面中定義了下列方法用於執行SQL語句:

int excuteUpdate(String sql):執行更新操作INSERT、UPDATE、DELETE 
ResultSet executeQuery(String sql):執行查詢操作SELECT

但是使用Statement運算元據表存在弊端:
1.存在拼串操作,繁瑣
2.存在SQL隱碼攻擊問題

SQL隱碼攻擊問題:

SQL 注入是利用某些系統沒有對使用者輸入的資料進行充分的檢查,而在使用者輸入資料中注入非法的 SQL 語句段或命令(如:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' ='1') ,從而利用系統的 SQL 引擎完成惡意行為的做法。

對於 Java 而言,要防範 SQL 注入,只要用 PreparedStatement(從Statement擴充套件而來) 取代 Statement 就可以了。

PreparedStatement的使用

PreparedStatement介紹

  1. PreparedStatement 介面是 Statement 的子介面,它表示一條預編譯過的 SQL 語句
  2. PreparedStatement 物件所代表的 SQL 語句中的引數用問號(?)來表示,呼叫 PreparedStatement 物件的setXxx() 方法來設定這些引數. setXxx() 方法有兩個引數,第一個引數是要設定的 SQL 語句中的引數的索引(從 1開始),第二個是設定的 SQL 語句中的引數的值
  3. 可以通過呼叫 Connection 物件的 preparedStatement(String sql) 方法獲取 PreparedStatement 物件

PreparedStatement vs Statement

Java與SQL對應資料型別轉換表

Java型別SQL型別
booleanBIT
byteTINYINT
shortSMALLINT
intINTEGER
longBIGINT
StringCHAR,VARCHAR,LONGVARCHAR
byte arrayBINARY,VAR BINARY
java.sql.DateDATE
java.sql.TimeTIME
java.sql.TimestampTIMESTAMP

使用PreparedStatement實現增,刪,改操作

使用PreparedStatement實現增、刪、改操作

	public void update(String sql,Object ...args){//sql中佔位符的個數與可變形參的長度相同!
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.獲取資料庫的連線
			conn = JDBCUtils.getConnection();
			//2.預編譯sql語句,返回PreparedStatement的例項
			ps = conn.prepareStatement(sql);
			//3.填充佔位符
			for(int i = 0;i < args.length;i++){
				ps.setObject(i + 1, args[i]);//小心引數宣告錯誤!!
			}
			//4.執行sql語句
			ps.execute();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//5.資源的關閉
			JDBCUtils.closeResource(conn, ps);
			
		}	
	}

使用PreparedStatement實現查詢操作

public <T> T getInstance(Class<T> clazz,String sql,Object ...args){
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;

        try {
            //獲取資料庫連線
            conn= JDBCUtils.getConnection();
            //預編譯sql語句,得到PreparedStatement物件
            ps=conn.prepareStatement(sql);
            //填充佔位符
            for(int i=0;i<args.length;i++){
                ps.setObject(i+1,args[i]);
            }
            //執行executeQuery(),得到結果集:ResultSet
            rs=ps.executeQuery();
            //獲取結果集的後設資料:ResultSetMetaData
            ResultSetMetaData rsmd=rs.getMetaData();
            //通過ResultSetMetaData獲取結果集的列數
            int columnCount=rsmd.getColumnCount();
            if(rs.next()){
                T t=clazz.newInstance();
                //處理結果集一行資料中的每一列
                for (int i=0;i<columnCount;i++){
                    //獲取列值
                    Object columValue=rs.getObject(i+1);
                    //獲取每個列的列名
                    String columnName=rsmd.getColumnName(i+1);
                    String columnLable=rsmd.getColumnLabel(i+1);
                    //使用反射,給物件的相應屬性賦值射
                    Field field=clazz.getDeclaredField(columnLable);
                    field.setAccessible(true);
                    field.set(t,columValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關閉資源
            JDBCUtils.closeResource(conn,ps,rs);
        }
        return null;
    }

ResultSet和ResultSetMetaData

ResultSet

  1. 查詢需要呼叫PreparedStatement 的 executeQuery() 方法,查詢結果是一個ResultSet 物件
  2. ResultSet 物件以邏輯表格的形式封裝了執行資料庫操作的結果集,ResultSet 介面由資料庫廠商提供實現
  3. ResultSet 物件維護了一個指向當前資料行的遊標,初始的時候,遊標在第一行之前,可以通過 ResultSet 物件的 next() 方法移動到下一行。呼叫 next()方法檢測下一行是否有效。若有效,該方法返回 true,且指標下移。相當於Iterator物件的 hasNext() 和 next() 方法的結合體
  4. 當指標指向一行時, 可以通過呼叫 getXxx(int index) 或 getXxx(int columnName) 獲取每一列的值
  5. ResultSet介面的常用方法:

注意:
Java與資料庫互動涉及到的相關Java API中的索引都從1開始

在這裡插入圖片描述

相關文章