Spring JPA原生查询参数前自动加单引号导致跨库关联SQL报错问题
参数被自动添加单引号的原因
JPA的参数绑定基于JDBC预编译SQL(PreparedStatement)实现,仅支持对查询值做参数化处理,库名、表名、字段名这类属于SQL语法结构的标识符,不属于值参数范畴,预编译时会自动将传入的字符串识别为字符串值,自动添加单引号,最终导致SQL语法错误。WHERE条件中的参数属于合法的值参数,符合预编译参数的适用场景,因此不会出现额外加单引号的问题。
实现参数化库名/表名跨库关联原生查询的方案
目前有两种稳定可行的实现方式:
方案1:使用SpEL表达式实现动态替换
Spring Data JPA支持在@Query注解中使用SpEL表达式直接拼接参数,不会将参数作为预编译值处理,语法为#{#参数名},改造后的代码如下:
@Query(value = "select Student.id as id , Student.name as studentname, Teacher.name as teachername from #{#firstdatabase} inner join #{#seconddatabase} on Student.id = Teacher.id", nativeQuery = true) List<StudentTeacher> getListStudentTeacher(@Param("firstdatabase") String firstdatabase, @Param("seconddatabase") String seconddatabase);
注意:该方式存在SQL注入风险,必须严格校验传入的库名、表名的合法性,建议仅允许传入预设白名单内的库表名称,禁止直接传递用户可控的原始字符串作为参数。
方案2:使用EntityManager自定义原生SQL
如果需要更灵活的SQL拼接逻辑,可以直接注入EntityManager手动构造查询语句:
@Autowired private EntityManager entityManager; public List<StudentTeacher> getListStudentTeacher(String firstDatabase, String secondDatabase) { // 先做库表参数合法性校验,避免SQL注入 if (!isValidDbTable(firstDatabase) || !isValidDbTable(secondDatabase)) { throw new IllegalArgumentException("非法的库表参数"); } String sql = "select Student.id as id , Student.name as studentname, Teacher.name as teachername from " + firstDatabase + " inner join " + secondDatabase + " on Student.id = Teacher.id"; Query query = entityManager.createNativeQuery(sql, StudentTeacher.class); return query.getResultList(); }
- 该方式同样需要做严格的参数校验,所有动态拼接的库表参数必须经过白名单或者规则校验。
内容的提问来源于stack exchange,提问作者Shrayan Santra
相关产品推荐
相关产品推荐

