Java PreparedStatement

时间:2020-02-23 14:36:45  来源:igfitidea点击:

Java PreparedStatement层次结构

//Method :

public PreparedStatement prepareStatement(String query)throws SQLException{}

//Usage :

Connection con = DriverManager.getConnection ("jdbc:mysql://localhost:3306/customerdb", "root", "root");

PreparedStatement ps = con.prepareStatement("select id, firstname, lastname, email, birthdate from tblcustomer");

PreparedStatement的优势

我们可以将方法分为不同的类别。

PreparedStatement方法

  • Java PreparedStatement就像一个Statement,它是Java JDBC Framework的一部分。

  • 它用于对数据库执行分类操作。

1.执行查询

以下所有方法都有2个参数。
第一个参数是参数索引,第二个参数是参数值。

  • PreparedStatement扩展了Statement接口。

  • PreparedStatement支持参数化查询,因此被认为更安全。
    PreparedStatement还可以防止SQL注入攻击。

  • 我们可以通过调用Connection的prepareStatement(String query)方法来获得PreparedStatement的实例,如下所示。

  • PreparedStatement可以用于参数化查询和普通查询。

  • PreparedStatement的查询性能优于语句的查询性能。

  • 可以重新使用PreparedStatement实例以执行具有不同参数的同一查询。

  • PreparedStatement使应用程序免受SQL Injection攻击。

  • ResultSet executeQuery():此方法用于通过PreparedStatement对象执行读取操作。
    它返回一个ResultSet的实例,用于获取数据。

注意:parameterIndex值从1开始,所有这些方法都抛出SQLException。

2.将参数值传递给查询

我们将使用MySQL数据库来演示PreparedSatement的用法。
使用下面的DB脚本创建数据库,表和示例数据。

create database customerdb;

use customerdb;

create table tblcustomer(
  id integer AUTO_INCREMENT primary key,
  firstname varchar(32),
  lastname varchar(32),
  email varchar(32),
  birthdate datetime
);

insert into tblcustomer (id,firstname,lastname,email,birthdate) values(1,'Ricky','Smith','[email protected]','2001-12-10');

数据库连接信息:

MySql数据库的名称:customerdb IP:本地主机端口:3306用户名:root密码:root

Maven依赖关系:

<dependencies>
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.48</version>
  </dependency>
</dependencies>

Java PreparedStatement示例

在这种情况下,我们将从tblcustomer中获取具有指定ID的行。
查询将返回单行。

package com.theitroad.examples;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class PreparedStatementDemo {
  public static void main(String[] args) throws Exception {
      Connection con = null;
      PreparedStatement ps = null;
      ResultSet rs = null;
      int customerId = 1;
      String query = "select id, firstname, lastname, email,     birthdate from tblcustomer where id = ?";
      try {
          Class.forName("com.mysql.jdbc.Driver");
          con = DriverManager.getConnection("jdbc:mysql://localhost:3306/customerdb", "root", "root");
          ps = con.prepareStatement(query);
          ps.setInt(1, customerId);
          rs = ps.executeQuery();
          while (rs.next()) {
              System.out.println("Id:" + rs.getInt(1));
              System.out.println("First Name:" + rs.getString(2));
              System.out.println("Last Name:" + rs.getString("lastname"));
              System.out.println("Email:" + rs.getString("email"));
              System.out.println("BirthDate:" + rs.getDate("birthdate"));
          }
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
          rs.close();
          ps.close();
          con.close();
      }
  }
}

了解执行步骤:

步骤1:加载JDBC驱动程序。

Class.forName(" com.mysql.jdbc.Driver")将jdbc驱动程序加载到内存中。

步骤2:现在我们需要获取Connection对象。
下一行将执行此操作。

DriverManager.getConnection(" << JDBC Url >>"," << Db用户名>>"," << db密码>>");

步骤3:我们可以从Connection对象获取PreparedStatement的实例。
我们还需要指定要执行的查询。
例如

PreparedSatement ps = con.prepareStatement(<<查询>>);

PreparedStatement还支持参数化查询。

"?"是查询中的参数。
在执行查询之前,需要提供此参数的值。

步骤4:提供查询参数的值。
上面的示例中只有一个参数,即整数类型的id。

int customerId = 1; ps.setInt(1,customerId); setInt(<<参数编号>>,<<参数值>)方法有2个参数。
在上面的示例中," 1"是参数编号,变量customerId是Parameter的值。

步骤5:执行查询。

