最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JDBC中PreparedStatement詳解以及應用場景實例介紹

 更新時間:2024年02月13日 09:11:35   作者:@泡泡糖  
PreparedStatement對象代表的是一個預編譯的SQL語句,用它提供的setter方法可以傳入查詢的變量,這篇文章主要給大家介紹了關(guān)于JDBC中PreparedStatement詳解以及應用場景實例介紹的相關(guān)資料,需要的朋友可以參考下

前言

在Java中,當需要向數(shù)據(jù)庫中執(zhí)行SQL語句并傳遞參數(shù)時,我們通常會使用PreparedStatement接口。PreparedStatement繼承自Statement接口,用于預編譯SQL語句并執(zhí)行參數(shù)化查詢,這樣可以提高執(zhí)行效率并防止SQL注入攻擊。

1、PreparedStatement介紹

PreparedStatement是Java JDBC API的一部分,它提供了一種更有效率和安全的方式來向SQL語句傳遞參數(shù)。PreparedStatement允許我們執(zhí)行帶有動態(tài)參數(shù)的SQL語句,這些參數(shù)可以在執(zhí)行SQL語句之前預編譯,從而提高執(zhí)行效率。PreparedStatement對象可以通過Connection對象創(chuàng)建,并接受一條SQL語句作為參數(shù)。

PreparedStatement接口中定義了一系列用于設置參數(shù)的方法,包括setInt、setString、setDate等等,這些方法用于指定預編譯的SQL語句中的參數(shù)值。PreparedStatement還提供了一種用于執(zhí)行查詢的方法executeQuery(),以及用于執(zhí)行非查詢的方法executeUpdate()。

2、與Statement相比,PreparedStatement有以下優(yōu)點:

1.更高的執(zhí)行效率

當需要執(zhí)行多次相同的SQL語句時,PreparedStatement能夠?qū)QL語句預編譯,從而提高執(zhí)行效率。PreparedStatement對象在創(chuàng)建時,會將SQL語句編譯成一種可重用的二進制格式,當調(diào)用execute()方法時,直接傳遞參數(shù)即可執(zhí)行SQL語句,這比Statement每次都需要解析SQL語句要更加高效。

2.防止SQL注入攻擊

使用Statement執(zhí)行動態(tài)SQL語句時,需要將參數(shù)值拼接到SQL語句中,這樣容易受到SQL注入攻擊。而PreparedStatement通過參數(shù)化查詢的方式,將參數(shù)值作為參數(shù)傳遞給SQL語句,從而避免了SQL注入攻擊。

3.增加了代碼的可讀性

PreparedStatement的代碼更加簡潔明了,可以使代碼更易于理解和維護。

3、PreparedStatement的應用場景

PreparedStatement適用于執(zhí)行需要傳遞參數(shù)的SQL語句,特別是當需要執(zhí)行多次相同的SQL語句時,PreparedStatement能夠大大提高執(zhí)行效率。下面是PreparedStatement的一些常見應用場景: 

 通用的增、刪、改操作,可以直接調(diào)用此方法 

	public void update(String sql,Object ... args){
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.獲取數(shù)據(jù)庫的連接
			conn = JDBCUtils.getConnection();
			
			//2.獲取PreparedStatement的實例 (或:預編譯sql語句)
			ps = conn.prepareStatement(sql);
			//3.填充占位符
			for(int i = 0;i < args.length;i++){
				ps.setObject(i + 1, args[i]);
			}
			
			//4.執(zhí)行sql語句
			ps.execute();
		} catch (Exception e) {	
			e.printStackTrace();
		}finally{
			//5.關(guān)閉資源
			JDBCUtils.closeResource(conn, ps);
			
		}
	}

1)增加表數(shù)據(jù):

String sql = "update students set grade = ? where id = ?";
update(sql,4,90);

   2)更新表數(shù)據(jù):

String sql = "update students set grade = ? where id = ?";
update(sql,4,90);

 3) 刪除表數(shù)據(jù):

String sql = "delete from students where id = ?";
update(sql,4);

4、使用PreparedStatement實現(xiàn)查詢操作

首先我們需要學習一種思想:

