Java JDBC中的Statement和PreparedStatement

以Oracle为例吧

Statement为一条Sql语句生成执行计划,

如果要执行两条sql语句

select colume from table where colume=1;

select colume from table where colume=2;

会生成两个执行计划

一千个查询就生成一千个执行计划!

PreparedStatement用于使用绑定变量重用执行计划

select colume from table where colume=:x;

通过set不同数据只需要生成一次执行计划,可以重用

是否使用绑定变量对系统影响非常大,生成执行计划极为消耗资源

两种实现 速度差距可能成百上千倍

1.PreparedStatement是预编译的,对于批量处理可以大大提高效率.也叫JDBC存储过程

2.使用 Statement 对象。在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。PreparedStatement对象的开销比Statement大,对于一次性操作并不会带来额外的好处。

3.statement每次执行sql语句,相关数据库都要执行sql语句的编译,preparedstatement是预编译得,preparedstatement支持批处理

4.

Code Fragment 1:

[java] view
plain
 copy

  1. String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERECOF_NAME LIKE ′Colombian′";
  2. stmt.executeUpdate(updateString);

Code Fragment 2:

[java] view
plain
 copy

  1. PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SETSALES = ? WHERE COF_NAME LIKE ? ");
  2. updateSales.setInt(1, 75);
  3. updateSales.setString(2, "Colombian");
  4. updateSales.executeUpdate();

片断2和片断1的区别在于,后者使用了PreparedStatement对象,而前者是普通的Statement对象。PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度。

这种转换也给你带来很大的便利,不必重复SQL语句的句法,而只需更改其中变量的值,便可重新执行SQL语句。选择PreparedStatement对象与否,在于相同句法的SQL语句是否执行了多次,而且两次之间的差别仅仅是变量的不同。如果仅仅执行了一次的话,它应该和普通的对象毫无差异,体现不出它预编译的优越性。

5.执行许多SQL语句的JDBC程序产生大量的Statement和PreparedStatement对象。通常认为PreparedStatement对象比Statement对象更有效,特别是如果带有不同参数的同一SQL语句被多次执行的时候。PreparedStatement对象允许数据库预编译SQL语句,这样在随后的运行中可以节省时间并增加代码的可读性。

然而,在Oracle环境中,开发人员实际上有更大的灵活性。当使用Statement或PreparedStatement对象时,Oracle数据库会缓存SQL语句以便以后使用。在一些情况下,由于驱动器自身需要额外的处理和在Java应用程序和Oracle服务器间增加的网络活动,执行PreparedStatement对象实际上会花更长的时间。

然而,除了缓冲的问题之外,至少还有一个更好的原因使我们在企业应用程序中更喜欢使用PreparedStatement对象,那就是安全性。传递给PreparedStatement对象的参数可以被强制进行类型转换,使开发人员可以确保在插入或查询数据时与底层的数据库格式匹配。

当处理公共Web站点上的用户传来的数据的时候,安全性的问题就变得极为重要。传递给PreparedStatement的字符串参数会自动被驱动器忽略。最简单的情况下,这就意味着当你的程序试着将字符串“D‘Angelo”插入到VARCHAR2中时,该语句将不会识别第一个“,”,从而导致悲惨的失败。几乎很少有必要创建你自己的字符串忽略代码。

在Web环境中,有恶意的用户会利用那些设计不完善的、不能正确处理字符串的应用程序。特别是在公共Web站点上,在没有首先通过PreparedStatement对象处理的情况下,所有的用户输入都不应该传递给SQL语句。此外,在用户有机会修改SQL语句的地方,如HTML的隐藏区域或一个查询字符串上,SQL语句都不应该被显示出来。

在执行SQL命令时,我们有二种选择:可以使用PreparedStatement对象,也可以使用Statement对象。无论多少次地使用同一个SQL命令,PreparedStatement都只对它解析和编译一次。当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。

第一:

prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。

createStatement不会初始化,没有预处理,没次都是从0开始执行SQL

第二:

prepareStatement可以替换变量

在SQL语句中可以包含?,可以用ps=conn.prepareStatement("select* from Cust where ID=?");

int sid=1001;

ps.setInt(1, sid);

rs = ps.executeQuery();

可以把?替换成变量。

而Statement只能用

int sid=1001;

Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery("select * from Cust where ID="+sid);

来实现。

第三:

prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。

createStatement不会初始化,没有预处理,没次都是从0开始执行SQL

002

以下是利用以下三种查询以及打开和关闭说明的例子:

  • boolean execute(String SQL) : 返回一个布尔值true,如果ResultSet对象可以被检索,否则返回false。使用这个方法来执行SQL DDL语句,或当需要使用真正的动态SQL。
  • int executeUpdate(String SQL) : 返回受影响的SQL语句执行的行数。使用此方法来执行,而希望得到一些受影响的行的SQL语句 - 例如,INSERT,UPDATE或DELETE语句。
  • ResultSet executeQuery(String SQL) : 返回ResultSet对象。当希望得到一个结果集使用此方法,就像使用一个SELECT语句。

