为什么PrePareStatement预处理对象能提升性能

什么是prepareStatement预处理

PreparedStatement 是 JDBC 中的一个接口,用于执行预编译的 SQL 语句。与普通的 Statement 不同,PreparedStatement 的 SQL 语句在执行之前已经经过编译,因此更高效且安全,同时可以防止 SQL 注入攻击。PreparedStatement 通常用于执行多次相似的 SQL 查询或更新,只需编译一次,多次执行。

PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

prepareStatement预处理的好处

1,PreparedStatement比Statement效率更高,更快。

释:PreparedStatement拥有更佳的性能优势,数据库系统会对sql语句进行预编译处理,预处理语句将被预先编译好,这样预编译的sql语句 能在将来的查询中重用。也就是数据库对SQL语句的分析、编译、优化已经在第一次查询前完成,之后查询不再重复,所以 PreparedStatement比Statement更快。
为了获得性能上的优势,在sql查询语句时应该使用参数化sql查询而不是字符串追加的方式。即应该使用"where userName=?“而不是"where userName=”+userName。

2,防止SQL注入式攻击

在使用参数化查询时,数据库系统不会将参数的内容视为SQL指令进行处理,而是在数据库完成SQL指令的编译后,才会套用参数运行。因此,如果参数中 含有破坏性的指令,也不会被数据库所运行。

PreparedStatement与Statement的不同

一.代码的可读性和可维护性
虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次

传统处理sql语句的方式:

stmt.executeUpdate(
"insert into tb_name (col1,col2,col2,col4) values('"+var1+"','"+var2+"',"+var3+",'"+var4+"')"
);

PreparedStatement预处理sql语句的方式:

//先预处理sql语句
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
//在给占位符 ? 传参数
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
//最后执行处理好的sql语句
perstmt.executeUpdate();

二.PreparedStatement尽最大可能提高性能(原理)

数据库已经具有了类似的功能。它们通常会用如下方法对statement进行缓存。使用statement本身作为key并将存取方案存入与statement对应的缓存中。这样数据库引擎就可以对曾经执行过的statements中的存取方案进行重用。举个例子,如果我们发送一条包含SELECT a, b FROM t WHERE c = 2的statement到数据库,然后首先会将存取方案进行缓存。当我们再次发送相同的statement时,数据库会对先前使用过的存取方案进行重用,这样就降低了CPU的开销。

注意,这里使用了整个statement为key。也就是说,如果我们发送一个包含SELECT a, b FROM t WHERE c = 3的statement的话,缓存中不会没有与之对应的存取方案。这是因为“c=3”与曾经被缓存过的“c=2”不同。

举个例子:

for (int i = 0; i < 1000; i++) {
PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + i);
ResultSet rs = Ps.executeQuery();
rs.close();
ps.close();
}

在这里缓存不会被使用,因为每一次迭代都会发送一条包含不同SQL语句的statement给数据库。并且每一次迭代都会生成一个新的存取方案。现在让我们来看看下一段代码:

PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?");
for (int i = 0; i < 1000; i++) {
ps.setInt(1, i);
ResultSet rs = ps.executeQuery();
rs.close();
ps.close();
}

这样就具有了更好的效率,这个statement发送给数据库的是一条带有参数“?”的SQL语句。这样每次迭代会发送相同的statement到数据库,只是参数“c=?”不同。这种方法允许数据库重用statement的存取方案,这样就具有了更好的效率。这可以让你的应用程序速度更快,并且使用更少的CPU,这样数据库服务器就可以为更多的人提供服务。

三.最重要的一点是极大地提高了安全性

如果你使用预编译语句.你传入的任何内容就不会和原来的语句发生任何匹配的关系.(前提是数据库本身支持预编译,但上前可能没有什么服务端数据库不支持编译了,只有少数的桌面数据库,就是直接文件访问的那些)只要全使用预编译语句,你就用不着对传入的数据做任何过虑

为什么预处理对象会提升处理的性能

预处理对象可以提升处理的性能,主要有以下几个原因:

1、减少重复计算:通过对一些可能会重复计算的数据进行处理,可以直接使用预处理后的结果,避免了重复计算,提高了处理效率。

2、优化算法:通过对数据进行分析和处理,可以得到更好的处理算法,进而提高处理效率。

3、缓存和索引:预处理对象可以缓存和索引数据,使得后续查询或操作数据更加高效。

4、数据格式转换:预处理对象可以对数据进行格式转换,使得后续处理更加高效。

5、数据降维:在一些大规模数据处理中,可以通过预处理对象将数据进行降维,从而减少处理的时间和空间成本。

总结

  1. PreparedStatement在第一次编译后,存放在数据库里,类似于K-V对应的方式存储,这样,当下一条同样的PreparedStatement发送到数据库里,数据库查找到有相应的K存在,就调用K中的方法,省却了再去重新创建语句的过程,提高数据库的性能。
  2. ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询。
  3. 在J2EE的应用服务器的PreparedStatement缓存,个人认为,这里缓存的不是真正的缓存,而是数据库的PreparedStatement缓存的代理,不过应用服务器的PreparedStatement缓存和数据库里的PreparedStatement缓存保持一致,这样做,可能是应用服务器在管理PreparedStatement缓存时有它自己的比较好的实现策略,比单纯的使用JDBC使用数据库的缓存具有更好的性能或内存管理。
  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个示例代码,可以实现对数据库中的StudentInfo表进行插入操作: ```java import java.sql.*; public class StudentInsert { public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt = null; try { // 1. 加载数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 2. 建立数据库连接 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/StudentDB", "root", "password"); // 3. 创建PreparedStatement对象 String sql = "INSERT INTO StudentInfo (name, age, gender) VALUES (?, ?, ?)"; pstmt = conn.prepareStatement(sql); // 4. 设置参数 pstmt.setString(1, "张三"); pstmt.setInt(2, 20); pstmt.setString(3, "男"); // 5. 执行插入操作 int rows = pstmt.executeUpdate(); System.out.println(rows + " 行记录被插入"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { // 6. 关闭数据库连接和PreparedStatement对象 try { if (pstmt != null) pstmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } ``` 上述代码中,首先加载了MySQL数据库驱动,然后建立了一个与StudentDB数据库的连接。接着,使用PrepareStatement对象来创建一个插入SQL语句,并且使用setXXX()方法来设置每个参数的值。最后,调用executeUpdate()方法来执行插入操作,并输出结果。 需要注意的是,在实际编程中,需要根据不同的情况来设置参数的值,比如从用户输入中获取参数值,或者从其他对象中获取参数值。同时,还需要在程序中处理异常情况,如数据库连接失败、SQL语句执行失败等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值