ORM思想(object relational mapping)
        一個數(shù)據(jù)表對應一個java類
        表中的一條記錄對應java類的一個對象
        表中的一個字段對應java類的一個屬性

 我們首先新建一個students類,內(nèi)容如下:

public class Students {
    private int id;
    private String name;
    private int grade;
 
    public Students() {
    }
 
    public Students(int id, String name, int grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getGrade() {
        return grade;
    }
 
    public void setGrade(int grade) {
        this.grade = grade;
    }
 
    @Override
    public String toString() {
        return id+","+name+","+grade;
    }
}

 1)單條數(shù)據(jù)的查詢

// 通用的針對于不同表的查詢:返回一個對象 (version 1.0)
	public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
 
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			// 1.獲取數(shù)據(jù)庫連接
			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.執(zhí)行executeQuery(),得到結(jié)果集:ResultSet
			rs = ps.executeQuery();
 
			// 5.得到結(jié)果集的元數(shù)據(jù):ResultSetMetaData
			ResultSetMetaData rsmd = rs.getMetaData();
 
			// 6.1通過ResultSetMetaData得到columnCount,columnLabel;通過ResultSet得到列值
			int columnCount = rsmd.getColumnCount();
			if (rs.next()) {
				T t = clazz.newInstance();
				for (int i = 0; i < columnCount; i++) {// 遍歷每一個列
 
					// 獲取列值
					Object columnVal = rs.getObject(i + 1);
					// 獲取列的別名:列的別名,使用類的屬性名充當
					String columnLabel = rsmd.getColumnLabel(i + 1);
					// 6.2使用反射,給對象的相應屬性賦值
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnVal);
 
				}
				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7.關(guān)閉資源
			JDBCUtils.closeResource(conn, ps, rs);
		}
		return null;
	}

  調(diào)用上面的方法,實現(xiàn)查詢單條記錄:

String sql = "select * from students where id = ?";
Students s = getInstance(Students.class,sql,3);
System.out.println(s);

 2)多條數(shù)據(jù)的查詢

public <T> List<T> getForList(Class<T> clazz, String sql, Object... args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //1.獲取數(shù)據(jù)庫連接
            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.執(zhí)行executeQuery(),得到結(jié)果集:resultset
            rs = ps.executeQuery();
            //5.獲取結(jié)果集的元數(shù)據(jù)ResultSetMetaData
            ResultSetMetaData rsmd =  rs.getMetaData();
            //6.通過獲取ResultSetMetaData結(jié)果集的列數(shù)
            int columnCount = rsmd.getColumnCount();
            //7.創(chuàng)建集合對象
            ArrayList<T> list = new ArrayList<T>();
 
            while (rs.next()){
                T t = clazz.newInstance();
                //處理結(jié)果集一行數(shù)據(jù)中的每一個列
                for (int i = 0; i < columnCount; i++) {
                    Object value = rs.getObject(i+1);
 
                    //獲取每個列的別名getColumnLabel---針對于表的字段名和類的屬性名不同
                    String columnName = rsmd.getColumnLabel(i+1);
 
                    //給s對象指定的某個屬性,賦值為value
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,value);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(conn,ps,rs);
        }
        return null;
    }

調(diào)用上面的方法,實現(xiàn)查詢多條記錄:

String sql = "select * from students";
List<Students> list = getForList(Students.class,sql);
list.forEach(System.out::println);

PreparedStatement的注意事項

1.SQL注入攻擊

雖然PreparedStatement可以有效地防止SQL注入攻擊,但是在設置參數(shù)時也要注意一些細節(jié)。例如,在使用setString()方法設置字符串類型的參數(shù)時,應該使用單引號將字符串括起來。否則,可能會造成SQL語句語法錯誤。

PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE username = ?"); 

pstmt.setString(1, "張三"); //正確方式 
pstmt.setString(1, 張三); //錯誤方式

2.資源的釋放

與Statement一樣,使用完P(guān)reparedStatement對象后,我們也需要手動關(guān)閉對象以釋放資源,防止資源泄露。

關(guān)閉PreparedStatement對象可以調(diào)用PreparedStatement對象的close()方法。

下面是一個使用PreparedStatement的示例代碼:

