如何使用Spring Data JPA执行存储为String的查询?

时间:2017-04-20 16:02:45

标签: java sql spring spring-data-jpa

我以编程方式将我的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)
}
}

1 个答案:

答案 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);这样的查询并多次调用它。性能较差,但有时简单付出。