PreparedStatement的executeQuery()方法用于执行选择查询。
它将返回ResultSet的实例。
如果查询用于插入,更新或者删除,则可以使用executeUpdate()。

步骤6:迭代ResultSet。
ResultSet的next()方法用于获取查询输出。

步骤7:关闭资源:这是重要的步骤之一。
许多开发人员忘记关闭诸如ResultSet,PreparedStatement和Connection之类的资源。
这将导致资源泄漏,这可能会使您的应用程序崩溃。

程序输出:

Id:1
First Name:Ricky
Last Name:Smith
Email:[email protected]
BirthDate:2001-12-1

1.使用PreparedStatement获取数据

在此示例中,我们将使用PreparedStatement在tblcustomer表中执行插入操作。

package com.theitroad.examples;

import java.sql.*;
import java.text.SimpleDateFormat;

public class PrepareStatementInsertDemo {
  public static void main(String[] args) throws Exception {
      {
          Connection con = null;
          PreparedStatement ps = null;
          ResultSet rs = null;
          String firstname = "matthew";
          String lastname = "wade";
          String email = "[email protected]";
          Date birthdate = new Date(new SimpleDateFormat("YYYY-MM-DD").parse("2000-12-12").getTime());
          String query = "insert into tblcustomer (id,firstname,lastname,email,birthdate) values(default,?,?,?,?)";
          try {
              Class.forName("com.mysql.jdbc.Driver");
              con = DriverManager.getConnection("jdbc:mysql://localhost:3306/customerdb", "root", "root");
              ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
              ps.setString(1, firstname);
              ps.setString(2, lastname);
              ps.setString(3, email);
              ps.setDate(4, birthdate);
              int row = ps.executeUpdate();
              System.out.println("No. of Rows inserted:" + row);
              rs = ps.getGeneratedKeys();
              if (rs.next()) {
                  System.out.println("Id of new Customer:" + rs.getInt(1));
              }
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              rs.close();
              ps.close();
              con.close();
          }
      }
  }
}

在此示例中,在创建PreparedStatement实例时,我们传递了2个参数。
第一个是查询本身,第二个是" Statement.RETURN_GENERATED_KEYS",这将帮助我们获取新行的主键值。

以下代码用于提供用于插入查询的参数。

ps.setString(1, firstname);
ps.setString(2, lastname);
ps.setString(3, email);
ps.setDate(4, birthdate);

如前一个程序所述,executeUpdate()方法用于执行插入操作。
它将返回受我们的查询影响的行数。

程序输出:

No. of Rows inserted:1
Id of new Customer:2

如果转到DB并执行选择查询,则将看到以下结果。

mysql> use customerdb;

Database changed

mysql> select * from tblcustomer;
+----+-----------+----------+------------------+---------------------+
| id | firstname | lastname | email            | birthdate           |
+----+-----------+----------+------------------+---------------------+
|  1 | Ricky     | Smith    | [email protected] | 2001-12-10 00:00:00 |
|  2 | matthew   | wade     | [email protected] | 1999-12-26 00:00:00 |
+----+-----------+----------+------------------+---------------------+
2 rows in set (0.00 sec)

2.使用PreparedStatement插入操作

现在我们将执行更新操作。
我们将更新电子邮件为" [email protected]"的客户的名字和姓氏。
在上一个示例中插入了该行。

package com.theitroad.examples;

import java.sql.*;

public class PrepareStatementUpdateDemo {
  public static void main(String[] args) throws Exception {
      {
          Connection con = null;
          PreparedStatement ps = null;
          String email = "[email protected]";
          String newFirstname = "john";
          String newLastname = "smith";
          String query = "update tblcustomer set firstname = ?,lastname =? where email = ?";
          try {
              Class.forName("com.mysql.jdbc.Driver");
              con = DriverManager.getConnection("jdbc:mysql://localhost:3306/customerdb", "root", "root");
              ps = con.prepareStatement(query);
              ps.setString(1, newFirstname);
              ps.setString(2, newLastname);
              ps.setString(3, email);
              int row = ps.executeUpdate();
              System.out.println("No. of Rows Updated:" + row);
              if (row == 1) {
                  String selectQuery = "select id,firstname,lastname,email,birthdate from tblcustomer where email=?";
                  try (PreparedStatement selStatement = con.prepareStatement(selectQuery);
                  ) {
                      selStatement.setString(1, email);
                      ResultSet rs = selStatement.executeQuery();
                      if (rs.next()) {
                          System.out.println("Id:" + rs.getInt(1));
                          System.out.println("First Name:" + rs.getString(2));
                          System.out.println("Last Name:" + rs.getString("lastname"));
                          System.out.println("Email:" + rs.getString("email"));
                          System.out.println("BirthDate:" + rs.getDate("birthdate"));
                      }
                      rs.close();
                  }
              }
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              ps.close();
              con.close();
          }
      }
  }
}

