jdbc核心类库有

  • DriverManager
  • Connection
  • Statement
  • ResultSet

DriverManager的作用

  • 注册驱动:可以让JDBC知道使用的是哪个驱动
  • 获取Connection连接对象:如果能获取到Connection对象,说明已经成功连接到了

Connection 的作用

  • 用来获取发送器对象Statement,这样数据库就可以发送sql语句了

Statement

  • 常用的方法 
    • executeUpdate(String sql)执行更新操作,insert ,update,delete等,其实也可以执行create table , alter table , drop table 等操作,但是不建议使用
    • executeQuery(String sql)执行sql的查询语句,返回值是一个结果集对象ResultSet
  • 不常用的方法,但是要知道 
    • execute(String sql) 使用这方式,可以输入任何sql语句,但是由于他的返回值只是布尔值,我们不能清楚到底操作了几行, 
      • 所以这个方法一般要配合getUpdateCount()方法来获取影响的行数
      • 如果执行的是查询操作还需要,通过Result的getResultSet()来获取查询语句的结果

ResultSet

  • 就是一张二维的表格,它内部有一个“行光标”,光标默认 的位置在第一行的上面
  • 常用的方法 
    • next() 光标向下移动一行
    • getxxx(String 列名) 获取指定列的值
  • 不常用的方法 
    • beforeFirst()将光标移动到第一行的前面。也就是默认的起始位置。
    • afterLast()将光标移动到最后一行的后面
    • first()将光标移动到第一行的位置
    • last()将光标移动到最后一行的位置
    • isBeforeFirst()当前光标是否在第一行的前面位置
    • isAfterLast()当前光标是否在最后一行的后面
    • isFirst()当前的光标是否在第一行
    • isLast()当前的光标是否在最后一行
    • previous()当前的光标位置向上移动一行
    • relative(int row):相对位移,当row为正数 的时候,表示向下移动row行,为负数时,表示向上移动row行
    • absolute(int row)将光标移动到指定的位置上
    • int getRow() 返回当前所有的光标行,一半用来获取数据的行数。

JDBC结果集的特性

  • 方法: 
    Statement createStatement(int resultSetType, 
    int resultSetConcurrency)
  • 参数:

    • 第一个参数 
      • ResultSet.TYPE_FORWARD_ONLY:不滚动结果集;
      • ResultSet.TYPE_SCROLL_INSENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化;
      • ResultSet.TYPE_SCROLL_SENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化;( 
        没有数据库驱动会支持它! )
    • 第二个参数 
      • CONCUR_READ_ONLY:结果集是只读的,不能通过修改结果集而反向影响数据库;
      • CONCUR_UPDATABLE:结果集是可更新的,对结果集的更新可以反向影响数据库。
  • 是否滚动

    • 如果结果集不可滚动,那么只能使用next()方法来移动行标,但是判断行标位置的方法还是可以使用的。
    • 不可滚动禁用的方法: 
      • beforeFirst()
      • first()
      • last()
      • afterLast()
      • previous()
      • relative()
  • 是否更新:结果集改变,数据库也改变
  • 是否敏感:数据库改变,结果集合也改变

==注意== 
使用Connection.createStatement()方法创建的结果结合是不滚动,不敏感,不更新

PreparedStatement的用法

  • PrepareStatement 是Statement 的一个子接口,它更加强大 ,能够防止sql攻击
  • 提高代码的可维护性,可读性
  • 提高效率
  • Statement 漏洞实例
    • sql漏洞代码演示


import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; public class Demo2 { /** * 测 是sql漏洞 * @author lien * @throws SQLException * */ public boolean Bug(String username , String password) throws SQLException{ /* * 四大参数 * DriverClassName com.mysql.jdbc.Driver * url jdbc:mysql://localhost:3306/mydatabase1 * user root * mypassword root * */ String url = "jdbc:mysql://localhost:3306/mydatabase1"; String user = "root"; String mypassword = "root"; // 对象引用声明 Connection con = null; Statement state = null; ResultSet query = null; //加载驱动类 try { Class.forName("com.mysql.jdbc.Driver"); // 获得连接对象 con = DriverManager.getConnection(url, user, mypassword); // 获得发送器对象 state = con.createStatement(); //发送查询语句 String sql = "select * from teacher where name='"+username + "' and age='"+password +"'"; System.out.println(sql); //获得结果集合对象 query = state.executeQuery(sql); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return query.next(); } @Test public void test(){ try { /* * 这里写了一个假条建,肯定是a=a肯定成立,那么就算name属性验证了不正确,但是结果还是ture * select * from teacher where name='a' or 'a'='a' and age='66' or '1'='1' */ boolean bug = this.Bug("a' or 'a'='a", "66' or '1'='1"); System.out.println(bug); } catch (SQLException e) { e.printStackTrace(); } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 使用PreparedStatement解决步骤 
    • 创建sql模板 
      • 参数使用?代替:例如:”select * from teacher where name=? and age=?”
      • 通过模板获得发送器对象:pst = con.prepareStatement(sqlpattern);
      • 调用发送器pst的setxxx()方法。为参数赋值
      • 调用控参数的查询方法


import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; public class Demo2 { /** * 测 是sql漏洞 * @author lien * @throws SQLException * */ public boolean Bug(String username , int password) throws SQLException{ /* * 四大参数 * DriverClassName com.mysql.jdbc.Driver * url jdbc:mysql://localhost:3306/mydatabase1 * user root * mypassword root * */ String url = "jdbc:mysql://localhost:3306/mydatabase1"; String user = "root"; String mypassword = "root"; // 对象引用声明 Connection con = null; PreparedStatement pst = null; ResultSet query = null; //加载驱动类 try { Class.forName("com.mysql.jdbc.Driver"); // 获得连接对象 con = DriverManager.getConnection(url, user, mypassword); // sql模板,参数的地方使用?代替 String sqlpattern = "select * from teacher where name=? and age=?"; // 获得发送器对象 pst = con.prepareStatement(sqlpattern); //为参数赋值 pst.setString(1, username); pst.setInt(2, password); //调用查询方法 query = pst.executeQuery(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return query.next(); } @Test public void test(){ try { boolean bug = this.Bug("小明", 76); System.out.println(bug); } catch (SQLException e) { e.printStackTrace(); } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

statement 和preparedStatement 区别

  • PreparedStatement继承了Statement(parparedStatement是statement的一个子接口)
  • PreparedStatement可以写动态参数化的查询
  • PreparedStatement比 Statement 更快
  • PreparedStatement可以防止SQL注入式攻击

预处理的原理

  • 服务器的工作 
    • 校验sql语法的正确性
    • 编译:一个与函数相似的东西
    • 执行:调用函数
  • PreparedStatement 
    • 前提:连接的数据库必须支持预处理
    • 每个preparedstatement 都和sql模板绑定在一起,先把sql模板给数据库,数据库先进行校验,在进行编译,此时只是把参数传递过去而已
    • 若二次执行,就不需要再次校验sql语法,也不用编译,直接执行。