我以编程方式将我的SQL查询构建为String并希望将其作为SQL语句执行,但我使用的是Spring Data JPA,并且无法将JDBC与Prepared Statements一起使用。这可能在JPA中吗?
public class Polygon {
public static void main(String[] args) {
// Build Lat/Longs
Set<String[]> coordinates = new HashSet<>();
coordinates.add(new String[]{"42", "-72.95333862304689"});
coordinates.add(new String[]{"42.05337156043361", "-71.06643676757814"});
coordinates.add(new String[]{"41.32732632036624", "-71.06643676757814"});
coordinates.add(new String[]{"41.32732632036624", "-72.95333862304689"});
coordinates.add(new String[]{"42.05337156043361", "-72"});
// Trim & Build Query
String query = "SELECT * FROM SITE WHERE (LATITUDE LIKE ";
for(String[] c : coordinates){
c[0] += ".0";
c[1] += ".0";
String[] latArray = c[0].split("\\.");
String[] lngArray = c[1].split("\\.");
String lat = latArray[0] + "." + latArray[1].substring(0, 1) + "%";
String lng = lngArray[0] + "." + lngArray[1].substring(0, 1) + "%";
query += lat + " AND LONGITUDE LIKE " + lng + ") OR (LATITUDE LIKE ";
}
query = query.substring(0, query.length() - 20) + ");";
System.err.println(query);
/*
* This is the Query I am printing, which is correct
*
* SELECT * FROM SITE
* WHERE (LATITUDE LIKE 41.3% AND LONGITUDE LIKE -71.0%)
* OR (LATITUDE LIKE 42.0% AND LONGITUDE LIKE -72.0%)
* OR (LATITUDE LIKE 42.0% AND LONGITUDE LIKE -72.9%)
* OR (LATITUDE LIKE 42.0% AND LONGITUDE LIKE -71.0%)
* OR (LATITUDE LIKE 41.3% AND LONGITUDE LIKE -72.9%);
*
* How to execute this with Spring Data JPA?
*/
// @Query("SELECT * FROM SITE :where", nativeQuery = true)
// public List<SiteDTO> executeSiteQuery(@Param("where") String where);
// Doesn't Work, because (Syntax error on token ""SELECT * FROM SITE :where"", invalid MemberValuePairs)
}
}
答案 0 :(得分:1)
您的查询看起来太动态,无法被Spring Data JPA注释理解。实际上,当您尝试将SQL注入param字段时,您尝试的变通方法将无效,因此框架将阻止您执行此操作以防止SQL注入。
您可以向存储库添加自定义行为并实现预准备语句(请参阅如何从EntityManager here中获取会话)。基本上是:
public class MyRepositoryImpl<SiteDTO, ID extends Serializable>
extends SimpleJpaRepository<SiteDTO, ID> implements MyRepository<SiteDTO, ID> {
private EntityManager entityManager;
// There are two constructors to choose from, either can be used.
public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
// This is the recommended method for accessing inherited class dependencies.
this.entityManager = entityManager;
}
public List<SiteDTO> executeSiteQuery(List<String> longitudesToMatch, List<String> latitudesToMatch) {
// Here you can grab the session from the entity manager and create your own query
}
}
否则,如果您将其视为过度杀伤,则可以考虑在Spring Service中执行查询的or
部分。我的意思是,使用像public List<SiteDTO> executeSiteQuery(@Param("latitude") String latitude, @Param("longitude") String longitude);
这样的查询并多次调用它。性能较差,但有时简单付出。