【问题标题】:Creating a custom query with Spring DATA JPA?使用 Spring DATA JPA 创建自定义查询?
【发布时间】:2017-08-15 11:19:00
【问题描述】:

我正在使用 Spring Data JPA 开发一个项目。我在数据库中有一个表作为 my_query。

我想创建一个以字符串为参数的方法,然后在数据库中将其作为查询执行。

方法:

executeMyQuery(queryString)

例如,当我通过时

queryString= "SELECT * FROM my_query"

那么它应该在数据库级别运行该查询。

仓库类如下。

public interface MyQueryRepository extends JpaRepository<MyQuery, Long>{
    public MyQuery findById(long id);

    @Modifying(clearAutomatically = true)
    @Transactional
    @Query(value = "?1", nativeQuery = true)
    public void executeMyQuery(String query);

}

但是,它并没有像我预期的那样工作。它给出了以下错误。

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''select * from my_query;'' at line 1

有没有其他方法可以实现这个目标。提前致谢

【问题讨论】:

    标签: mysql sql spring spring-data spring-data-jpa


    【解决方案1】:

    您可以参数化的唯一部分是WHERE 子句中使用的值。考虑来自official doc 的这个示例:

    public interface UserRepository extends JpaRepository<User, Long> {
      @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
      User findByEmailAddress(String emailAddress);
    }
    

    【讨论】:

    • 谢谢@ilya。是否有使用 Spring Data JPA 完成此任务的替代方法?没有@Query注解?
    • @benji 如果你真的需要这样的行为,那么你需要获取 EntityManager 并直接使用它运行查询。作为参考,请参阅此答案:stackoverflow.com/a/15341601/187241。但请三思而后行。如果您在很多地方都需要它,那么 Spring Data 可能不适合您。它的主要思想是对你隐藏查询,让你稍微调整它们,例如,使用@Query 注释。
    【解决方案2】:

    对此没有特别的支持。但是您可以做的是创建一个带有String 参数的自定义方法,并在您的实现中注入EntityManager 并执行它。

    可能有用的链接:

    https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

    How to access entity manager with spring boot and spring data

    注意:我会重新考虑您尝试做的事情是否是一个好主意,因为它会将存储库的实现细节渗入应用程序的其余部分。

    【讨论】:

      【解决方案3】:

      使用 EntityManager 你可以做到这一点。

      假设您的实体类如下所示:

      import javax.persistence.*;
      import java.math.BigDecimal;
      
      @Entity
      @Table(name = "USER_INFO_TEST")
      public class UserInfoTest {
          private int id;
          private String name;
          private String rollNo;
      
          public UserInfoTest() {
          }
      
          public UserInfoTest(int id, String name) {
          this.id = id;
          this.name = name;
          }
      
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name = "ID", nullable = false, precision = 0)
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
      
          @Basic
          @Column(name = "name", nullable = true)
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          @Basic
          @Column(name = "roll_no", nullable = true)
          public String getRollNo() {
              return rollNo;
          }
      
          public void setRollNo(String rollNo) {
              this.rollNo = rollNo;
          }
      }
      

      您的查询是“select id, name from users where roll_no = 1001”。

      这里查询将返回一个带有 id 和 name 列的对象。您的 Response 类如下所示:

      你的响应类是这样的:

      public class UserObject{
          int id;
          String name;
          String rollNo;
      
          public UserObject(Object[] columns) {
              this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
              this.name = (String) columns[1];
          }
      
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getRollNo() {
              return rollNo;
          }
      
          public void setRollNo(String rollNo) {
              this.rollNo = rollNo;
          }
      }
      

      这里的UserObject构造函数会得到一个Object Array并用该对象设置数据。

      public UserObject(Object[] columns) {
                  this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
                  this.name = (String) columns[1];
              }
      

      您的查询执行功能如下所示:

      public UserObject getUserByRoll(EntityManager entityManager,String rollNo) {
      
              String queryStr = "select id,name from users where roll_no = ?1";
              try {
                  Query query = entityManager.createNativeQuery(queryStr);
                  query.setParameter(1, rollNo);
      
                  return new UserObject((Object[]) query.getSingleResult());
              } catch (Exception e) {
                  e.printStackTrace();
                  throw e;
              }
          }
      

      这里你必须导入波纹管包:

      import javax.persistence.Query;
      import javax.persistence.EntityManager;
      

      现在你的主类,你必须调用这个函数。首先获取 EntityManager 并调用此 getUserByRoll(EntityManager entityManager,String rollNo) 函数。调用过程如下:

      这里是导入

      import javax.persistence.EntityManager;
      import javax.persistence.PersistenceContext;
      

      通过这种方式获取EntityManager

      @PersistenceContext
      private EntityManager entityManager;
      
      UserObject userObject = getUserByRoll(entityManager,"1001");
      

      现在你在这个 userObject 中有数据了。

      注意

      query.getSingleResult() 返回一个对象数组。您必须使用查询列位置来维护列位置和数据类型。

      从roll_no = 1001的用户中选择id、name

      查询返回一个数组,它是 [0] --> id 和 1 -> 名称。

      更多信息请访问this thread

      【讨论】:

        【解决方案4】:

        谢谢@ilya。是否有使用 Spring Data JPA 完成此任务的替代方法?没有@Query 注解?

        我只是想在这部分采取行动。是的,有一种方法可以在不使用 @query 注释的情况下进行。您需要从实现 JPA 存储库实例的接口定义派生查询。

        然后从您的存储库实例中,您将接触到所有允许对数据库进行 CRUD 操作的方法,例如

         interface UserRepository extends CrudRepository<User, Long> {
        
         long deleteByLastname(String lastname);
        
         List<User> removeByLastname(String lastname);
        }
        

        通过这些方法,spring data 将了解您要归档的内容并相应地实施它们。

        还要记住,基本的 CRUD 操作是从基类定义中提供的,您不需要重新定义它们。例如,这是 spring 定义的 JPARepository 类,因此扩展它为您提供了所有方法。

         public interface CrudRepository<T, ID extends Serializable>
         extends Repository<T, ID> {
        
         <S extends T> S save(S entity);      
        
         Optional<T> findById(ID primaryKey); 
        
         Iterable<T> findAll();               
        
         long count();                        
        
         void delete(T entity);               
        
         boolean existsById(ID primaryKey);   
        
        
        }
        

        有关更多最新信息,请查看https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ 的文档

        【讨论】:

          【解决方案5】:

          基于@jeliesanswer,我正在使用以下方法

          您可以为您的自定义方法创建另一个接口(例如 MyQueryCustom),然后按如下方式实现它。

          public class MyQueryRepositoryImpl implements MyQueryRepositoryCustom {
              @PersistenceContext
              private EntityManager entityManager;
          
              public int executeQuery(String query) {
                  return entityManager.createNativeQuery(query).executeUpdate();
              }
          }
          

          这将执行一个自定义查询。

          【讨论】:

            【解决方案6】:

            如果你想添加自定义查询,你应该添加@Param

            @Query("from employee where name=:name")    
            employee findByName(@Param("name)String name);
            }
            

            此查询将选择匹配 name 的唯一记录。这将起作用

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-03-25
              • 2020-01-23
              • 1970-01-01
              • 2015-12-07
              • 2012-09-13
              • 2019-03-10
              • 1970-01-01
              • 2019-09-25
              相关资源
              最近更新 更多