了解程序:

在上面的示例中,我们在查询中有3个参数。
第一个是新的名字,第二个是新的姓氏,第三个是客户的电子邮件。

下面的代码行将此参数的值提供给PreparedStatement。

ps.setString(1, newFirstname);
ps.setString(2, newLastname);
ps.setString(3, email);

executeUpdate()方法用于执行更新查询。
它将返回查询更新的行数。

程序输出:

No. of Rows Updated:1
Id:2
First Name:john
Last Name:smith
Email:[email protected]
BirthDate:1999-12-26

您可以使用SQL查询在数据库中检查更新。

mysql> select * from tblcustomer;
+----+-----------+----------+------------------+---------------------+
| id | firstname | lastname | email            | birthdate           |
+----+-----------+----------+------------------+---------------------+
|  1 | Ricky     | Smith    | [email protected] | 2001-12-10 00:00:00 |
|  2 | john      | smith    | [email protected] | 1999-12-26 00:00:00 |
+----+-----------+----------+------------------+---------------------+
2 rows in set (0.00 sec)

3.使用PreparedStatement更新操作

现在,我们将删除电子邮件为" [email protected]"的客户记录。

package com.theitroad.examples;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class PrepareStatementDeleteDemo {
  public static void main(String[] args) throws Exception {
      {
          Connection con = null;
          PreparedStatement ps = null;
          String email = "[email protected]";
          String query = "delete from tblcustomer where email = ?";
          try {
              Class.forName("com.mysql.jdbc.Driver");
              con = DriverManager.getConnection("jdbc:mysql://localhost:3306/customerdb", "root", "root");
              ps = con.prepareStatement(query);
              ps.setString(1, email);
              int row = ps.executeUpdate();
              System.out.println("No. of Rows Deleted:" + row);
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              ps.close();
              con.close();
          }
      }
  }
}

4.使用PreparedStatement删除操作

  • int executeUpdate():此方法用于执行插入,删除和更新查询。
    它将返回一个整数值,指示受查询影响的数字数据库行。

  • void setInt(int parameterIndex,int value):此方法将Integer值设置为指定的参数索引。

PreparedStatement中的批处理方法

package com.theitroad.examples;
import java.sql.*;
import java.text.SimpleDateFormat;

public class PrepareStatementBatchDemo {
  public static void main(String[] args) throws Exception {
      {
          Connection con = null;
          PreparedStatement ps = null;
          ResultSet rs = null;
          SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD");
          String query = "insert into tblcustomer (id,firstname,lastname,email,birthdate) values(default,?,?,?,?)";
          try {
              Class.forName("com.mysql.jdbc.Driver");
              con = DriverManager.getConnection("jdbc:mysql://localhost:3306/customerdb", "root", "root");
              ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);

              //1st Insert
              ps.setString(1, "Ross");
              ps.setString(2, "Southee");
              ps.setString(3, "[email protected]");
              ps.setDate(4, new Date(sdf.parse("2000-12-12").getTime()));
              ps.addBatch();

              //2nd Insert
              ps.setString(1, "Mayank");
              ps.setString(2, "Kohli");
              ps.setString(3, "[email protected]");
              ps.setDate(4, new Date(sdf.parse("2005-12-12").getTime()));
              ps.addBatch();

              //3rd Insert
              ps.setString(1, "Tom");
              ps.setString(2, "Patel");
              ps.setString(3, "[email protected]");
              ps.setDate(4, new Date(sdf.parse("1995-12-12").getTime()));
              ps.addBatch();

              //Execution
              int[] rows = ps.executeBatch();

              for (int row : rows) {
                  System.out.println("No. of Rows inserted:" + row);
              }
              rs = ps.getGeneratedKeys();
              while (rs.next()) {
                  System.out.println("Id of new Customer:" + rs.getInt(1));
              }
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              rs.close();
              ps.close();
              con.close();
          }
      }
  }
}

在上面的示例中,我们分批插入了3个客户记录。
批量插入多行而不是单行更为有效。
addBatch()方法可批量添加数据。
executeBatch()执行批处理中的所有查询。

输出:

No. of Rows inserted:1
No. of Rows inserted:1
No. of Rows inserted:1
Id of new Customer:10
Id of new Customer:11
Id of new Customer:12