← Назад к вопросам

В чем разница между 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);
    }
}

Основные отличия

ФункцияCrudRepositoryJpaRepository
findAll()Возвращает IterableВозвращает List
PaginationНет встроенногоPage<T> поддержка
SortingОтдельно через PagingAndSortingRepositoryВстроено
Batch savesave() поодиночкеsaveAndFlush(), saveAllAndFlush()
Batch deletedelete() поодиночкеdeleteInBatch()
flush()НетЕсть - явная синхронизация
Версия Spring DataSpring 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 плюс дополнительные оптимизации.