(三)JDBC-SQL注入漏洞和CRUD操作之PreparedStatement

本文深入解析SQL注入漏洞,展示如何通过PreparedStatement防止SQL注入,同时提供JDBC的CRUD操作实例,包括批量处理和批处理技巧,帮助开发者提升数据库操作的安全性和效率。

一、SQL注入漏洞分析

1、分析

 

2、测试

public class UserDao {
   
   /**
    * 完成用户登录的方法:解决SQL注入漏洞
    * @param username
    * @param password
    * @return
    */
   public boolean login2(String username,String password){
      Connection conn = null;
      PreparedStatement pstmt = null;
      ResultSet rs = null;
      // 定义一个变量:
      boolean flag = false;
      try{
         // 获得连接:
         conn = JDBCUtil.getConnection();
         // 编写SQL语句:
         String sql = "select * from user where username = ? and password = ?";
         // 预编译SQL
         pstmt = conn.prepareStatement(sql);
         // 设置参数:
         pstmt.setString(1, username);
         pstmt.setString(2, password);
         // 执行SQL语句:
         rs = pstmt.executeQuery();
         if(rs.next()){
            // 说明根据用户名和密码可以查询到这条记录
            flag = true;
         }
      }catch(Exception e){
         e.printStackTrace();
      }finally{
         JDBCUtil.release(rs, pstmt, conn);
      }
      return flag;
   }
​
/* *//**
    * 用户登录的方法
    * @param username
    * @param password
    * @return
    */
   public boolean login1(String username,String password){
      
      Connection conn = null;
      Statement stmt = null;
      ResultSet rs = null;
      // 定义一个变量:
      boolean flag = false;
      try{
         // 获得连接:
         conn = JDBCUtil.getConnection();
         // 完成登录功能:
         // 创建执行SQL语句的对象:
         stmt = conn.createStatement();
         // 编写SQL语句:
         String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";
         // 执行SQL:
         rs = stmt.executeQuery(sql);
         if(rs.next()){
            // 说明根据用户名和密码可以查询到这条记录
            flag = true;
         }
      }catch(Exception e){
         e.printStackTrace();
      }finally{
         JDBCUtil.release(rs, stmt, conn);
      }
      return flag;
   }
}

测试类

    public static void main(String[] args) {
      UserDao userDao = new UserDao();
//    boolean flag = userDao.login("aaa", "123");
//    boolean flag = userDao.login("aaa' or '1=1", "asdfjklsd");
      boolean flag = userDao.login2("aaa' -- ", "qweqwersdfsd");
      if(flag){
         System.out.println("登录成功!");
      }else{
         System.out.println("登录失败!");
      }
   }

3、SQL注入漏洞解决

需要采用PreparedStatement对象解决SQL注入漏洞。这个对象将SQL预先进行编译,使用?作为占位符。?所代表内容是SQL所固定。再次传入变量(包含SQL的关键字)。这个时候也不会识别这些关键字。

二、JDBC的CRUD操作之PreparedStatement的保存操作

1、代码