public void queryUsersByName(String name) throws SQLException {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    try {
        conn = getConnection();
        String sql = "SELECT * FROM users WHERE name = ?";
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, name);
        rs = pstmt.executeQuery();

        while (rs.next()) {
            // 處理結(jié)果集
        }
    } finally {
        // 釋放資源
        if (rs != null) {
            rs.close();
        }
        if (pstmt != null) {
            pstmt.close();
        }
        if (conn != null) {
            conn.close();
        }
    }
}

在finally塊中,我們按照ResultSet、PreparedStatement、Connection的順序關(guān)閉對象。使用try-finally塊可以確保即使在處理過程中出現(xiàn)異常,也能夠及時關(guān)閉對象以釋放資源。

3.批處理操作

批處理是指一次向數(shù)據(jù)庫發(fā)送多條 SQL 語句進行執(zhí)行的操作,可以有效提高數(shù)據(jù)庫操作效率。在使用 Statement 執(zhí)行批處理時,需要在 SQL 語句中使用分號(;)來分隔多個 SQL 語句,但是在使用 PreparedStatement 執(zhí)行批處理時,只需要在多次調(diào)用 addBatch() 方法時,傳入不同的 SQL 語句即可。

以下是一個 PreparedStatement 批處理的示例:

String sql = "INSERT INTO users(name, age) VALUES(?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
for(int i=0; i<10; i++){
    ps.setString(1, "user"+i);
    ps.setInt(2, i);
    ps.addBatch();
}
int[] result = ps.executeBatch();

4.數(shù)據(jù)庫事務

事務是指一組操作,要么全部執(zhí)行成功,要么全部執(zhí)行失敗。在數(shù)據(jù)庫操作中,事務通常用于保證數(shù)據(jù)的一致性和完整性,一旦某個操作失敗,整個事務將回滾到最初狀態(tài),所有操作都將失效。

在使用 PreparedStatement 進行數(shù)據(jù)庫操作時,可以結(jié)合事務來保證數(shù)據(jù)的一致性和完整性。在 JDBC 中,事務的使用可以通過 Connection 對象來實現(xiàn),其核心方法如下:

  • setAutoCommit(boolean autoCommit): 設置是否自動提交事務,默認值為 true,即自動提交。
  • commit(): 手動提交事務。
  • rollback(): 回滾事務。

以下是一個 PreparedStatement 結(jié)合事務的示例:

Connection conn = null;
PreparedStatement ps = null;
try{
    conn = getConnection();
    // 關(guān)閉自動提交,開啟事務
    conn.setAutoCommit(false);
    String sql = "INSERT INTO users(name, age) VALUES(?,?)";
    ps = conn.prepareStatement(sql);
    ps.setString(1, "user1");
    ps.setInt(2, 20);
    ps.executeUpdate();
    ps.setString(1, "user2");
    ps.setInt(2, 30);
    ps.executeUpdate();
    // 手動提交事務
    conn.commit();
}catch(SQLException e){
    // 回滾事務
    if(conn != null){
        try{
            conn.rollback();
        }catch(SQLException ex){
            ex.printStackTrace();
        }
    }
    e.printStackTrace();
}finally{
    JdbcUtils.release(conn, ps, null);
}

總結(jié)

PreparedStatement 是一種高效、安全、易用的數(shù)據(jù)庫操作方式,具有多種優(yōu)點,如可防止 SQL 注入攻擊、支持參數(shù)化查詢、可以重復使用等。在實際開發(fā)中,建議優(yōu)先選擇使用 PreparedStatement 進行數(shù)據(jù)庫操作。

如果還有其他問題或需要進一步了解 PreparedStatement,可以查閱 JDK API 文檔或者其他相關(guān)資料。

相對于Statement,PreparedStatement的優(yōu)點是什么?

1、PreparedStatement有助于防止SQL注入,因為它會自動對特殊字符轉(zhuǎn)義。

2、PreparedStatement可以用來進行動態(tài)查詢。

3、PreparedStatement執(zhí)行更快。尤其當你重用它或者使用它的拼量查詢接口執(zhí)行多條語句時。

4、使用PreparedStatement的setter方法更容易寫出面向?qū)ο蟮拇a,而Statement的話,我們得拼接字符串來生成查詢語句。

