HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Теги: spring, java, spring data jpa, generic-репозитори, spring orm, crud-методы, аннотации jpa, маппинг, crudrepository, findbyname, jpql</p>
1 <p>Теги: spring, java, spring data jpa, generic-репозитори, spring orm, crud-методы, аннотации jpa, маппинг, crudrepository, findbyname, jpql</p>
2 <p>Одной из замечательных возможностей Spring является<strong>Spring Data JPA</strong>. Это один из "подпроектов" проекта Spring Data. По умолчанию, будем считать, что вы уже знаете, что такое JPA. Итак, нам необходимо написать обычное DAO для некоторой JPA сущности, предположим, Student.</p>
2 <p>Одной из замечательных возможностей Spring является<strong>Spring Data JPA</strong>. Это один из "подпроектов" проекта Spring Data. По умолчанию, будем считать, что вы уже знаете, что такое JPA. Итак, нам необходимо написать обычное DAO для некоторой JPA сущности, предположим, Student.</p>
3 <p><em>Да, здесь следует сделать небольшую поправку. Когда речь идёт о бизнес-сущностях и JPA, то правильнее применять термин репозиторий (<strong>Repository</strong>), что мы и будем дальше делать.</em></p>
3 <p><em>Да, здесь следует сделать небольшую поправку. Когда речь идёт о бизнес-сущностях и JPA, то правильнее применять термин репозиторий (<strong>Repository</strong>), что мы и будем дальше делать.</em></p>
4 <p>На практике интерфейс обычного репозитория выглядел бы как-то так:</p>
4 <p>На практике интерфейс обычного репозитория выглядел бы как-то так:</p>
5 public interface StudentRepository { Student save(Student entity); void delete(Student entity); Optional&lt;Student&gt; findById(long id); List&lt;Student&gt; findByName(String name); // и, возможно, ещё куча методов }<p>А сама реализация будет выглядеть примерно таким образом:</p>
5 public interface StudentRepository { Student save(Student entity); void delete(Student entity); Optional&lt;Student&gt; findById(long id); List&lt;Student&gt; findByName(String name); // и, возможно, ещё куча методов }<p>А сама реализация будет выглядеть примерно таким образом:</p>
6 @Repository public class StudentRepositoryImpl implements StudentRepository { @PersistenceContext private EntityManager em; @Override public Student save(Student student) { em.persist(student); } @Override public void delete(Student entity) { em.remove(employee); } @Override public Optional&lt;Student&gt; findById(long id) { return em.find(Person.class, id); } @Override public List&lt;Student&gt; findByName(String name) { // да, это неправильно, это всего лишь пример return em.createQuery("select s from Student where sname="+name) .getResultList(); } // и, возможно, ещё куча методов }<p>В действительности код в реальном проекте будет выглядеть немного сложнее. Появятся абстрактные<strong>Generic-репозитории</strong>, и разных специфичных методов поиска<strong>entity</strong>со сложными<strong>JPQL</strong>будет достаточно. Да и конфигурация<strong>Spring ORM</strong>+ сама<strong>entity</strong>Student здесь просто опущены.</p>
6 @Repository public class StudentRepositoryImpl implements StudentRepository { @PersistenceContext private EntityManager em; @Override public Student save(Student student) { em.persist(student); } @Override public void delete(Student entity) { em.remove(employee); } @Override public Optional&lt;Student&gt; findById(long id) { return em.find(Person.class, id); } @Override public List&lt;Student&gt; findByName(String name) { // да, это неправильно, это всего лишь пример return em.createQuery("select s from Student where sname="+name) .getResultList(); } // и, возможно, ещё куча методов }<p>В действительности код в реальном проекте будет выглядеть немного сложнее. Появятся абстрактные<strong>Generic-репозитории</strong>, и разных специфичных методов поиска<strong>entity</strong>со сложными<strong>JPQL</strong>будет достаточно. Да и конфигурация<strong>Spring ORM</strong>+ сама<strong>entity</strong>Student здесь просто опущены.</p>
7 <h2>А теперь воспользуемся магией Spring Data JPA</h2>
7 <h2>А теперь воспользуемся магией Spring Data JPA</h2>
8 <p>Spring Data вводит абстракцию репозитория, поэтому<strong>CRUD-методы</strong>мы позаимствуем. Итак, наш код будет выглядеть таким образом:</p>
8 <p>Spring Data вводит абстракцию репозитория, поэтому<strong>CRUD-методы</strong>мы позаимствуем. Итак, наш код будет выглядеть таким образом:</p>
9 import org.springframework.data.repository.CrudRepository; public interface StudentRepository extends CrudRepository&lt;Student, Long&gt; { List&lt;Student&gt; findByName(String name); // и, возможно, ещё куча методов }<p>Ну и чтобы этот интерфейс был найден, не забудем поставить:</p>
9 import org.springframework.data.repository.CrudRepository; public interface StudentRepository extends CrudRepository&lt;Student, Long&gt; { List&lt;Student&gt; findByName(String name); // и, возможно, ещё куча методов }<p>Ну и чтобы этот интерфейс был найден, не забудем поставить:</p>
10 @EnableJpaRepositories public class AppConfiguration { /* */ }<h2>И… ВСЁ!</h2>
10 @EnableJpaRepositories public class AppConfiguration { /* */ }<h2>И… ВСЁ!</h2>
11 <p>А где же код работы с<strong>JPA</strong>? Как ни странно, но кода нет! И не будет. Давайте разберёмся, как эта магия работает.</p>
11 <p>А где же код работы с<strong>JPA</strong>? Как ни странно, но кода нет! И не будет. Давайте разберёмся, как эта магия работает.</p>
12 <p>Весь SQL уже написан в<strong>entity</strong>Student с помощью аннотаций JPA. Действительно, благодаря уже настроенному маппингу этой<strong>entity</strong>на БД можно написать все методы CRUD, которые определены в интерфейсе<strong>CrudRepository</strong>.</p>
12 <p>Весь SQL уже написан в<strong>entity</strong>Student с помощью аннотаций JPA. Действительно, благодаря уже настроенному маппингу этой<strong>entity</strong>на БД можно написать все методы CRUD, которые определены в интерфейсе<strong>CrudRepository</strong>.</p>
13 <p>Но как же метод<strong>findByName</strong>интерфейса<strong>StudentRepository</strong>? Несложно догадаться, что<strong>Spring Data JPA</strong>по имени метода может идентифицировать поле<strong>entity</strong>, по которому необходимо производить поиск - сгенерировать<strong>JPQL</strong>, именно тот, который был написан в первой реализации.</p>
13 <p>Но как же метод<strong>findByName</strong>интерфейса<strong>StudentRepository</strong>? Несложно догадаться, что<strong>Spring Data JPA</strong>по имени метода может идентифицировать поле<strong>entity</strong>, по которому необходимо производить поиск - сгенерировать<strong>JPQL</strong>, именно тот, который был написан в первой реализации.</p>
14 <p>В действительности, методы и запросы могут быть сложнее. Приведём пример интерфейса:</p>
14 <p>В действительности, методы и запросы могут быть сложнее. Приведём пример интерфейса:</p>
15 public interface StudentRepository extends CrudRepository&lt;Student, Long&gt; { List&lt;Student&gt; findByName(String name); List&lt;Student&gt; findByNameIgnoreCase(String name); List&lt;Student&gt; findByNameOrEmail(String name, String email); long deleteByLastname(String lastname); // и, возможно, ещё куча методов }<p>В<a>документации</a>есть целая "таблица глаголов" для формирования более сложных действий и запросов.</p>
15 public interface StudentRepository extends CrudRepository&lt;Student, Long&gt; { List&lt;Student&gt; findByName(String name); List&lt;Student&gt; findByNameIgnoreCase(String name); List&lt;Student&gt; findByNameOrEmail(String name, String email); long deleteByLastname(String lastname); // и, возможно, ещё куча методов }<p>В<a>документации</a>есть целая "таблица глаголов" для формирования более сложных действий и запросов.</p>
16 <p><strong>Счастливого использования!</strong></p>
16 <p><strong>Счастливого использования!</strong></p>
17 <p><em>Есть вопрос? Напишите в комментариях!</em></p>
17 <p><em>Есть вопрос? Напишите в комментариях!</em></p>
18  
18