Создание пользовательского запроса с помощью Spring DATA JPA?
Я работаю над проектом с 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
. Рассмотрите этот пример из официального документа:
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
Ответ 2
Специальной поддержки для этого нет. Но вы можете создать собственный метод с параметром String
и в вашей реализации вы получите EntityManager
и выполните его.
Возможно полезные ссылки:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
Как получить доступ к диспетчеру объектов с весенними загрузками и данными весны
Примечание. Я бы переосмыслил, что то, что вы пытаетесь сделать, является хорошей идеей, потому что оно исчерпывает детали реализации репозитория в остальной части приложения.
Ответ 3
Спасибо, @ilya. Существует ли альтернативный подход для достижения этой задачи с использованием Spring Data JPA? Без аннотации @Query?
Я просто хочу действовать по этому поводу. да, вы можете обойти это без использования аннотации @query. вам нужно определить производный запрос из вашего интерфейса, который реализует экземпляр репозитория JPA.
то из вашего экземпляра репозитория вы будете подвержены всем методам, которые позволяют выполнять операции CRUD в вашей базе данных, такие как
interface UserRepository extends CrudRepository<User, Long> {
long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
с этими методами данные весны поймут, что вы пытаетесь архивировать и внедрять их соответственно.
Также имейте в виду, что основные операции CRUD предоставляются из определения базового класса, и вам не нужно их определять. например, это класс 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/.
Ответ 4
С помощью 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;
}
}
И ваш запрос "выберите идентификатор, имя пользователя, где roll_no = 1001".
Здесь запрос вернет объект с идентификатором и именем столбца. Ваш класс ответа ниже:
Ваш класс ответа выглядит так:
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 получит массив объектов и установит данные вместе с объектом.
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
запрос возвращает массив и его [0] → идентификатор и 1 → имя.
Подробнее посетите эту тему.
Ответ 5
Основываясь на ответе @jelies, я использую следующий подход
Вы можете создать другой интерфейс для своих пользовательских методов (например, MyQueryCustom), а затем реализовать его следующим образом.
public class MyQueryRepositoryImpl implements MyQueryRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
public int executeQuery(String query) {
return entityManager.createNativeQuery(query).executeUpdate();
}
}
Это выполнит пользовательский запрос.