如果參數(shù)太多了,字符串拼接看起來會非常丑陋并且容易出錯。

到此這篇關(guān)于JDBC中PreparedStatement詳解以及應用場景實例介紹的文章就介紹到這了,更多相關(guān)JDBC中PreparedStatement詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于java數(shù)組與字符串相互轉(zhuǎn)換的問題

    關(guān)于java數(shù)組與字符串相互轉(zhuǎn)換的問題

    這篇文章主要介紹了java數(shù)組與字符串相互轉(zhuǎn)換的問題,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • SpringCloud之Feign遠程接口映射的實現(xiàn)

    SpringCloud之Feign遠程接口映射的實現(xiàn)

    這篇文章主要介紹了SpringCloud之Feign遠程接口映射的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • java swing中實現(xiàn)拖拽功能示例

    java swing中實現(xiàn)拖拽功能示例

    這篇文章主要介紹了java swing中實現(xiàn)拖拽功能示例,需要的朋友可以參考下
    2014-04-04
  • Java實現(xiàn)二維碼、條形碼功能(案例代碼)

    Java實現(xiàn)二維碼、條形碼功能(案例代碼)

    ZXing是一個開放源碼的,用Java實現(xiàn)的多種格式的1D/2D條碼圖像處理庫,它包含了聯(lián)系到其他語言的端口,Zxing可以實現(xiàn)使用手機的內(nèi)置的攝像頭完成條形碼的掃描及解碼,這篇文章主要介紹了Java實現(xiàn)二維碼、條形碼等功能,需要的朋友可以參考下
    2024-01-01
  • SpringBoot自定義啟動器Starter流程詳解

    SpringBoot自定義啟動器Starter流程詳解

    SpringBoot中的starter是一種非常重要的機制,能夠拋棄以前繁雜的配置,將其統(tǒng)一集成進starter,應用者只需要在maven中引入starter依賴,SpringBoot就能自動掃描到要加載的信息并啟動相應的默認配置。starter讓我們擺脫了各種依賴庫的處理,需要配置各種信息的困擾
    2022-11-11
  • 一文徹底搞懂Java和JDK的版本命名問題

    一文徹底搞懂Java和JDK的版本命名問題

    今天通過本文給大家分享我對Java的版本號以及JDK的命名的了解,通過實例圖文展示給大家介紹的非常詳細,需要的朋友跟隨小編一起看看吧
    2021-06-06
  • Java實現(xiàn)控制臺輸出兩點間距離

    Java實現(xiàn)控制臺輸出兩點間距離

    這篇文章主要介紹了Java實現(xiàn)控制臺輸出兩點間距離,涉及了部分編程坐標的問題,具有一定參考價值,需要的朋友可以了解下
    2017-09-09
  • 如何正確控制springboot中bean的加載順序小結(jié)篇

    如何正確控制springboot中bean的加載順序小結(jié)篇

    這篇文章主要介紹了如何正確控制springboot中bean的加載順序總結(jié),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • 一文探索Java文件讀寫更高效方式

    一文探索Java文件讀寫更高效方式

    這篇文章主要介紹了一文探索Java文件讀寫更高效方式,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值需要的小伙伴可以參考一下
    2022-07-07
  • Java反射獲取所有Controller和RestController類的方法

    Java反射獲取所有Controller和RestController類的方法

    這篇文章給大家分享了Java反射獲取所有Controller和RestController類的方法,文中有詳細的代碼示例講解,具有一定的參考價值,需要的朋友可以參考下
    2023-08-08

最新評論

土默特左旗| 双峰县| 新泰市| 扎囊县| 即墨市| 历史| 蒙阴县| 彰化市| 班戈县| 嵊州市| 新干县| 太湖县| 堆龙德庆县| 明光市| 大安市| 奉化市| 公主岭市| 金湖县| 桐城市| 平遥县| 安化县| 揭西县| 襄汾县| 南江县| 焦作市| 松溪县| 二连浩特市| 资源县| 南溪县| 清新县| 庆安县| 台安县| 永善县| 正定县| 永城市| 吉木萨尔县| 九江市| 南华县| 松江区| 陇南市| 富阳市|