基于对环境和数据库安装在前面的章节中做此示例代码已被写入。

复制下面的例子中JDBCExample.java,编译并运行,如下所示:

//STEP 1. Import required packages
import java.sql.*;

public class JDBCExample {
   // JDBC driver name and database URL
   static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
   static final String DB_URL = "jdbc:mysql://localhost/EMP";

   //  Database credentials
   static final String USER = "username";
   static final String PASS = "password";

   public static void main(String[] args) {
   Connection conn = null;
   Statement stmt = null;
   try{
      //STEP 2: Register JDBC driver
      Class.forName("com.mysql.jdbc.Driver");

      //STEP 3: Open a connection
      System.out.println("Connecting to database...");
      conn = DriverManager.getConnection(DB_URL,USER,PASS);

      //STEP 4: Execute a query
      System.out.println("Creating statement...");
      stmt = conn.createStatement();
      String sql = "UPDATE Employees set age=30 WHERE id=103";

      // Let us check if it returns a true Result Set or not.
      Boolean ret = stmt.execute(sql);
      System.out.println("Return value is : " + ret.toString() );

      // Let us update age of the record with ID = 103;
      int rows = stmt.executeUpdate(sql);
      System.out.println("Rows impacted : " + rows );

      // Let us select all the records and display them.
      sql = "SELECT id, first, last, age FROM Employees";
      ResultSet rs = stmt.executeQuery(sql);

      //STEP 5: Extract data from result set
      while(rs.next()){
         //Retrieve by column name
         int id  = rs.getInt("id");
         int age = rs.getInt("age");
         String first = rs.getString("first");
         String last = rs.getString("last");

         //Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);
      }
      //STEP 6: Clean-up environment
      rs.close();
      stmt.close();
      conn.close();
   }catch(SQLException se){
      //Handle errors for JDBC
      se.printStackTrace();
   }catch(Exception e){
      //Handle errors for Class.forName
      e.printStackTrace();
   }finally{
      //finally block used to close resources
      try{
         if(stmt!=null)
            stmt.close();
      }catch(SQLException se2){
      }// nothing we can do
      try{
         if(conn!=null)
            conn.close();
      }catch(SQLException se){
         se.printStackTrace();
      }//end finally try
   }//end try
   System.out.println("Goodbye!");
}//end main
}//end JDBCExample

现在编译上面的例子如下:

C:>javac JDBCExample.java
C:>

当运行JDBCExample,它会产生以下结果:

C:>java JDBCExample
Connecting to database...
Creating statement...
Return value is : false
Rows impacted : 1
ID: 100, Age: 18, First: Zara, Last: Ali
ID: 101, Age: 25, First: Mahnaz, Last: Fatma
ID: 102, Age: 30, First: Zaid, Last: Khan
ID: 103, Age: 30, First: Sumit, Last: Mittal
Goodbye!
C:>

003

看过的东西忘得太快,即便记住,真正用上了才发现记的东西模棱两可。

今天用jdbc写了一段SQL语句,用PreparedStatement对象来插入对象,用pstmt.execute()的执行结果来判断数据是否插入成功:

pstmt = conn.prepareStatement("insert into columninfo(columntitle,reid,topid) values(?,?,?)");
pstmt.setString(1, column.getColumntitle());
pstmt.setInt(2, column.getReid());
pstmt.setInt(3, column.getTopid());
return pstmt.execute();
public ResultSet executeQuery() throws SQLException
返回一个不为空的结果集

public int executeUpdate() throws SQLException
返回:1、返回INSERT、UPDATE或者DELETE语句执行后的更新行数;
2、返回0表示SQL语句没有执行成功。

public boolean execute() throws SQLException
返回:true表示SQL语句执行的结果返回ResultSet对象;
false表示SQL语句执行结果返回的是更新行数或者没有返回。

004

1. ResultSet executeQuery(String sql); 执行SQL查询,并返回ResultSet 对象。

2.int executeUpdate(String sql); 可执行增,删,改,返回执行受到影响的行数。

3. boolean execute(String sql); 可执行任何SQL语句,返回一个布尔值,表示是否返回ResultSet 。

execute是executeQuery和executeUpdate的综合.

-----

executeUpdate() 这是 PreparedStatement 接口中的方法

executeUpdate(String sql) 这是 PreparedStatement 从父接口 Statement 中继承过来的方法

executeUpdate() 中执行 SQL 语句需要在创建 PerparedStatement 时通过 Connection 的 prepareStatement(String sql) 方法中写出,因为 PerparedStatement 中的 SQL 语句数据库需要进行预编译和缓存,因此要在创建 PerparedStatement 对象时给出 SQL 语句。

