我一直在研究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方法实现,我只是对这种情况感到好奇。
1条答案
按热度按时间ql3eal8s1#
因为字符串可以包含SQL,而整数不能,所以从安全性的Angular 来看,没有必要进行绑定(SQL注入)。
来自literal_handling_mode的休眠文档:
此枚举定义JPA条件如何处理文字。(AUTO),条件查询将绑定参数用于任何非数字值的文字。但是,为了提高JDBC语句高速缓存的可能性,您可能还希望将绑定参数用于数字值。BIND模式将绑定变量用于任何文字值。INLINE模式将按原样内联文字值。要防止SQL注入,不要在字符串变量中使用INLINE。2总是在INLINE模式中使用常量。
在版本HHH-9576中,添加了一个新参数来修复此问题,自版本5.2.12起适用
或在 Spring Boot www.example.com中application.properties您可以使用
添加配置后,您的两个查询将看起来与bind参数相同。