使用 Spring DATA JPA 创建自定义查询?

Posted

技术标签:

【中文标题】使用 Spring DATA JPA 创建自定义查询?【英文标题】:Creating a custom query with 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

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

【问题讨论】:

【参考方案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 并直接使用它运行查询。作为参考,请参阅此答案:***.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 的唯一记录。这将起作用

【讨论】:

以上是关于使用 Spring DATA JPA 创建自定义查询?的主要内容,如果未能解决你的问题,请参考以下文章

在为嵌套对象创建自定义 Spring Data JPA 查询时获取 IllegalArgumentException

在 JPA 存储库(Spring Data Jpa)中执行自定义查询

Spring Data JPA - JpaRepository 中的自定义排序

Spring Data JPA自定义查询限制功能不起作用[重复]

Spring Data JPA - 带有“@Param Date”的自定义@Query 不起作用

Spring Data Jpa 使用@Query标注自定义查询语句