Java JDBC下执行SQL的不同方式、参数化预编译防御(四)

2014-11-23 22:28:02 · 作者: · 浏览: 2
个方法无须参数,因为prepareStatement在创建的时候已经存储了预编译的SQL语句,在执行SQL语句的时候只要传入参数值即可(setXxx)
Statement和prepareStatement的性能对比
复制代码
import java.util.*;
import java.io.*;
import java.sql.*;
public class PreparedStatementTest
{
private String driver;
private String url;
private String user;
private String pass;
public void initParam(String paramFile)throws Exception
{
// 使用Properties类来加载属性文件
Properties props = new Properties();
props.load(new FileInputStream(paramFile));
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
pass = props.getProperty("pass");
// 加载驱动
Class.forName(driver);
}
public void insertUseStatement()throws Exception
{
long start = System.currentTimeMillis();
try(
// 获取数据库连接
Connection conn = DriverManager.getConnection(url
, user , pass);
// 使用Connection来创建一个Statment对象
Statement stmt = conn.createStatement())
{
// 需要使用100条SQL语句来插入100条记录
for (int i = 0; i < 1000 ; i++ )
{
stmt.executeUpdate("insert into student_table values("
+ " null ,'姓名" + i + "' , 1)");
}
System.out.println("使用Statement费时:"
+ (System.currentTimeMillis() - start));
}
}
public void insertUsePrepare()throws Exception
{
long start = System.currentTimeMillis();
try(
// 获取数据库连接
Connection conn = DriverManager.getConnection(url
, user , pass);
// 使用Connection来创建一个PreparedStatement对象
PreparedStatement pstmt = conn.prepareStatement(
"insert into student_table values(null, ,1)"))
{
// 100次为PreparedStatement的参数设值,就可以插入100条记录
for (int i = 0; i < 1000 ; i++ )
{
pstmt.setString(1 , "姓名" + i);
pstmt.executeUpdate();
}
System.out.println("使用PreparedStatement费时:"
+ (System.currentTimeMillis() - start));
}
}
public static void main(String[] args) throws Exception
{
PreparedStatementTest pt = new PreparedStatementTest();
pt.initParam("mysql.ini");
pt.insertUseStatement();
pt.insertUsePrepare();
}
}
复制代码
mysql.ini:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/select_test
user=root
pass=111
result:
使用Statement费时:71269
使用PreparedStatement费时:69226
除了性能上的优势,prepareStatement还有另一个优势: 无须在SQL语句中"拼接"SQL参数,从安全的角度来看,这就从很大程序上避免了"SQL注入"的发生。使用prepareStatement时,所有的参数都变成了"问号占位符",也就避免了数据和代码的混淆(这是造成注入的根本原因)
关于使用参数化预编译防御SQL注入,这里要注意几点:
1. 参数化预编译之所以能防御住SQL注入,只要是基于以下2点:
1) setString(): WEB程序接收字符串的场景
将用户输入的参数全部强制转换为字符串,并进行适当的转义,防止了闭合的产生
2) setInt(): WEB程序接收整型的场景
将用户输入的非整型参数强制转换为整型,并去除潜在的"非整型注入字符",类似与 PHP中的intVal()防御思路
2. 并不是说使用了参数化预编译方法执行SQL,就不会有注入的发生了,当WEB系统和DataBase系统的字符集配置不当,可能会导致宽字节注入的发生
0x3: prepareCall存储过程对象
调用存储过程可以使用CallableStatement,程序员通过Connection的prepareCall()方法创建CallableStatement对象
创建存储过程
delimiter //
create procedure add_pro(a int, b int, out sum int)
begin