而 executeUpdate(String sql) 是 Statement 中的方法,参数中的 SQL 语句只是提交给数据库去执行,并不需要预编译。

如果 SQL 语句中有 ? 占位符,那么在设置好占位符中的值后,必须使用 executeUpdate() 执行。而 executeUpdate(String sql) 只是提交一个 SQL 语句,且这个语句中不能带有 ? 占位符。

005

在用纯JSP做一个页面报警功能的时候习惯性的用executeQuery来执行SQL语句,结果执行update时就遇到问题,语句能执行,但返回结果出现问题,另外还忽略了executeUpdate的返回值不是结果集ResultSet,而是数值!特收藏如下一篇文章(感谢网友们对各种信息的贡献):

JDBCTM中Statement接口提供的execute、executeQuery和executeUpdate之间的区别

Statement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute。使用哪一个方法由 SQL 语句所产生的内容决定。

方法executeQuery

用于产生单个结果集的语句,例如 SELECT 语句。 被使用最多的执行 SQL 语句的方法是 executeQuery。这个方法被用来执行 SELECT 语句,它几乎是使用最多的 SQL 语句。

方法executeUpdate

用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数,指示受影响的行数(即更新计数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate
的返回值总为零。

使用executeUpdate方法是因为在 createTableCoffees 中的 SQL 语句是 DDL (数据定义语言)语句。创建表,改变表,删除表都是 DDL 语句的例子,要用 executeUpdate 方法来执行。你也可以从它的名字里看出,方法 executeUpdate 也被用于执行更新表 SQL 语句。实际上,相对于创建表来说,executeUpdate 用于更新表的时间更多,因为表只需要创建一次,但经常被更新。

方法execute:

用于执行返回多个结果集、多个更新计数或二者组合的语句。因为多数程序员不会需要该高级功能

execute方法应该仅在语句能返回多个ResultSet对象、多个更新计数或ResultSet对象与更新计数的组合时使用。当执行某个已存储过程或动态执行未知 SQL 字符串(即应用程序程序员在编译时未知)时,有可能出现多个结果的情况,尽管这种情况很少见。

因为方法 execute 处理非常规情况,所以获取其结果需要一些特殊处理并不足为怪。例如,假定已知某个过程返回两个结果集,则在使用方法 execute 执行该过程后,必须调用方法 getResultSet 获得第一个结果集,然后调用适当的 getXXX 方法获取其中的值。要获得第二个结果集,需要先调用 getMoreResults 方法,然后再调用 getResultSet 方法。如果已知某个过程返回两个更新计数,则首先调用方法
getUpdateCount,然后调用 getMoreResults,并再次调用 getUpdateCount。

对于不知道返回内容,则情况更为复杂。如果结果是 ResultSet 对象,则方法 execute 返回 true;如果结果是 Java int,则返回
false。如果返回 int,则意味着结果是更新计数或执行的语句是 DDL 命令。在调用方法 execute 之后要做的第一件事情是调用 getResultSet 或 getUpdateCount。调用方法 getResultSet 可以获得两个或多个 ResultSet 对象中第一个对象;或调用方法 getUpdateCount 可以获得两个或多个更新计数中第一个更新计数的内容。

当 SQL 语句的结果不是结果集时,则方法 getResultSet 将返回 null。这可能意味着结果是一个更新计数或没有其它结果。在这种情况下,判断 null 真正含义的唯一方法是调用方法 getUpdateCount,它将返回一个整数。这个整数为调用语句所影响的行数;如果为 -1 则表示结果是结果集或没有结果。如果方法 getResultSet 已返回 null(表示结果不是 ResultSet 对象),则返回值 -1
表示没有其它结果。也就是说,当下列条件为真时表示没有结果(或没有其它结果):

((stmt.getResultSet() == null) && (stmt.getUpdateCount() == -1))

如果已经调用方法 getResultSet 并处理了它返回的 ResultSet 对象,则有必要调用方法 getMoreResults 以确定是否有其它结果集或更新计数。如果 getMoreResults 返回 true,则需要再次调用 getResultSet 来检索下一个结果集。如上所述,如果 getResultSet 返回 null,则需要调用 getUpdateCount 来检查 null 是表示结果为更新计数还是表示没有其它结果。

当 getMoreResults 返回 false 时,它表示该 SQL 语句返回一个更新计数或没有其它结果。因此需要调用方法 getUpdateCount 来检查它是哪一种情况。在这种情况下,当下列条件为真时表示没有其它结果:

((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))

下面的代码演示了一种方法用来确认已访问调用方法 execute 所产生的全部结果集和更新计数:

stmt.execute(queryStringWithUnknownResults);

while (true) {

int rowCount = stmt.getUpdateCount();

if (rowCount > 0) { // 它是更新计数

System.out.println("Rows changed = " + count);

stmt.getMoreResults();

continue;

}

if (rowCount == 0) { // DDL 命令或 0 个更新

System.out.println(" No rows changed or statement was DDL

command");

stmt.getMoreResults();

continue;

}

// 执行到这里,证明有一个结果集

// 或没有其它结果

ResultSet rs = stmt.getResultSet;

if (rs != null) {

. . . // 使用元数据获得关于结果集列的信息

while (rs.next()) {

. . . // 处理结果

stmt.getMoreResults();

continue;

}

break; // 没有其它结果

时间: 2024-12-19 01:14:05

Java JDBC中的Statement和PreparedStatement的相关文章

JDBC中的Statement和PreparedStatement的区别

以Oracle为例吧 Statement为一条Sql语句生成执行计划, 如果要执行两条sql语句 select colume from table where colume=1; select colume from table where colume=2; 会生成两个执行计划 一千个查询就生成一千个执行计划! PreparedStatement用于使用绑定变量重用执行计划 select colume from table where colume=:x; 通过set不同数据只需要生成一次执行

[转] JDBC中的Statement和PreparedStatement的区别

以Oracle为例吧 Statement为一条Sql语句生成执行计划,如果要执行两条sql语句select colume from table where colume=1;select colume from table where colume=2;会生成两个执行计划一千个查询就生成一千个执行计划! PreparedStatement用于使用绑定变量重用执行计划select colume from table where colume=:x;通过set不同数据只需要生成一次执行计划,可以重用

【Java编程】JDBC注入攻击-Statement 与 PreparedStatement

在上一篇[Java编程]建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement我们介绍了如何使用JDBC驱动建立一个简单的连接,并实现使用Statement和PreparedStatement进行数据库查询,本篇blog将接着上篇blog通过SQL注入攻击比较Statement和PreparedStatement.当然这两者还有很多其他方面的不同,在之后的blog中会继续更新. [Statement查询] 1.在DBH

jdbc中的Statement对象和Preparedstatement对象的区别,以及通过jdbc操作调用存储过程

一. java.sql.*   和  javax.sql.*的包的类结构 |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接口. |- connect(url, properties):  连接数据库的方法. url: 连接数据库的URL URL语法: jdbc协议:数据库子协议://主机:端口/数据库 user: 数据库的用户名 password: 数据库用户密码 |- DriverManager类: 驱动管理器类,用于管理所有注册的驱动程序 |-regis

使用JDBC分别利用Statement和PreparedStatement来对MySQL数据库进行简单的增删改查以及SQL注入的原理

一.MySQL数据库的下载及安装 https://www.mysql.com/ 点击DOWNLOADS,拉到页面底部,找到MySQL Community(GPL)Downloads,点击 选择下图中的MySQL Community Server 选择想要的版本进行下载 之后的步骤,因为本人已经安装过MySQL数据库,而卸载重装会比较麻烦,卸载不干净会导致新的装不上,所以可以参考下面的博客,因为官网的改动,前面的部分已经与该博客不符,按照本人在上面的介绍寻找即可 https://blog.csdn

Java -- JDBC 学习--通过Statement进行数据库更新操作

通过 JDBC 向指定的数据表中插入一条记录. 1. Statement: 用于执行 SQL 语句的对象 1). 通过 Connection 的 createStatement() 方法来获取 2). 通过 executeUpdate(sql) 可以执行 SQL 语句. 3). 传入的 SQL 可以是 INSRET, UPDATE 或 DELETE. 但不能是 SELECT 2. Connection.Statement 都是应用程序和数据库服务器的连接资源. 使用后一定要关闭. 需要在 fin

JDBC预编译statement(preparedstatement)和statement的比较、execute与executeUpdate的区别

和 Statement一样,PreparedStatement也是用来执行sql语句的与创建Statement不同的是,需要根据sql语句创建PreparedStatement除此之外,还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLExcep

【Java编程】建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement

本blog提供了一个简单的通过JDBC驱动建立JDBC连接例程,并分别通过Statement和PreparedStatement实现对数据库的查询.在下一篇blog中将重点比较Statement与PreparedStatement的差异. 1.为项目添加JDBC驱动 1)JDBC驱动下载 官方下载地址:mysql-connector-java-5.0.8.zip CSDN资料下载地址:mysql-connector-java-5.0.8.zip 2)为项目添加JDBC驱动 建立项目Java项目J

【转】Java开发中JDBC连接数据库代码和步骤总结

(转自:http://www.cnblogs.com/hongten/archive/2011/03/29/1998311.html) JDBC连接数据库 创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String className)实现. 例如: try{ //加载MySql的驱动类 Class.forName("co