PrepareStatement相对Statement的优势:
·消除SQL注入的安全漏洞
·Statement会是数据库频繁编译SQL,可能造成数据库缓冲区的溢出
·数据库和相关驱动都可以对PrepareStatement进行优化
JdbcUtils工具类:
/** * 有关mysql数据库的工具类,单例模式SingleTon */ package mysql.base; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * * 2009-9-24 湖南大学 计算机与通信学院 计算机科学与技术专业 * * @author 陈春晓 * */ public final class JdbcUtils { private static String url = "jdbc:mysql://localhost:3306/test"; private static String username = "root"; private static String password = "xiaochun"; private static JdbcUtils instance = null; private JdbcUtils() { }; public static JdbcUtils getInstance() { if (instance == null) { synchronized (JdbcUtils.class) { if (instance == null) instance = new JdbcUtils(); } } return instance; } // 保证驱动只装载一次 static { // 注册驱动,只需要一次 try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 获取一个数据库连接 * * @return Connection * @exception SQLException */ public Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } /** * 释放资源 * * @param ResultSet * rs * @param Statement * st * @param Connection * conn */ public void free(ResultSet rs, Statement st, Connection conn) { try { if (rs != null) rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { if (st != null) st.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { if (conn != null) conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
测试代码:
/** * 测试SQL注入问题,要处理这个漏洞,就需要用PreparedStatement类代替Statement */ package mysql.base; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * * 2009-9-24 湖南大学 计算机与通信学院 计算机科学与技术专业 * * @author 陈春晓 * */ public class SQLInject { /** * @param args * @throws SQLException */ public static void main(String[] args) throws SQLException { // TODO Auto-generated method stub read("xiali"); // 测试SQL inject安全漏洞 read1("xiali"); } /** * 读取数据库,使用PrepareStatement类可以消除sql注入漏洞 * * @param name * @throws SQLException */ public static void read(String name) throws SQLException { // 有SQL inject安全漏洞 String sqlStr = "select id,name,birthday,money from user where name=?"; // System.out.println(sqlStr); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { // 注册驱动,只需要一次 // Class.forName("com.mysql.jdbc.Driver"); // 建立连接 conn = JdbcUtils.getInstance().getConnection(); //long start =System.currentTimeMillis(); // 创建语句 ps = conn.prepareStatement(sqlStr); // 添加参数 ps.setString(1, name); // 执行语句 rs = ps.executeQuery(); // 处理结果 while (rs.next()) { System.out.println(rs.getObject("id") + "\t" + rs.getObject("name") + "\t" + rs.getObject("birthday") + "\t" + rs.getObject("money")); } //long end=System.currentTimeMillis(); //System.out.println("Statement:read() "+(end-start)+"ms"); } finally { JdbcUtils.getInstance().free(rs, ps, conn); } } /** * 存在SQL 注入安全漏洞 * * @param name * @throws SQLException */ public static void read1(String name) throws SQLException { // 有SQL inject安全漏洞 String sqlStr = "select id,name,birthday,money from user where name='" + name + "'"; // System.out.println(sqlStr); Connection conn = null; Statement st = null; ResultSet rs = null; try { // 注册驱动,只需要一次 // Class.forName("com.mysql.jdbc.Driver"); // 建立连接 conn = JdbcUtils.getInstance().getConnection(); //long start =System.currentTimeMillis(); // 创建语句 st = conn.createStatement(); // 执行语句 rs = st.executeQuery(sqlStr); // 处理结果 while (rs.next()) { System.out.println(rs.getObject("id") + "\t" + rs.getObject("name") + "\t" + rs.getObject("birthday") + "\t" + rs.getObject("money")); } //long end=System.currentTimeMillis(); //System.out.println("Statement:read() "+(end-start)+"ms"); } finally { JdbcUtils.getInstance().free(rs, st, conn); } } }