← Назад к вопросам
В чем разница между CrudRepository и JpaRepository?
1.8 Middle🔥 141 комментариев
#ORM и Hibernate#Spring Boot и Spring Data
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между CrudRepository и JpaRepository
Это два фундаментальных интерфейса в Spring Data JPA, и выбор между ними важен для правильной архитектуры приложения.
Иерархия интерфейсов
Repository (маркер интерфейс)
↓
CrudRepository (базовые CRUD операции)
↓
PagingAndSortingRepository (добавляет pagination и sorting)
↓
JpaRepository (добавляет JPA-специфичные методы)
CrudRepository - базовые операции
// Интерфейс CrudRepository
public interface CrudRepository<T, ID> extends Repository<T, ID> {
// CREATE
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
// READ
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll(); // Возвращает Iterable
long count();
// UPDATE
// Использует save()
// DELETE
void deleteById(ID id);
void delete(T entity);
void deleteAll();
}
// Использование
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findByEmail(String email);
}
public class UserService {
private final UserRepository userRepository;
public void createUser(User user) {
userRepository.save(user); // CREATE
}
public void deleteUser(Long id) {
userRepository.deleteById(id); // DELETE
}
public Iterable<User> getAllUsers() {
return userRepository.findAll(); // Возвращает Iterable
}
}
JpaRepository - JPA-специфичные методы
// Интерфейс JpaRepository расширяет CrudRepository
public interface JpaRepository<T, ID> extends
CrudRepository<T, ID>,
PagingAndSortingRepository<T, ID> {
// Батч операции
void flush(); // Синхронизировать с БД
<S extends T> S saveAndFlush(S entity);
<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
// Удаление
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
void deleteAllInBatch(Iterable<T> entities);
// Поиск
List<T> findAll(); // Возвращает List, не Iterable
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
// Pagination
Page<T> findAll(Pageable pageable);
}
// Использование
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
List<User> findByAgeGreaterThan(int age);
}
public class UserService {
private final UserRepository userRepository;
public void createUsers(List<User> users) {
// JpaRepository метод - более эффективно
userRepository.saveAllAndFlush(users);
}
public List<User> getAllUsers(Pageable pageable) {
// JpaRepository - встроена pagination
Page<User> page = userRepository.findAll(pageable);
return page.getContent();
}
public void deleteUsersEfficiently(List<User> users) {
// JpaRepository - батч удаление
userRepository.deleteInBatch(users);
}
}
Основные отличия
| Функция | CrudRepository | JpaRepository |
|---|---|---|
| findAll() | Возвращает Iterable | Возвращает List |
| Pagination | Нет встроенного | Page<T> поддержка |
| Sorting | Отдельно через PagingAndSortingRepository | Встроено |
| Batch save | save() поодиночке | saveAndFlush(), saveAllAndFlush() |
| Batch delete | delete() поодиночке | deleteInBatch() |
| flush() | Нет | Есть - явная синхронизация |
| Версия Spring Data | Spring Data 1.0+ | Spring Data 2.0+ рекомендуется |
Примеры различных операций
// ============ CrudRepository ============
public interface CrudUserRepository extends CrudRepository<User, Long> {}
public class CrudUserService {
private final CrudUserRepository repo;
public void demo() {
// Получить всех - Iterable
Iterable<User> users = repo.findAll();
// Нужно преобразовать в List если нужна индексация
List<User> userList = StreamSupport
.stream(users.spliterator(), false)
.collect(Collectors.toList());
// Сохранить несколько
List<User> newUsers = Arrays.asList(
new User("John"),
new User("Jane")
);
repo.saveAll(newUsers);
// Но это не гарантирует flush в БД
}
}
// ============ JpaRepository ============
public interface JpaUserRepository extends JpaRepository<User, Long> {}
public class JpaUserService {
private final JpaUserRepository repo;
public void demo() {
// Получить всех - сразу List
List<User> users = repo.findAll();
// Можно сразу использовать
users.get(0);
// Сохранить несколько с гарантией flush
List<User> newUsers = Arrays.asList(
new User("John"),
new User("Jane")
);
repo.saveAllAndFlush(newUsers);
// Гарантированно записано в БД
// Pagination
Pageable pageRequest = PageRequest.of(0, 10, Sort.by("name"));
Page<User> page = repo.findAll(pageRequest);
System.out.println("Всего: " + page.getTotalElements());
System.out.println("Страниц: " + page.getTotalPages());
}
}
Производительность - Batch операции
// ❌ НЕЭФФЕКТИВНО - CrudRepository с циклом
public void saveManyUsersCrud(List<User> users) {
CrudUserRepository repo;
for (User user : users) {
repo.save(user); // Каждый save = отдельная SQL вставка
}
// Результат: 1000 users = 1000 SQL запросов!
}
// ✅ ЭФФЕКТИВНО - JpaRepository с batch
public void saveManyUsersJpa(List<User> users) {
JpaUserRepository repo;
repo.saveAllAndFlush(users); // Одна батч операция
// Результат: 1000 users = 1 batched INSERT запрос
}
// SQL разница:
// CrudRepository:
// INSERT INTO users (name) VALUES (Alice);
// INSERT INTO users (name) VALUES (Bob);
// INSERT INTO users (name) VALUES (Charlie);
// ... 1000 раз
// JpaRepository:
// INSERT INTO users (name) VALUES (Alice), (Bob), (Charlie), ...;
// Одна батч операция - в 10-100x быстрее!
Когда использовать что
// ИСПОЛЬЗУЙ CrudRepository когда:
// 1. Простое приложение с малым объемом данных
// 2. Нет требований к pagination
// 3. Нет требований к batch операциям
// 4. Хочешь минимальный интерфейс
public interface SimpleRepository extends CrudRepository<Entity, Long> {}
// ИСПОЛЬЗУЙ JpaRepository когда:
// 1. Нужна pagination/sorting
// 2. Нужны batch операции
// 3. Нужна явная контроль flush
// 4. Работаешь с большими объемами данных
// 5. Нужны JPA-специфичные методы
public interface ComplexRepository extends JpaRepository<Entity, Long> {}
Реальный пример: микросервис покупок
// JpaRepository - правильный выбор для сложных операций
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerId(Long customerId);
Page<Order> findByStatus(String status, Pageable pageable);
@Query("SELECT o FROM Order o WHERE o.created_at BETWEEN ?1 AND ?2")
List<Order> findByDateRange(LocalDateTime start, LocalDateTime end);
}
@Service
public class OrderService {
private final OrderRepository orderRepository;
@Transactional
public void processOrders(List<Order> orders) {
// Батч сохранение - очень эффективно
orderRepository.saveAllAndFlush(orders);
// Pagination для отчетов
Page<Order> page = orderRepository.findByStatus(
"PENDING",
PageRequest.of(0, 100)
);
// Гарантия что данные в БД
orderRepository.flush();
}
public Page<Order> getOrdersByCustomer(
Long customerId,
int page,
int size) {
// JpaRepository с Pageable
return orderRepository.findByCustomerId(
customerId,
PageRequest.of(page, size, Sort.by("created_at").descending())
);
}
}
Вывод
CrudRepository - базовые CRUD операции, простой интерфейс
- Для: простых приложений, минимальный функционал
- Методы: save(), findById(), findAll() как Iterable
JpaRepository - полнофункциональный интерфейс
- Для: сложных приложений, batch операции, pagination
- Методы: все CrudRepository + saveAndFlush(), deleteInBatch(), flush(), Page<T>
- Производительность: в 10-100x быстрее для batch операций
Рекомендация: используй JpaRepository по умолчанию для новых проектов. Он имеет все возможности CrudRepository плюс дополнительные оптимизации.