Аннотации JPA: @OneToOne, @ManyToMany, @JoinColumn, @Lob, @Query, @Modifying, @EnableJpaRepositories
1. @OneToOne
Аннотация @OneToOne используется для определения связи "один к одному" между сущностями. Это может быть, например, связь между пользователем и его профилем.
2. @ManyToMany
@ManyToMany обозначает связь "многие ко многим". Это используется, когда несколько сущностей одной таблицы могут быть связаны с несколькими сущностями другой таблицы.
3. @JoinColumn
Аннотация @JoinColumn задаёт внешний ключ для связи. Она может использоваться с аннотациями @OneToOne и @ManyToOne.
4. @Lob
@Lob используется для маппинга больших объектов, таких как текстовые или бинарные данные.
5. @Query
Аннотация @Query позволяет задавать JPQL или SQL-запросы прямо в репозитории.
6. @Modifying
Используется вместе с @Query для выполнения операций обновления или удаления данных.
7. @EnableJpaRepositories
Эта аннотация активирует JPA-репозитории в Spring Boot.
#Java #Training #Spring #OneToOne #ManyToMany #JoinColumn #Lob #Query #Modifying #EnableJpaRepositories
1. @OneToOne
Аннотация @OneToOne используется для определения связи "один к одному" между сущностями. Это может быть, например, связь между пользователем и его профилем.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "profile_id", referencedColumnName = "id")
private Profile profile;
}
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
}
Здесь связь между User и Profile устанавливается через внешний ключ profile_id.
2. @ManyToMany
@ManyToMany обозначает связь "многие ко многим". Это используется, когда несколько сущностей одной таблицы могут быть связаны с несколькими сущностями другой таблицы.
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "courses")
private List<Student> students;
}
Связь осуществляется через промежуточную таблицу student_course.
3. @JoinColumn
Аннотация @JoinColumn задаёт внешний ключ для связи. Она может использоваться с аннотациями @OneToOne и @ManyToOne.
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "customer_id", nullable = false)
private Customer customer;
}
Здесь customer_id в таблице Order будет внешним ключом, ссылающимся на таблицу Customer.
4. @Lob
@Lob используется для маппинга больших объектов, таких как текстовые или бинарные данные.
@Entity
public class Document {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob
private String content; // Для больших текстов
@Lob
private byte[] fileData; // Для бинарных данных
}
5. @Query
Аннотация @Query позволяет задавать JPQL или SQL-запросы прямо в репозитории.
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);
}6. @Modifying
Используется вместе с @Query для выполнения операций обновления или удаления данных.
public interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Query("UPDATE User u SET u.name = :name WHERE u.id = :id")
void updateUserName(@Param("id") Long id, @Param("name") String name);
}7. @EnableJpaRepositories
Эта аннотация активирует JPA-репозитории в Spring Boot.
@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
public class AppConfig {
}
#Java #Training #Spring #OneToOne #ManyToMany #JoinColumn #Lob #Query #Modifying #EnableJpaRepositories
👍1
Теперь переходим к рассмотрению аннотаций Spring Data JPA.
Аннотация @Query
Аннотация @Query используется в Spring Data JPA для определения пользовательских JPQL (Java Persistence Query Language) или нативных SQL-запросов непосредственно в репозиторных интерфейсах. Она позволяет гибко настраивать запросы к базе данных, не полагаясь на автоматически генерируемые методы Spring Data. Аннотация находится в пакете org.springframework.data.jpa.repository.
Параметры аннотации
value (обязательный):
Тип: String.
Описание: Содержит JPQL или SQL-запрос. Если запрос JPQL, он должен соответствовать синтаксису JPA. Если это нативный SQL-запрос, необходимо указать параметр nativeQuery = true.
Пример:
nativeQuery (необязательный):
Тип: boolean.
Значение по умолчанию: false.
Описание: Указывает, является ли запрос нативным SQL-запросом. Если true, запрос выполняется как сырой SQL-запрос.
Пример:
countQuery (необязательный):
Тип: String.
Описание: Используется для указания запроса, который будет выполнен для подсчета общего количества записей при использовании пагинации. Актуально только для нативных запросов.
Пример:
name (необязательный):
Тип: String.
Описание: Указывает имя именованного запроса, который должен быть определен в метаданных JPA (например, в orm.xml или через аннотацию @NamedQuery).
Пример:
countName (необязательный):
Тип: String.
Описание: Указывает имя именованного запроса для подсчета количества записей. Используется вместе с name.
Пример:
Жизненный цикл аннотации
Инициализация:
Аннотация @Query обрабатывается во время инициализации Spring-контекста. Spring Data JPA анализирует репозиторные интерфейсы и создает прокси-объекты для методов, помеченных @Query.
Выполнение:
Когда метод репозитория вызывается, Spring Data JPA выполняет запрос, указанный в @Query. Если запрос JPQL, он преобразуется в SQL с помощью JPA-провайдера (например, Hibernate). Если запрос нативный, он выполняется напрямую.
Уничтожение:
Аннотация не имеет явного жизненного цикла уничтожения, так как она используется только для конфигурации запросов.
Механизмы Spring, связанные с @Query
Spring Data JPA:
Spring Data JPA предоставляет реализацию репозиториев, которая автоматически обрабатывает аннотацию @Query. Она интегрируется с JPA-провайдером (например, Hibernate) для выполнения запросов.
JPA-провайдер:
JPA-провайдер (например, Hibernate) отвечает за преобразование JPQL-запросов в SQL и их выполнение. Для нативных запросов JPA-провайдер передает SQL напрямую в базу данных.
Транзакционность:
По умолчанию методы репозитория выполняются в транзакции. Это можно настроить с помощью аннотации @Transactional.
Варианты настройки
Использование именованных запросов:
Вместо указания запроса непосредственно в @Query, можно использовать именованные запросы, определенные в orm.xml или через @NamedQuery.
Пагинация и сортировка:
Методы с @Query могут поддерживать пагинацию и сортировку, если возвращают Page, Slice или List с параметром Pageable.
Проекции:
Можно использовать проекции DTO для возврата только необходимых полей:
Динамические запросы:
Для сложных запросов можно использовать JpaSpecificationExecutor или Querydsl.
#Java #Training #Hard #Spring #SpringDataJPA #Query
Аннотация @Query
Аннотация @Query используется в Spring Data JPA для определения пользовательских JPQL (Java Persistence Query Language) или нативных SQL-запросов непосредственно в репозиторных интерфейсах. Она позволяет гибко настраивать запросы к базе данных, не полагаясь на автоматически генерируемые методы Spring Data. Аннотация находится в пакете org.springframework.data.jpa.repository.
Параметры аннотации
value (обязательный):
Тип: String.
Описание: Содержит JPQL или SQL-запрос. Если запрос JPQL, он должен соответствовать синтаксису JPA. Если это нативный SQL-запрос, необходимо указать параметр nativeQuery = true.
Пример:
@Query("SELECT u FROM User u WHERE u.email = ?1")
User findByEmail(String email);nativeQuery (необязательный):
Тип: boolean.
Значение по умолчанию: false.
Описание: Указывает, является ли запрос нативным SQL-запросом. Если true, запрос выполняется как сырой SQL-запрос.
Пример:
@Query(value = "SELECT * FROM users WHERE email = ?1", nativeQuery = true)
User findByEmail(String email);
countQuery (необязательный):
Тип: String.
Описание: Используется для указания запроса, который будет выполнен для подсчета общего количества записей при использовании пагинации. Актуально только для нативных запросов.
Пример:
@Query(value = "SELECT * FROM users WHERE active = true",
countQuery = "SELECT COUNT(*) FROM users WHERE active = true",
nativeQuery = true)
Page<User> findActiveUsers(Pageable pageable);
name (необязательный):
Тип: String.
Описание: Указывает имя именованного запроса, который должен быть определен в метаданных JPA (например, в orm.xml или через аннотацию @NamedQuery).
Пример:
@Query(name = "User.findByEmail")
User findByEmail(String email);
countName (необязательный):
Тип: String.
Описание: Указывает имя именованного запроса для подсчета количества записей. Используется вместе с name.
Пример:
@Query(name = "User.findActiveUsers", countName = "User.countActiveUsers")
Page<User> findActiveUsers(Pageable pageable);
Жизненный цикл аннотации
Инициализация:
Аннотация @Query обрабатывается во время инициализации Spring-контекста. Spring Data JPA анализирует репозиторные интерфейсы и создает прокси-объекты для методов, помеченных @Query.
Выполнение:
Когда метод репозитория вызывается, Spring Data JPA выполняет запрос, указанный в @Query. Если запрос JPQL, он преобразуется в SQL с помощью JPA-провайдера (например, Hibernate). Если запрос нативный, он выполняется напрямую.
Уничтожение:
Аннотация не имеет явного жизненного цикла уничтожения, так как она используется только для конфигурации запросов.
Механизмы Spring, связанные с @Query
Spring Data JPA:
Spring Data JPA предоставляет реализацию репозиториев, которая автоматически обрабатывает аннотацию @Query. Она интегрируется с JPA-провайдером (например, Hibernate) для выполнения запросов.
JPA-провайдер:
JPA-провайдер (например, Hibernate) отвечает за преобразование JPQL-запросов в SQL и их выполнение. Для нативных запросов JPA-провайдер передает SQL напрямую в базу данных.
Транзакционность:
По умолчанию методы репозитория выполняются в транзакции. Это можно настроить с помощью аннотации @Transactional.
Варианты настройки
Использование именованных запросов:
Вместо указания запроса непосредственно в @Query, можно использовать именованные запросы, определенные в orm.xml или через @NamedQuery.
Пагинация и сортировка:
Методы с @Query могут поддерживать пагинацию и сортировку, если возвращают Page, Slice или List с параметром Pageable.
Проекции:
Можно использовать проекции DTO для возврата только необходимых полей:
@Query("SELECT new com.example.UserDTO(u.id, u.name) FROM User u WHERE u.email = ?1")
UserDTO findUserDtoByEmail(String email);Динамические запросы:
Для сложных запросов можно использовать JpaSpecificationExecutor или Querydsl.
#Java #Training #Hard #Spring #SpringDataJPA #Query
👌2
Запросы и мутации в GraphQL
GraphQL опирается на две основные операции:
Query — безопасные операции чтения данных.
Mutation — операции изменения состояния (создание, обновление, удаление).
Обе операции используют один и тот же язык запросов, отличаются только семантикой:
Query не влияет на состояние системы, Mutation — влияет.
1. Как выглядит запрос (Query)
GraphQL-запрос — декларативное описание структуры данных, которую клиент хочет получить.
Простой пример:
Здесь:
query — тип операции (можно опустить: GraphQL сам определит, что это запрос).
user(id: 42) — вызов поля корневого типа Query.
{ name, avatar } — конкретные поля, которые клиент хочет получить.
GraphQL не вернёт дополнительные поля и не допустит отсутствующих — запрос полностью определяет форму ответа.
Ответ будет ровно такой:
2. Как работает передача аргументов
Аргументы передаются в круглых скобках и могут быть любого типа, определённого в схеме:
скаляры, enum, input-объекты.
Пример схемы:
Пример запроса:
Ответ будет:
2.1. Переменные запроса (не хардкодим аргументы)
GraphQL поддерживает variables, что особенно важно для фронтенда.
Запрос:
Передаваемые переменные:
Сервер объединяет запрос с переменными и выполняет его.
Преимущества переменных:
запрос можно кэшировать,
тело операции не меняется,
безопаснее, чем вставлять значения в строку.
3. Что делает Mutation
Mutation изменяет данные.
Пример схемы:
Пример запроса:
Mutation возвращает объект результата, содержащий новое состояние или подтверждение.
Ответ:
Важный принцип:
Mutation считается одиночной транзакцией.
Даже если внутри происходит много действий, GraphQL гарантирует их упорядоченное выполнение.
4. Возврат данных в нужной форме
GraphQL всегда возвращает данные:
в структуре, которую запросил клиент
в иерархии, описанной в запросе
строго тех типов, которые указаны в схеме
Пример: вложенная выборка.
Ответ:
#Java #middle #GraphQL #Query #Mutation
GraphQL опирается на две основные операции:
Query — безопасные операции чтения данных.
Mutation — операции изменения состояния (создание, обновление, удаление).
Обе операции используют один и тот же язык запросов, отличаются только семантикой:
Query не влияет на состояние системы, Mutation — влияет.
1. Как выглядит запрос (Query)
GraphQL-запрос — декларативное описание структуры данных, которую клиент хочет получить.
Простой пример:
query {
user(id: 42) {
name
avatar
}
}Здесь:
query — тип операции (можно опустить: GraphQL сам определит, что это запрос).
user(id: 42) — вызов поля корневого типа Query.
{ name, avatar } — конкретные поля, которые клиент хочет получить.
GraphQL не вернёт дополнительные поля и не допустит отсутствующих — запрос полностью определяет форму ответа.
Ответ будет ровно такой:
{
"data": {
"user": {
"name": "Den",
"avatar": "https://example.com/den.png"
}
}
}
Никаких “лишних” полей.2. Как работает передача аргументов
Аргументы передаются в круглых скобках и могут быть любого типа, определённого в схеме:
скаляры, enum, input-объекты.
Пример схемы:
type Query {
posts(limit: Int, authorId: ID): [Post!]!
}Пример запроса:
query {
posts(limit: 5, authorId: 42) {
id
title
}
}Ответ будет:
{
"data": {
"posts": [
{ "id": "101", "title": "GraphQL SDL" },
{ "id": "102", "title": "gRPC vs GraphQL" }
]
}
}2.1. Переменные запроса (не хардкодим аргументы)
GraphQL поддерживает variables, что особенно важно для фронтенда.
Запрос:
query GetUser($id: ID!) {
user(id: $id) {
name
avatar
}
}Передаваемые переменные:
{
"id": 42
}Сервер объединяет запрос с переменными и выполняет его.
Преимущества переменных:
запрос можно кэшировать,
тело операции не меняется,
безопаснее, чем вставлять значения в строку.
3. Что делает Mutation
Mutation изменяет данные.
Пример схемы:
type Mutation {
createPost(input: CreatePostInput!): Post!
}Пример запроса:
mutation {
createPost(input: { title: "GraphQL", content: "SDL explained" }) {
id
title
}
}Mutation возвращает объект результата, содержащий новое состояние или подтверждение.
Ответ:
{
"data": {
"createPost": {
"id": "501",
"title": "GraphQL"
}
}
}Важный принцип:
Mutation считается одиночной транзакцией.
Даже если внутри происходит много действий, GraphQL гарантирует их упорядоченное выполнение.
4. Возврат данных в нужной форме
GraphQL всегда возвращает данные:
в структуре, которую запросил клиент
в иерархии, описанной в запросе
строго тех типов, которые указаны в схеме
Пример: вложенная выборка.
query {
user(id: 1) {
name
posts(limit: 2) {
title
comments {
text
}
}
}
}Ответ:
{
"data": {
"user": {
"name": "Den",
"posts": [
{
"title": "GraphQL Basics",
"comments": [
{ "text": "Отличная статья" }
]
},
{
"title": "SDL Tutorial",
"comments": []
}
]
}
}
}
Сервер не может изменить структуру ответа — она определяется клиентом.#Java #middle #GraphQL #Query #Mutation
5. Ошибки и partial responses
GraphQL всегда возвращает JSON-объект с двумя ключами:
Что важно:
GraphQL может вернуть часть данных, даже если произошла ошибка.
пример: запрос
допустим, поле posts упало из-за ошибки в БД.
Ответ:
GraphQL:
не останавливает выполнение всего запроса,
возвращает то, что смог,
указывает путь к проблемному полю.
Это концепция partial response, которой нет ни в REST, ни в gRPC.
6. Как Mutation обрабатывает ошибки
Mutation также может вернуть частичный результат, но чаще ошибка означает, что произошло отклонение операции:
GraphQL намеренно не использует коды HTTP-статуса, кроме:
200 — запрос обработан
400 — синтаксическая ошибка запроса
500 — ошибка самого сервера GraphQL (не бизнес-ошибка)
#Java #middle #GraphQL #Query #Mutation
GraphQL всегда возвращает JSON-объект с двумя ключами:
data
errors
Что важно:
GraphQL может вернуть часть данных, даже если произошла ошибка.
пример: запрос
query {
user(id: 1) {
name
posts {
title
likes
}
}
}допустим, поле posts упало из-за ошибки в БД.
Ответ:
{
"data": {
"user": {
"name": "Den",
"posts": null
}
},
"errors": [
{
"message": "Database timeout",
"path": ["user", "posts"]
}
]
}GraphQL:
не останавливает выполнение всего запроса,
возвращает то, что смог,
указывает путь к проблемному полю.
Это концепция partial response, которой нет ни в REST, ни в gRPC.
6. Как Mutation обрабатывает ошибки
Mutation также может вернуть частичный результат, но чаще ошибка означает, что произошло отклонение операции:
{
"data": {
"createPost": null
},
"errors": [
{
"message": "User not authorized",
"path": ["createPost"]
}
]
}GraphQL намеренно не использует коды HTTP-статуса, кроме:
200 — запрос обработан
400 — синтаксическая ошибка запроса
500 — ошибка самого сервера GraphQL (не бизнес-ошибка)
#Java #middle #GraphQL #Query #Mutation