JDBC中Statement和PreparedSatement的区别和运用详情
JDBC中Statement和PreparedSatement的区别和运用详情
众所周知:
-
PreparedStatement继承java,jdbc,Statement
-
Statement和PreparedStatement两者都是接口
-
内部需建立类似于Sockt链接,效率不明显
Statement的方法
-
Statement接口中提供了三种执行SQL语句的方法:分别是:executeQuery、executeUpdate和execute
使用具体的方法需由SQL语句产生的内容决定。
-
executeQuery:用于产生单个结果集的语句,例如“SELECT”语句
-
executeUpdate:用于执行INSERT、UPDATE或DALETE语句以及SQL DDL(数据库定义语言)语句(例如:CREATE TABLE和DROP TABLE),executeUpdate的返回值是一个整数类型,代表受影响的行数(插入、更新和删除条数),对于CREATE TABLE或DROP TABLE不属于操作行的语句,executeUpdate返回值为0
-
exceute:用于执行返回多个结果集、多个更新或者两者结合的语句,因为多数情况下不需要高级功能,这里不多作详解
-
Statement本身不包含SQL语句,因而必须给Statement.execute()方法提供SQL语句作为参数
-
注意:执行语句的所有方法都将关闭所调用的Statement对象的结果集(表示当前结果集,如果存在,关闭),在重新执行Statement对象之前,需要对当前ResultSet对象进行处理
PreparedStatement方法:
- 继承了Statement中所有的方法
- PreparedStatement有自己的executeQuery、executeUpdate和execute方法
- PreparedStatement对象并不将SQL语句作为参数提供给方法,因为方法本身已经包含了预编译SQL语句
CallableStatement对象继承这些方法的PreparedStatement形式,对于方法的PrepareStatement或CallableStatement版本,使用查询参数时将抛出SQLexception异常
在使用和安全方面也不各相同
当处理批量SQL语句时,怎么选择,怎么选择使用?
1)数据量少时,Statement和PreparedStatement两者差距效果没有没想差异
2)数据量大时,statement每次都需编译执行sql语句,相关数据库都要执行sql语句的编译,PrepareStatement的优势比较明显,内部采用的是Cache机制,则预编译SQL语句,存放在Cache中,如执行相同的SQL语句时,直接从Cache中取出使用(因为相同语句预编译只编译一次)对于批量处理可以大大提高效率. 也叫JDBC存储过程。
3)数据量较大时,使用Statement,因为PrepareStatement拥有的编译空间有限,在数据量较大时,可能会发生异常
PreparedStatement简单的处理:
package JDBC;
import java.sql.*;
public class JdbcTest {
public static void main(String[] args) throws SQLException {
Connection coon = null;
Statement stan = null;
PreparedStatement ps = null;
try {
Class.forName("com.mysql.jdbc.Driver");
try {
coon = DriverManager.getConnection("jdbc:mysql://localhost:3306/center", "root", "123456");
// 将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式,则其所有SQL语句将作为单个事务执行并提交。
// 否则,将其SQL语句分组为事务,这些事务通过调用方法提交或方法回滚而终止。默认情况下,新连接处于自动提交模式。
// 语句完成后,将进行提交。语句完成的时间取决于SQL语句的类型:对于DML语句,例如Insert,Update或Delete和DDL语句,该语句在完成执行后立即完成。
// 对于Select语句,当关联的结果集关闭时,该语句完成。对于CallableStatement对象或返回多个结果的语句,当所有关联的结果集都已关闭并且所有更新计数和输出参数都已获取时,该语句完成。
// 注意:如果在事务期间调用此方法并且更改了自动提交模式,则提交事务。如果调用setAutoCommit并且未更改自动提交模式,则该调用为无操作。
String sql = "insert into center_user (CENTER_NAME,CENTER_AGE,CENTER_SEX) values('发能',? ,'男') ";
ps = coon.prepareStatement(sql);
ps.setInt(1, 18);
int count = ps.executeUpdate();
System.out.println(count == 1 ? "成功" : "失败!");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
ps.close();
coon.close();
}
}
}
PreparedStatement批量预编译处理:
package JDBC;
import java.sql.*;
public class JdbcTest {
public static void main(String[] args) throws SQLException {
Connection coon = null;
Statement stan = null;
PreparedStatement ps = null;
try {
Class.forName("com.mysql.jdbc.Driver");
try {
coon = DriverManager.getConnection("jdbc:mysql://localhost:3306/center", "root", "123456");
// 将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式,则其所有SQL语句将作为单个事务执行并提交。
// 否则,将其SQL语句分组为事务,这些事务通过调用方法提交或方法回滚而终止。默认情况下,新连接处于自动提交模式。
// 语句完成后,将进行提交。语句完成的时间取决于SQL语句的类型:对于DML语句,例如Insert,Update或Delete和DDL语句,该语句在完成执行后立即完成。
// 对于Select语句,当关联的结果集关闭时,该语句完成。对于CallableStatement对象或返回多个结果的语句,当所有关联的结果集都已关闭并且所有更新计数和输出参数都已获取时,该语句完成。
// 注意:如果在事务期间调用此方法并且更改了自动提交模式,则提交事务。如果调用setAutoCommit并且未更改自动提交模式,则该调用为无操作。
coon.setAutoCommit(false);
String sql = "insert into center_user (CENTER_NAME,CENTER_AGE,CENTER_SEX) values(?,18 ,'男') ";
//可直接将SQL语句放入到preparedStatement方法中
ps = coon.prepareStatement(sql);
//循环遍历数据
for (int i = 10; i <20 ; i++) {
ps.setString(1,"小宝" + i);
ps.addBatch();
}
//执行执行批处理
ps.executeBatch();
//提交事务
coon.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
//释放资源
ps.close();
coon.close();
}
}
}
Statement批量预编译处理:
可以包含不同结构sql,灵活性较高,但是效率低下,因为没有SQL预编译
再做批量处理时,需要对某些固定不变的sql进行重复写入,操作繁琐
package JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcTest02 {
public static void main(String[] args) {
Connection conn = null;
Statement stan = null;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
try {
//获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/center", "root", "123456");
stan = conn.createStatement();
//addBatch
//将给定的SQL命令添加到此Statement对象的当前命令列表中。可以通过调用executeBatch方法来批量执行此列表中的命令。
// 注意:不能在PreparedStatement或CallableStatement上调用此方法。
stan.addBatch("DROP database if exists userName");
stan.addBatch("create database userName");
stan.addBatch("insert into user (li1,li2) VALUES('1','2')");
stan.addBatch("insert into user (li3,li4) VALUES('1','2')");
//批量处理
stan.executeBatch();
System.out.println("省略........");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
stan.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
PrepareStatement中执行的SQL语句是可以带参数的,也可以替换变量,尽量采用使用 ?号的方式传递参数,增加代码的可读性又可以预编译加速
Statement则不可以。
在数据安全的角度PreparedStatement可防止SQL注入:
通常见的SQL注入如下:
防止SQL注入。在SQL中包含特殊字符或SQL的关键字(如:’ or 1 or ‘)时,Statement将出现将SQL拼接进行编译(出现异常或查询出错),可用PreparedStatement来解决。
//原义SQL SELECT * FROM CEMTER WHERE CENTER_NAME = 'wuxin' AND PASSWORD='guisha'; //在用户进行非法SQL注入会出现SQL中的关键字进行关联拼接 其中 or '1' = '1' 就是用户非法输入的SQL SELECT * FROM CENTER WHERE CEMTER_NAME = 'wuxin' or '1' = '1';
//如下:
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
//如果我们把[' or '1' = '1]作为varpasswd传入进来.用户名随意,看看会成为什么?
select * from tb_name = '任意' and passwd = '' or '1' = '1';
//因为'1'='1'肯定成立,所以可以任何通过验证
当数据库被非法SQL注入,可能会造成数据库数据丢失,严重到删除数据库

浙公网安备 33010602011771号