@Test
public void insert() {
    Connection conn = null;
    PreparedStatement pstmt = null;
    try {
        // 获得连接:
        conn = JDBCUtil.getConnection();
        // 编写SQL语句:
        String sql = "insert into user values (null,?,?,?,?)";
        // 预编译SQL:
        pstmt = conn.prepareStatement(sql);
        // 设置参数:
        pstmt.setString(1, "一");
        pstmt.setString(2, "二");
        pstmt.setString(3, "三");
        pstmt.setInt(4, 4);
        // 执行SQL
        int num = pstmt.executeUpdate();
        if (num > 0) {
            System.out.println("保存成功!");
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.release(pstmt, conn);
    }
}

2、执行结果

 

转存失败重新上传取消

三、修改操作

1、代码

@Test
/**
 * 修改操作
 */
public void modify(){
    Connection conn = null;
    PreparedStatement pstmt = null;
    try{
        // 获得连接:
        conn = JDBCUtil.getConnection();
        // 编写SQL语句:
        String sql = "update user set username = ?,password =?,nickname=?,age = ? where id = ?";
        // 预编译SQL:
        pstmt = conn.prepareStatement(sql);
        // 设置参数:
        pstmt.setString(1, "name");
        pstmt.setString(2, "pwd");
        pstmt.setString(3, "nick");
        pstmt.setInt(4, 24);
        //修改的id值
        pstmt.setInt(5, 1);
        // 执行SQL:
        int num = pstmt.executeUpdate();
        if(num > 0){
            System.out.println("修改成功!");
        }
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        JDBCUtil.release(pstmt, conn);
    }
}

四、删除操作

1、代码

@Test
/**
 * 删除操作
 */
public void delete(){
    Connection conn = null;
    PreparedStatement pstmt  = null;
    try{
        // 获得连接:
        conn = JDBCUtil.getConnection();
        // 编写SQL语句:
        String sql = "delete from user where id = ?";
        // 预编译SQL
        pstmt = conn.prepareStatement(sql);
        // 设置参数:
        pstmt.setInt(1, 4);
        // 执行SQL:
        int num = pstmt.executeUpdate();
        if(num > 0){
            System.out.println("删除成功!");
        }
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        JDBCUtil.release(pstmt, conn);
    }
}

五、查询

1、代码

@Test
/**
 * 查询操作
 */
public void query(){
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try{
        // 获得连接:
        conn = JDBCUtil.getConnection();
        // 编写SQL:
        String sql = "select * from user";
        // 预编译SQL:
        pstmt = conn.prepareStatement(sql);
        // 设置参数:
        // 执行SQL:
        rs = pstmt.executeQuery();
        // 遍历结果集:
        while(rs.next()){
            System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname"));
        }
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        JDBCUtil.release(rs, pstmt, conn);
    }
}

六、JDBC的批处理

之前进行JDBC的操作的时候,都是一条SQL语句执行。现在如果使用批处理,可以将一批SQL一起执行。

1、代码

@Test
/**
 * 批处理基本操作
 */
public void batch(){
    Connection conn = null;
    Statement stmt = null;
    try{
        // 获得连接:
        conn = JDBCUtil.getConnection();
        // 创建执行批处理对象:
        stmt = conn.createStatement();
        // 编写一批SQL语句:
        String sql1 = "create database test1";
        String sql2 = "use test1";
        String sql3 = "create table user(id int primary key auto_increment,name varchar(20))";
        String sql4 = "insert into user values (null,'aaa')";
        String sql5 = "insert into user values (null,'bbb')";
        String sql6 = "insert into user values (null,'ccc')";
        String sql7 = "update user set name = 'tom' where id = 2";
        String sql8 = "delete from user where id = 1";
        // 添加到批处理
        stmt.addBatch(sql1);
        stmt.addBatch(sql2);
        stmt.addBatch(sql3);
        stmt.addBatch(sql4);
        stmt.addBatch(sql5);
        stmt.addBatch(sql6);
        stmt.addBatch(sql7);
        stmt.addBatch(sql8);
        // 执行批处理:
        stmt.executeBatch();
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        JDBCUtil.release(stmt, conn);
    }
}

七、批量插入(使用PreparedStatement)

@Test
/**
 * 批量插入记录:
 * * 默认情况下MySQL批处理没有开启的,需要在url后面拼接一个参数即可。
 * jdbc:mysql://localhost:3306/mydb?rewriteBatchedStatements=true
 */
public void batchInster(){
    // 记录开始时间:
    long begin = System.currentTimeMillis();
    Connection conn = null;
    PreparedStatement pstmt = null;
    try{
        // 获得连接:
        conn = JDBCUtil.getConnection();
        // 编写SQL语句:
        String sql = "insert into test1.user values (null,?)";
        // 预编译SQL:
        pstmt = conn.prepareStatement(sql);
        for(int i=1;i<=10000;i++){
            pstmt.setString(1, "name"+i);
            // 添加到批处理
            pstmt.addBatch();
            // 注意问题:
            // 执行批处理
            if(i % 1000 == 0){
                // 执行批处理:
                pstmt.executeBatch();
                // 清空批处理:
                pstmt.clearBatch();
            }
        }
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        JDBCUtil.release(pstmt, conn);
    }
    long end = System.currentTimeMillis();
    System.out.println((end-begin));
}

 

扫一扫关注我
扫一扫关注我
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值