Java PreparedStatement
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