Statement和PreStatement的区别 以及 #{}和${}的区别

"本文详细对比了PreparedStatement和Statement在Java JDBC中的使用,包括语法差异、执行速度、批量操作以及防止SQL注入的能力。PreparedStatement通过预编译和参数化SQL语句提高了执行效率和安全性,适合多次执行相同SQL的情况,而Statement适用于一次性执行的SQL。同时,文章还提到了#{...}

一、语法

prepareStatement在mybatis中获取的时候,就已经完成预编译,和用ParameterHandler 设置参数了,后面用它来执行sql语句,只剩执行了

预编译是需要mysql执行的,而设置参数是mybatis执行的,成型的sql语句,最后也是mysql执行的

两者的语法区别

  1. statement语法
Statement stmt = connect.createStatement();
String sql= "SELECT * FROM cg_user WHERE userId=10086 AND name LIKE 'xiaoming'";
ResultSet rs = stmt.executeUpdate(sql);
    1. preparedstatement
    PreparedStatement preparedStatement = connect.prepareStatement("SELECT * FROM cg_user WHERE userId= ? AND name LIKE ?");  
    preparedStatement .setInt(1, 10086 );  
    preparedStatement .setString(2, "xiaoming");  
    preparedStatement .executeUpdate();  
    

      二、访问数据库的速度

      prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。
      createStatement不会初始化,没有预处理,没次都是从0开始执行SQL

      PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度。
      这种转换也给你带来很大的便利,不必重复SQL语句的句法,而只需更改其中变量的值,便可重新执行SQL语句。选择PreparedStatement对象与否,在于相同句法的SQL语句是否执行了多次,而且两次之间的差别仅仅是变量的不同。如果仅仅执行了一次的话,它应该和普通的对象毫无差异,体现不出它预编译的优越性。

      三、prepareStatement批量执行:

      好处:Update大量的数据时, 先构建一个INSERT语句再多次的执行, 会导致很多次的网络连接.。要减少JDBC的调用次数改善性能, 可以使用PreparedStatement的AddBatch()方法一次性发送多个查询给数据库。

      // 初始实现:
      PreparedStatement ps = conn.prepareStatement(
                      "INSERT into db_user values (?, ?, ?)");
              for (n = 0; n < 100; n++) {
                  ps.setString(name[n]);
                  ps.setLong(id[n]);
                  ps.setInt(salary[n]);
                  ps.executeUpdate();
              }
      //改进实现:
      //使用Batch功能
              PreparedStatement ps = conn.prepareStatement(
                      "INSERT into db_user values (?, ?, ?)");
              for (n = 0; n < 100; n++) {
                  ps.setString(username[n]);
                  ps.setString(password[n]);
                  ps.addBatch();
              }
              ps.executeBatch();
      

        四、SQL注入漏洞:

        Statement stmt = connect.createStatement();
        String sql= "SELECT * FROM cg_user WHERE userId"+ userId +" AND name LIKE " + name";
        ResultSet rs = stmt.executeUpdate(sql);
        

          假如入参name的值为 or '1' = '1' 那么SQL是成立的,就会返回所有数据,或者变成这个[‘;drop table cg_user ;],那么SQL拼接后就变成:

          SELECT * FROM cg_user WHERE userId='' AND name LIKE '' ; drop table cg_user ;
          

            如果使用prepareStatement预编译就不会了,因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析和编译,对应的执行计划也会缓存下来,之后数据库就会以参数化的形式进行查询。set值永远是把占位符当成data处理。

            PreparedStatement preparedStatement = connect.prepareStatement("SELECT * FROM cg_user WHERE userId= ? AND name LIKE ?");  
            preparedStatement .setInt(1, '');  
            preparedStatement .setString(2, "; drop table cg_user");  
            preparedStatement .executeUpdate();  
            

              sql会变成:

              SELECT * FROM cg_user WHERE userId='' AND name LIKE '; drop table cg_user'  ;
              

                总结:

                1. JDBC驱动的最佳化是基于使用的是什么功能,选择PreparedStatement还是Statement取决于你要怎么使用它们,对于只执行一次的SQL语句选择Statement是最好的。相反,如果SQL语句被多次执行选用PreparedStatement是最好的。

                2. PreparedStatement的第一次执行消耗是很高的,它的性能体现在后面的重复执行,使用PreparedStatement的方式来执行一个针对数据库表的查询,JDBC驱动会发送一个网络请求到数据解析和优化这个查询,而执行时会产生另一个网络请求,在JDBC驱动中,减少网络通讯是最终的目的。如果我的程序在运行期间只需要一次请求, 那么就使用Statement,对于Statement,同一个查询只会产生一次网络到数据库的通讯。

                ====================================================================================================================================================================================== 自己的理解

                Statement和preStatement都是来执行,sql语句的

                区别:

                	1.preStatement会先将sql语句,预编译成SELECT ... WHERE userId= ? AND name LIKE ?");  
                	  用占位符将sql填充完整,然后执行的时候用set方法填充占位符
                	  预编译这一步是需要mysql执行的
                	2.而statement会直接 执行原 sql语句,不会用占位符,直接将 参数 字符串拼接,然后执行
                	  会导致,sql注入
                

                preparestatment 预编译后 用 set方法 set值 占位符位置
                statement 不进行预编译,直接字符串拼接,即 去掉 值的“”,直接拼接在 ?处,然后执行

                #{}和¥{}的区别

                	1.用${},执行sql的时候用 Statement执行的,直接将参数拼接到 sql后面
                	  并且 ${} 传来的值会去掉""直接接按${} 的位置 覆盖${}
                	  例如select * from table where id = ${},这时候传一个字符串“3or2==2”
                	  这时候sql变成,select * from table where id = 3or2==2,这时候or ===2必定执行
                	  
                	2.用#{},执行sql用PreStatement执行,先预编译sql
                		select * from table where id = #{}为
                		select * from table where id = ?
                	  然后ps set参数,变为select * from table where id = "3or 2=2"
                	  #{}传来的值会 用set值的方式,将?set成传来的参数
                

                ${} 的使用场景就是,拼接sql字符串而不是 set值,即 from table , order by 字段,select 字段,这些需要拼接字符串的 就用 ${} ,这时 如果用 #{} , 那么 会导致例如from “student” , 这样的sql执行不了

                评论
                添加红包

                请填写红包祝福语或标题

                红包个数最小为10个

                红包金额最低5元

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

                抵扣说明:

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

                余额充值