PrepareStatement是 Statement的子接口,能够传入带占位符的 SQL语句,提供了补充占位符变量的方法。
使用 prepareStatement:java
1. 建立 PrepareStatement对象sql
2. 调用 PrepareStatement的 setXxx(int index, Object val) 设置占位符的值,索引值从1开始。
3. 执行 SQL语句: executeQuery() 或 executeUpdate().。执行时不须要再传入 SQL 语句。数据库
/** * PrepareStatement是 Statement的子接口,能够传入带占位符的 SQL语句 * 提供了补充占位符变量的方法。 * * 使用 prepareStatement: * 1. 建立 PrepareStatement对象 * String sql = "INSERT INTO Student VALUES(?,?,?,?,?,?)"; * PrepareStatement ps = conn.prepareStatement(sql); * 2. 调用 PrepareStatement的 setXxx(int index, Object val) 设置占位符的值 * 索引值从1开始。 * 3. 执行 SQL语句: executeQuery() 或 executeUpdate(). * 执行时不须要再传入 SQL 语句。 */ @Test public void test8() { Connection conn = null; PreparedStatement preparedStatement = null; try { //获取数据库链接 conn = getConnection2(); //设置 SQL语句 String sql = "INSERT INTO Student(Sno, Sname, Ssex, Sage, Sdept, S_entrance) " + "VALUES(?,?,?,?,?,?)"; //为占位符赋值 preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1, "201415411"); preparedStatement.setString(2, "李明"); preparedStatement.setString(3, "男"); preparedStatement.setInt(4, 20); preparedStatement.setString(5, "CS"); preparedStatement.setDate(6, Date.valueOf("2014-09-09")); //执行 SQL语句 preparedStatement.executeUpdate(); } catch(Exception e) { e.printStackTrace(); } finally { if(preparedStatement != null) { try { preparedStatement.close(); } catch(Exception e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(Exception e) { e.printStackTrace(); } } } } //getConnection2()方法 public Connection getConnection2() throws Exception { //1.准备链接数据库的4个字符串 //1.1 建立Properties对象 Properties properties = new Properties(); //1.2 获取jdbc.properties对应的输入流 java.io.InputStream in = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties"); //1.3 加载文件 properties.load(in); //1.4 给字符串赋值 String driver = properties.getProperty("driver"); String jdbcUrl = properties.getProperty("jdbcUrl"); String user = properties.getProperty("user"); String password = properties.getProperty("password"); //2.加载数据库驱动程序(对应的Driver实现类中有注册驱动的静态代码块) Class.forName(driver); //3.经过DriverManager的getConnection方法获取数据库链接 return DriverManager.getConnection(jdbcUrl, user, password); }
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的作法。缓存
对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement 取代 Statement 就能够了。性能优化
以下程序,使用Statement,有SQL注入风险函数
/** * 用户表中有两列:用户username和密码password * 只有当用户和密码都正确时,登录成功,不然不成功 * */ @Test public void test9() { //当用户名和密码设置以下,表中不存在这个用户名和密码,可是任然能够登陆成功 String username = "a' OR password = "; String userpassword = " OR '1'='1"; String sql = "SELECT * FROM Users WHERE username = '" + username +"' AND " + "password= '" + userpassword + "'"; Connection conn = null; Statement statement = null; ResultSet resultSet = null; try { conn = getConnection2(); statement = conn.createStatement(); resultSet = statement.executeQuery(sql); if(resultSet.next()) { System.out.println("登录成功!"); } else { System.out.println("用户名和密码不匹配或用户不存在"); } } catch(Exception e) { e.printStackTrace(); } finally { if(resultSet != null) { try { resultSet.close(); } catch(Exception e) { e.printStackTrace(); } } if(statement != null) { try { statement.close(); } catch(Exception e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(Exception e) { e.printStackTrace(); } } } }
当用户名和密码这样设置时:性能
String username = "a' OR password = ";
String userpassword = " OR '1'='1";学习
尽管表中没有这个用户名和密码,但依然能够登陆,此时SQL语句为:优化
SELECT * FROM Student WHERE username = 'a' OR password = ' AND Sno= ' OR '1'='1'this
如上,username的值为 a,password的值为 AND Sno=。整个WHERE条件是或条件判断,而 '1'='1' 是恒成立的,因此这条语句会执行。
使用PreparedStatement,将有效的解决注入问题
/** * 使用 PreparedStatement将有效的解决注入问题 * */ @Test public void test10() { String username = "a' OR Sno = "; String userpassword = " OR '1'='1"; String sql = "SELECT * FROM Users WHERE username = ?" + " AND password= ?"; Connection conn = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { conn = getConnection2(); preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1, username); preparedStatement.setString(2, userpassword); resultSet = preparedStatement.executeQuery(); if(resultSet.next()) { System.out.println("登录成功!"); } else { System.out.println("用户名和密码不匹配或用户不存在"); } } catch(Exception e) { e.printStackTrace(); } finally { if(resultSet != null) { try { resultSet.close(); } catch(Exception e) { e.printStackTrace(); } } if(preparedStatement != null) { try { preparedStatement.close(); } catch(Exception e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(Exception e) { e.printStackTrace(); } } } }
JDBC学习笔记:
1. 获取数据库链接 http://my.oschina.net/daowuming/blog/704243
2. 经过Statement执行更新、查询操做 http://my.oschina.net/daowuming/blog/704384
3. 使用PrepareStatement ----当前----
4. 使用ResultSetMetaData 对象处理结果集元数据 http://my.oschina.net/daowuming/blog/704487
5. 使用DatabaseMetaData获取数据库信息 http://my.oschina.net/daowuming/blog/704553
6. BLOB http://my.oschina.net/daowuming/blog/704593
7. 处理事务与隔离级别 http://my.oschina.net/daowuming/blog/704611
8. 批量处理 http://my.oschina.net/daowuming/blog/704641
9. 数据库链接池 http://my.oschina.net/daowuming/blog/704700
10. 调用函数与存储过程 http://my.oschina.net/daowuming/blog/704813