• JDBC-02:操作访问数据库时使用Statement操作数据表的弊端


    对数据库的基本操作

    (1)操作和访问数据库
    • 数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。
    • 在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:
      • Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。(不用)
      • PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
      • CallableStatement:用于执行 SQL 存储过程
        在这里插入图片描述

    (2)使用Statement操作数据表的弊端
    • 通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。

    • Statement 接口中定义了下列方法用于执行 SQL 语句:

      int excuteUpdate(String sql):执行更新操作INSERTUPDATEDELETE
      ResultSet executeQuery(String sql):执行查询操作SELECT
      
      • 1
      • 2
    • 但是使用Statement操作数据表存在弊端:

      • 问题一:存在拼串操作,繁琐
      • 问题二:存在SQL注入问题
    • SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法。

    • 对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。

    运行结果为:

    在这里插入图片描述

    代码(解释在代码后面):

    package com.jsm.java1;
    
    import java.io.InputStream;
    import java.lang.reflect.Field;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    import java.util.Scanner;
    
    import org.junit.Test;
    
    public class StatementTest {
       public static void main(String[] args) {
          Scanner scanner = new Scanner(System.in);
          System.out.print("请输入用户名:");
          String user = scanner.nextLine();
          System.out.print("请输入密码:");
          String password = scanner.nextLine();
              // 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
    //   SQL注入的问题:
          /*
          SELECT user,password FROM user_table WHERE user='1' or ' AND password= '=1 or '1' = '1'
    
           */
    
          //需要拼写sql语句
          String sql="SELECT user,password FROM user_table WHERE user='"+user+"' AND password='"+password+"'";
    
          User user1 = get(sql, User.class);
          if (user1!=null){
             System.out.println("登录成功!!");
          }else {
             System.out.println("登录失败!");
          }
       }
    
     
       // 使用Statement实现对数据表的查询操作
       public static  <T> T  get(String sql, Class<T> clazz) {
          T t = null;
    
          Connection conn = null;
          Statement st = null;
          ResultSet rs = null;
          try {
             // 1.加载配置文件
             InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
             Properties pros = new Properties();
             pros.load(is);
    
             // 2.读取配置信息
             String user = pros.getProperty("user");
             String password = pros.getProperty("password");
             String url = pros.getProperty("url");
             String driverClass = pros.getProperty("driverClass");
    
             // 3.加载驱动
             Class.forName(driverClass);
    
             // 4.获取连接
             conn = DriverManager.getConnection(url, user, password);
    
             st = conn.createStatement();
    
             rs = st.executeQuery(sql);
    
             // 获取结果集的元数据
             ResultSetMetaData rsmd = rs.getMetaData();
    
             // 获取结果集的列数
             int columnCount = rsmd.getColumnCount();
    
             if (rs.next()) {
    
                t = clazz.newInstance();
    
                for (int i = 0; i < columnCount; i++) {
                   // //1. 获取列的名称
                   // String columnName = rsmd.getColumnName(i+1);
    
                   // 1. 获取列的别名
                   String columnName = rsmd.getColumnLabel(i + 1);
    
                   // 2. 根据列名获取对应数据表中的数据
                   Object columnVal = rs.getObject(columnName);
    
                   // 3. 将数据表中得到的数据,封装进对象
                   Field field = clazz.getDeclaredField(columnName);
                   field.setAccessible(true);
                   field.set(t, columnVal);
                }
                return t;
             }
          } catch (Exception e) {
             e.printStackTrace();
          } finally {
             // 关闭资源
             if (rs != null) {
                try {
                   rs.close();
                } catch (SQLException e) {
                   e.printStackTrace();
                }
             }
             if (st != null) {
                try {
                   st.close();
                } catch (SQLException e) {
                   e.printStackTrace();
                }
             }
    
             if (conn != null) {
                try {
                   conn.close();
                } catch (SQLException e) {
                   e.printStackTrace();
                }
             }
          }
    
          return null;
       }
    
    }
    
    • 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
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129

    解释:如下


    (3)sql注入问题
    • SQL注入攻击是比较常见的网络攻击方式之一

      它不是利用操作系统的BUG来实现攻击,而是发生于应用程序之数据库层的安全漏洞。针对程序员编写时的疏忽通过SQL语句,实现无账号登录,甚至篡改数据库,是在输入的字符串之中注入SQL的指令,那么这些注入进去的指令就会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破坏或是入侵,如下代码

    在上述操作的时候输入

    账号为:1’ or

    密码为:=1 or ‘1’ = '1

    拼凑成了正确的sql指令

    SELECT USER,PASSWORD 
    FROM user_table 
    WHERE USER = '1' OR ' AND password= '=1 OR '1' = '1'
    
    • 1
    • 2
    • 3

    对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。
    PreparedStatement看文章JDBC-03
    以及:JDBC-05:PrepardeStatement解决SQL注入问题

    附加:Java与SQL对应数据类型转换表

    Java类型SQL类型
    booleanBIT
    byteTINYINT
    shortSMALLINT
    intINTEGER
    longBIGINT
    StringCHAR,VARCHAR,LONGVARCHAR
    byte arrayBINARY , VAR BINARY
    java.sql.DateDATE
    java.sql.TimeTIME
    java.sql.TimestampTIMESTAMP

  • 相关阅读:
    树洞外链网盘系统php源码去除底部版权优化版
    乐信—高级Java开发工程师二面(偏业务)
    1488. 避免洪水泛滥
    CentOS安装NPM
    三个要点,掌握Spring Boot单元测试
    一点C知识:数据类型和内存地址。
    Python Matplotlib库:基本绘图补充
    软件设计不是CRUD(15):低耦合模块设计理论——行为抽象与设计模式(中)
    hadoop
    ChatGPT 报错“Sorry, you have been blocked…” 什么原因?如何解决?
  • 原文地址:https://blog.csdn.net/weixin_45869823/article/details/127699156