JavaWeb学习(七): Statement 与 PreparedStatement 的区别 :
前言:
两者由哪个类产生?
Connection 产生 Statement 对象 : createStatement()
Connection 产生 PreparedStatement 对象 : prepareStatement()
Connection 产生 CallableStatement 对象 : prepareCall()
两者之间的关系:
public interface PreparedStatement extends Statement
由此可知: PreparedStatement 是Statement 的一个子接口
所以 : Statement有的东西PreparedStatement 也有,甚至子类还比父类多很多东西
两者是通过怎么的方式操作数据库的?
Statement :
增删改 :executeUpdate()
查询 : executeQuery() --- 返回的是一个结果集(ResultSet)
PreparedStatement:
增删改 : executeUpdate()
查询 : executeQuery() --- 返回的是一个结果集(ResultSet)
赋值操作:setXxx(); --- 相对于 Statement 强大的地方
两者在使用时的区别(具体看代码,更好理解):
Statement:
1、SQL 语句
2、executeUpdate(sql)
PareparedStatement:
sql(可以存在占位符?)
在创建PreparedStatement 对象时,将sql预编译 prepareStatement(sql);
setXxx()替换占位符 (两个参数: 位置,值)
executeUpdate(); -- 由于已经预编译过,所以不用再进行重复编译
PareparedStatement 的优势:
1、编码更加简便(直接用 ?代替,避免了字符串的拼接)
2、提高性能(预编译,避免了重复编译,提高了性能)
3、安全(可以有效防止 sql 注入)
sql注入: 将用户输入的内容 和开发人员的SQL语句混为一体
stmt : 存在被注入的风险
(例如输入 用户名:任意值 ' or 1 = 1 --
密码:任意值
)
分析:
select count(*) from login where uname='任意值' or 1=1 --' and upwd = '任意值’;
(SQL语句中 -- 起注释的作用)
select count(*) from login where uname='任意值' or 1=1;
select count(*) from login;
pstmt : 有效防止 sql 注入(推荐使用)
select count(*) from login where uname=? and upwd = ?;
(没有符号跟 ?配对)
代码进行区别:
Statement:
package controlSql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SqlQuery {
private static final String URL = "jdbc:mysql://localhost:3306/sqltest";
private static final String User = "root";
private static final String Pwd = "root";
// 查询操作
public static void query() {
Connection connection = null;
Statement stamt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(URL, User, Pwd);
stamt = connection.createStatement();
String sql = "select sno,sname from s";
// 查询操作 : 返回结果集
rs = stamt.executeQuery(sql);
// 指针不为空一直向下走(也可以向上走 -- rs.previous())
while (rs.next()) {
// 通过 getXxx 方法获得 数据库中每个字段的信息
String sno = rs.getString("sno");
String sname = rs.getString("sname");
System.out.println(sno + "--" + sname);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后记得关闭,最后开的先关闭,最先开的最后关闭
rs.close();
stamt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 更新操作
public static void update() {
Connection connection = null;
Statement stamt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(URL, User, Pwd);
stamt = connection.createStatement();
// 括号里面的字段值需要用 单引号 '',较为复杂时要用到字符串的拼接
String sql = "insert into s values ('1006','sd','13')";
int cnt = stamt.executeUpdate(sql);
if(cnt > 0) System.out.print("操作成功!");
else System.out.print("操作失败!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后记得关闭,最后开的先关闭,最先开的最后关闭
stamt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
update();
// query();
}
}
PreparedStatement:
package controlSql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PreparedStatementExample {
private static final String URL = "jdbc:mysql://localhost:3306/sqltest";
private static final String User = "root";
private static final String Pwd = "root";
public static void query() {
Connection connection = null;
PreparedStatement stamt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(URL, User, Pwd);
// 查询操作(实现模糊查询)
String sql = "select * from s where sname like ? ";
stamt = connection.prepareStatement(sql);
stamt.setString(1, "%s%");
rs = stamt.executeQuery();
while (rs.next()) {
// 通过 getXxx 方法获得 数据库中每个字段的信息
String sno = rs.getString("sno");
String sname = rs.getString("sname");
System.out.println(sno + "--" + sname);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后记得关闭,最后开的先关闭,最先开的最后关闭
rs.close();
stamt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void update() {
Connection connection = null;
PreparedStatement stamt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(URL, User, Pwd);
// 插入操作
String sql = "insert into s values (?,?,?)";
// 预编译
stamt = connection.prepareStatement(sql);
// 按照位置进行插入
stamt.setString(1, "1005");
stamt.setString(2, "wu");
stamt.setString(3, "23");
int cnt = stamt.executeUpdate();
if(cnt > 0) System.out.print("操作成功!");
else System.out.print("操作失败!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后记得关闭,最后开的先关闭,最先开的最后关闭
stamt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// query();
update();
}
}
如果说年轻人未来是一场盛宴的话,那么我首先要有赴宴的资格。