JDBC

预处理SQL

在日常开发中,我们经常会根据用户输入的信息从数据库中进行数据筛选
现要根据用户输入的学生姓名查询学生信息

Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.next();
String sql = "SELECT id, name, sex, age FROM stu WHERE name='" + name + "'";

如果此时用户输入信息为: 张华' or 1='1 , 那么,上面的代码执行后 SQL 语句变为:

SELECT id, name, sex, age FROM stu WHERE name='张华' or 1='1'

明显查询的结果发生了变化,这样的情况被称作为 SQL 注入。为了防止 SQL 注入,Java 提供了 PreparedStatement 接口对 SQL 进行预处理,该接口是 Statement 接口的子接口,其常用方法

//执行查询,得到一个结果集
ResultSet executeQuery() throws SQLException;
//执行更新,得到受影响的行数
int executeUpdate() throws SQLException;
//使用给定的整数值设置给定位置的参数
void setInt(int parameterIndex, int x) throws SQLException;
//使用给定的长整数值设置给定位置的参数
void setLong(int parameterIndex, long x) throws SQLException;
//使用给定的双精度浮点数值设置给定位置的参数
void setDouble(int parameterIndex, double x) throws SQLException;
//使用给定的字符串值设置给定位置的参数
void setString(int parameterIndex, String x) throws SQLException;
//使用给定的对象设置给定位置的参数
void setObject(int parameterIndex, Object x) throws SQLException;
//获取结果集元数据
ResultSetMetaData getMetaData() throws SQLException;

获取 PreparedStatement 接口对象

PreparedStatement ps = connection.prepareStatement(sql);

PreparedStatement 进行预处理的原理

使用 PreparedStatement 时, SQL 语句中的参数一律使用 ? 号来进行占位,然后通过调用setXxx()方法来对占位的 ? 号进行替换。从而将参数作为一个整体进行查询。上面的示例使用 PreparedStatement 编写 SQL 语句为

Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.next();
String sql = "SELECT id, name, sex, age FROM stu WHERE name=?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, name);
ResultSet rs = ps.executeQuery();

反射

Class类

我们编写的 Java 程序先经过编译器编译,生成class文件,而class文件的执行场所是在 JVM 中,那么
JVM 如何存储我们编写的类的信息?
首先我们回想一下,一个类有哪些组成部分?

public class Class {
    
    private String name; //类名
    
    private Package pk; //包名
    
    private Constructor[] constructors; //构造方法,因为可能存在多个,所以使用数组
    
    private Field[] fields; //字段,因为可能存在多个,所以使用数组
    
    private Method[] methods; //方法,因为可能存在多个,所以使用数组
    
    private Class<?> interfaces; //实现的接口,因为可能存在多个,所以使用数组
    
    private Class<?> superClass; //继承的父类
    
    //省略getter/setter
}

为什么要设计这样的类?因为我们编写的程序从本质上来说也是文件, JVM 加载类的过程相当于对文件内容进行解析,解析内容就需要找到共有特征( Class 类定义),然后再将这特征(使用 Class 对象)存储起来,在使用的时候再取出来。通过 Class 对象反向推到我们编写的类的内容,然后再进行操作,这个过程就称为反射。在 JDK 中已经提供了这样的类: java.lang.Class , 因此,我们不需要再来设计,只需要学习它即可。如何获取一个类对应的 Class 对象呢?

//获取类中使用public修饰的字段
public Field[] getFields() throws SecurityException;
//获取类中定义的所有字段
public Field[] getDeclaredFields() throws SecurityException;
//通过给定的字段名获取类中定义的字段
public Field getField(String name) throws NoSuchFieldException, 
SecurityException;
//获取类中使用public修饰的方法
public Method[] getMethods() throws SecurityException;
//获取类中定义的所有方法
public Method[] getDeclaredMethods() throws SecurityException;
//通过给定的方法名和参数列表类型获取类中定义的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException;
//获取类中使用public修饰的构造方法
public Constructor<?>[] getConstructors() throws SecurityException;
//通过给定的参数列表类型获取类中定义的构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException;
//获取类的全限定名
public String getName();
//获取类所在的包
public Package getPackage();
//判断该类是否是基本数据类型
public native boolean isPrimitive();
//判断该类是否是接口
public native boolean isInterface();
//判断该类是否是数组
public native boolean isArray();
//通过类的无参构造创建一个实例
public T newInstance() throws InstantiationException, IllegalAccessException;
posted @ 2025-08-27 22:36  北燃  阅读(5)  评论(0)    收藏  举报