使用 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自定义查询限制功能不起作用[重复]