spring-data-jpa JPA CriteriaQuery生成的SQL,嵌套实体ID具有硬编码参数

qxsslcnc  于 2022-11-10  发布在  Spring
关注(0)|答案(1)|浏览(182)

我一直在研究SpringData JPA,在使用CriteriaQuery通过子实体的Id查找给定实体时遇到了这种奇怪的行为,我注意到在生成的SQL中有一个硬编码的child_id参数:

Hibernate: select parent0_.parent_id as parent_i1_4_, parent0_.parent_name as parent_n2_4_, parent0_.parent_type_parent_type_id as parent_t3_4_ from parent parent0_ inner join child children1_ on parent0_.parent_id=children1_.parent_parent_id where children1_.child_id=1

Hibernate: select parent0_.parent_id as parent_i1_4_, parent0_.parent_name as parent_n2_4_, parent0_.parent_type_parent_type_id as parent_t3_4_ from parent parent0_ inner join child children1_ on parent0_.parent_id=children1_.parent_parent_id where children1_.child_id=?

java代码:

父项

@Data
@Entity
public class Parent {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer parentId;

    private String parentName;

    @OneToMany(mappedBy = "parent")
    private List<Child> children;

}

子项

@Builder
@Data
@Entity
public class Child {

    @Id
    private Integer childId;

    private String childName;

    @ManyToOne
    private Parent parent;

}

父DAO

@Repository
public class ParentDAO {

    private EntityManager em;

    public ParentDAO(EntityManager em) {
        this.em = em;
    }

    public List<Parent> findByChildId(Integer childId) {

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Parent> cq = cb.createQuery(Parent.class);
        Root<Parent> root = cq.from(Parent.class);
        List<Predicate> predicates = new ArrayList<>();

        predicates.add(cb.equal(root.join("children").get("childId"), childId));
        cq.where(predicates.toArray(new Predicate[0]));

        return em.createQuery(cq).getResultList();
    }

    public List<Parent> findByChild(Child child) {

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Parent> cq = cb.createQuery(Parent.class);
        Root<Parent> root = cq.from(Parent.class);
        List<Predicate> predicates = new ArrayList<>();

        predicates.add(cb.equal(root.join("children"), child));
        cq.where(predicates.toArray(new Predicate[0]));

        return em.createQuery(cq).getResultList();
    }

}

Spring Data 应用程序

@SpringBootApplication
public class SpringDataApplication implements CommandLineRunner {

    private ParentDAO parentDAO;

    public SpringDataApplication(ParentDAO parentDAO) {
        this.parentDAO = parentDAO;
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringDataApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        parentDAO.findByChildId(1);
        parentDAO.findByChild(Child.builder().childId(1).build());
    }
}

这不是什么大事,因为目标可以通过findByChild方法实现,我只是对这种情况感到好奇。

ql3eal8s

ql3eal8s1#

因为字符串可以包含SQL,而整数不能,所以从安全性的Angular 来看,没有必要进行绑定(SQL注入)。
来自literal_handling_mode的休眠文档:
此枚举定义JPA条件如何处理文字。(AUTO),条件查询将绑定参数用于任何非数字值的文字。但是,为了提高JDBC语句高速缓存的可能性,您可能还希望将绑定参数用于数字值。BIND模式将绑定变量用于任何文字值。INLINE模式将按原样内联文字值。要防止SQL注入,不要在字符串变量中使用INLINE。2总是在INLINE模式中使用常量。
在版本HHH-9576中,添加了一个新参数来修复此问题,自版本5.2.12起适用

<property name="hibernate.criteria.literal_handling_mode" value="bind"/>

或在 Spring Boot www.example.com中application.properties您可以使用

spring.jpa.properties.hibernate.criteria.literal_handling_mode=bind

添加配置后,您的两个查询将看起来与bind参数相同。

select parent0_.parent_id as parent_i1_2_, parent0_.parent_name as parent_n2_2_ from parent parent0_ inner join child children1_ on parent0_.parent_id=children1_.parent_parent_id where children1_.child_id=?
binding parameter [1] as [INTEGER] - [1]
select parent0_.parent_id as parent_i1_2_, parent0_.parent_name as parent_n2_2_ from parent parent0_ inner join child children1_ on parent0_.parent_id=children1_.parent_parent_id where children1_.child_id=?
binding parameter [1] as [INTEGER] - [1]

相关问题