JPQL 占位符

前面章节在没有介绍 OpenJPA 的占位符之前,我们创建本地查询时,如果存在条件,直接使用“+”符号进行 SQL 语句字符串连接。示例代码如下:

int age = 50;
float salary = 4000.0f;
Query query = em.createNativeQuery(
        "select id, name, age, salary from user " +
        " where age < " + age + " and salary > " + salary, User.class);
List<User> list = query.getResultList();
for(User user : list) {
    System.out.println(user);
}

上面拼接 SQL 语句的方式容易出现 SQL 注入问题。那什么是 SQL 注入呢?

SQL注入指 web 应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在 web 应用程序中事先定义好的查询语句的结尾上添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

非常庆幸的是,OpenJPA 中提供了三种方式的占位符,分别如下:

  • ?:传统 JDBC 方式的占位符,仅仅适应本地SQL查询;

  • ?n:传统 ? 占位符的改良占位符,仅仅适应JPQL查询

  • ?name:变量名形式的占位符,仅仅适应JPQL查询

? 占位符

该种占位符和传统 JDBC 占位符一致,仅仅用于本地 SQL 查询。代码如下:

Query query = em.createNativeQuery(
        "select id, name, age, salary from user " +
        " where age < ? and salary > ?", User.class);
query.setParameter(1, 50);
query.setParameter(2, 4000.0f);
List<User> list = query.getResultList();
for(User user : list) {
    System.out.println(user);
}

输出 SQL 日志如下:

select id, name, age, salary from user  where age < ? and salary > ? [params=?, ?]
User{id=3, name='用户-2', age=44, salary=5855.36}
User{id=4, name='用户-3', age=10, salary=4105.1895}
User{id=10, name='用户-9', age=26, salary=6327.472}

注意:参数位置必须从1开始,否则将抛出如下错误:

Exception in thread "main" <openjpa-2.4.2-r422266:1777108 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Parameter 1 in SQL Query "select id, name, age, salary from user  where age < ? and salary > ?" is not given a value. The parameters given is "{2=50, 3=4000.0}".

?n 占位符

该占位符是传统 ? 占位符的改良版本,仅仅适应JPQL查询。代码如下:

Query query = em.createQuery(
        "select t from User t" +
        " where t.age < ?1 and t.salary > ?2", User.class);
query.setParameter(1, 50);
query.setParameter(2, 4000.0f);
List<User> list = query.getResultList();
for(User user : list) {
    System.out.println(user);
}

输出 SQL 日志如下:

SELECT t0.id, t0.age, t0.name, t0.salary FROM User t0 WHERE (t0.age < ? AND t0.salary > ?) [params=?, ?]
User{id=3, name='用户-2', age=44, salary=5855.36}
User{id=4, name='用户-3', age=10, salary=4105.1895}
User{id=10, name='用户-9', age=26, salary=6327.472}

注意,setParameter() 方法的参数一取值从1开始;如果不是,则抛出如下错误信息:

Exception in thread "main" <openjpa-2.4.2-r422266:1777108 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Query "select t from User t where t.age < ?2 and t.salary > ?3" did not contain positional parameter 1. JPQL positional parameters must start at 1. Detected parameters "[2, 3]".

?name 占位符

变量名形式的占位符是推荐使用的占位符,便于开发者查看,特别是参数多的时候,?n 占位符还需要自己逐个进行比对,不是很方便。注意,该占位符仅仅适应JPQL查询。代码如下:

Query query = em.createQuery(
        "select t from User t" +
        " where t.age < :age and t.salary > :salary", User.class);
query.setParameter("age", 50);
query.setParameter("salary", 4000.0f);
List<User> list = query.getResultList();
for(User user : list) {
    System.out.println(user);
}

输出 SQL 日志如下:

SELECT t0.id, t0.age, t0.name, t0.salary FROM User t0 WHERE (t0.age < ? AND t0.salary > ?) [params=?, ?]
User{id=3, name='用户-2', age=44, salary=5855.36}
User{id=4, name='用户-3', age=10, salary=4105.1895}
User{id=10, name='用户-9', age=26, salary=6327.472}

注意,如果将该种占位符应用到本地 SQL 查询,会抛出如下错误信息:

Exception in thread "main" java.lang.IllegalArgumentException: Named parameter "age" is used in native SQL query "select id, name, age, salary from user  where age < :age and salary > :salary". But named parameter is not allowed in native SQL query, use integer parameter ?1, ?2 etc.
说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号