之前执行sql语句都是用Statement去执行的,但是学习了PreparedStatement之后发现PreparedStatement更好用,下面就来说一下PreparedStatement的优点。
优点1:
Statement需要进行字符串拼接,可读性和维护性比较差
String sql = “insert into hero values(null,”+"‘提莫’"+","+313.0f+","+50+")";
代码如下:
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class work4 {
public static void main(String[] args) {
Connection c = null;
Statement s = null;
try {
Class.forName("com.mysql.jdbc.Driver");
c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root" ,"admin");
String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";//插入信息
s = c.createStatement();
s.execute(sql);
//先释放Statement对象
s.close();
//再释放Connection对象
c.close();
}catch(ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e) {
e.printStackTrace();
}
}
}
PreparedStatement 使用参数设置,可读性好,不易犯错
String sql = “insert into hero values(null,?,?,?)”;
代码如下:
package jdbc4;
import java.sql.*;
public class testJDBC {
public static void main(String[] args) {
Connection c = null;
PreparedStatement ps = null;
ResultSet r = null;
try {
Class.forName("com.mysql.jdbc.Driver");
c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root","admin");
String sql = "insert into hero values (null,?,?,?)";
ps = c.prepareStatement(sql);
ps.setString(1,"aa");
ps.setFloat(2, (float) 35.4);
ps.setInt(3,55);
ps.execute();
}catch(ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(r != null) {
try {
r.close();
}catch(Exception e) {
e.printStackTrace();
}
r = null;
}
if(ps != null) {
try {
ps.close();
}catch(Exception e) {
e.printStackTrace();
}
ps = null;
}
if(c != null) {
try {
c.close();
}catch(Exception e) {
e.printStackTrace();
}
c = null;
}
}
}
}
总结:
使用Statement进行字符串拼接时显得非常的繁琐,会有很多的双引号和单引号的配对,如果缺少一个,程序就会出错。而且查错十分艰难。(之前就被这种字符串拼接搞崩溃了…)
这时PreparedStatement就显得很清晰了,把要插入的元素先用?代替,之后在不同的位置一个一个使用set语句就可以了,十分方便清晰。
优点2:
PreparedStatement有预编译机制,性能比Statement更快
代码如下:
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String sql = "insert into hero values(null,?,?,?)";
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();
PreparedStatement ps = c.prepareStatement(sql);
) {
// Statement执行10次,需要10次把SQL语句传输到数据库端
// 数据库要对每一次来的SQL语句进行编译处理
for (int i = 0; i < 10; i++) {
String sql0 = "insert into hero values(null," + "'提莫'" + ","
+ 313.0f + "," + 50 + ")";
s.execute(sql0);
}
s.close();
// PreparedStatement 执行10次,只需要1次把SQL语句传输到数据库端
// 数据库对带?的SQL进行预编译
// 每次执行,只需要传输参数到数据库端
// 1. 网络传输量比Statement更小
// 2. 数据库不需要再进行编译,响应更快
for (int i = 0; i < 10; i++) {
ps.setString(1, "提莫");
ps.setFloat(2, 313.0f);
ps.setInt(3, 50);
ps.execute();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
总结:
如果需要插入10万条语句到数据库,使用Statement执行sql语句需要一条一条被数据库编译,这肯定会引起卡顿。但是PreparedStatement就不一样了,数据库只要对其刚开始的那条sql语句进行预编译,之后直接插入就可以了。总的来说PreparedStatement更加快。
优点3:
PreparedStatement可以防止SQL注入式攻击
代码如下:
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String sql = "select * from hero where name = ?";
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();
PreparedStatement ps = c.prepareStatement(sql);
) {
// 假设name是用户提交来的数据
String name = "'盖伦' OR 1=1";
String sql0 = "select * from hero where name = " + name;
// 拼接出来的SQL语句就是
// select * from hero where name = '盖伦' OR 1=1
// 因为有OR 1=1,所以恒成立
// 那么就会把所有的英雄都查出来,而不只是盖伦
// 如果Hero表里的数据是海量的,比如几百万条,把这个表里的数据全部查出来
// 会让数据库负载变高,CPU100%,内存消耗光,响应变得极其缓慢
System.out.println(sql0);
ResultSet rs0 = s.executeQuery(sql0);
while (rs0.next()) {
String heroName = rs0.getString("name");
System.out.println(heroName);
}
s.execute(sql0);
// 使用预编译Statement就可以杜绝SQL注入
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
// 查不出数据出来
while (rs.next()) {
String heroName = rs.getString("name");
System.out.println(heroName);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}