Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Что добавляет аннотация @Repository
Краткий ответ
@Repository — это специализированная аннотация Spring, которая:
- Регистрирует класс как компонент в контейнере Spring (как @Component)
- Добавляет трансляцию исключений БД в специфичные для Spring исключения
- Указывает на назначение класса — работа с данными
- Позволяет инжектировать repository в другие компоненты
Иерархия аннотаций Spring Stereotype
@Component ← базовая аннотация
↓
┌─────────────────────────────────────────┐
│ @Repository @Service @Controller │
│ (DATA) (LOGIC) (WEB) │
└─────────────────────────────────────────┘
Все три — это специализированные версии @Component, но каждая имеет дополнительные возможности.
1. Регистрация в контейнере Spring
Без @Repository
public class UserRepository {
public User findById(Long id) {
// ...
}
}
// ❌ Spring не знает об этом классе
// Невозможно внедрить через @Autowired
С @Repository
@Repository
public class UserRepository {
public User findById(Long id) {
// ...
}
}
// ✅ Spring регистрирует этот класс
// Можно внедрить через @Autowired
Использование
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // Spring внедрит @Repository
public User getUserById(Long id) {
return userRepository.findById(id);
}
}
2. Трансляция исключений (Exception Translation)
Это ГЛАВНОЕ преимущество @Repository.
Проблема без @Repository
// Без @Repository
public class PlainUserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) {
try {
// JdbcTemplate выбросит DataAccessException
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new Object[]{id},
new UserRowMapper()
);
} catch (DataAccessException e) {
// ❌ Выбросится специфичное для Spring исключение
// Но это всё ещё зависимость от Spring
throw e;
}
}
}
Решение с @Repository
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) {
// Spring автоматически переводит исключения БД
// в стандартные DataAccessException иерархии
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new Object[]{id},
new UserRowMapper()
);
}
}
// Spring автоматически перехватывает исключения и переводит их
Как работает трансляция
Исключение БД → Spring DataAccessException
────────────────────────────────────────────────────
SQLException → DataAccessResourceFailureException
SQLIntegrityConstraintViolationException → DataIntegrityViolationException
BadSqlGrammarException → InvalidDataAccessResourceUsageException
CancellationException → QueryTimeoutException
Иерархия исключений DataAccessException
DataAccessException (checked → unchecked!)
├── DataIntegrityViolationException (нарушение констреинтов)
├── DataAccessResourceFailureException (нет доступа к БД)
├── InvalidDataAccessResourceUsageException (неверный SQL)
├── QueryTimeoutException (timeout запроса)
├── PermissionDeniedDataAccessException (нет прав)
└── ... другие
3. Пример трансляции исключений
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public void createUser(User user) {
try {
jdbcTemplate.update(
"INSERT INTO users (email, name) VALUES (?, ?)",
user.getEmail(), user.getName()
);
} catch (DataIntegrityViolationException e) {
// ✅ Spring перевёл SQLException в специфичное исключение
// Это означает нарушение уникального ключа (email уже существует)
throw new UserAlreadyExistsException("Email already registered", e);
}
}
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void registerUser(UserRegistrationRequest request) {
try {
userRepository.createUser(new User(request.getEmail(), request.getName()));
} catch (DataIntegrityViolationException e) {
// Можем ловить специфичное исключение
logger.warn("Попытка зарегистрировать существующий email");
}
}
}
4. @Repository с Spring Data JPA
When using Spring Data JPA, @Repository becomes even more powerful:
// ✅ Spring Data Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Spring автоматически:
// 1. Создаёт реализацию
// 2. Переводит исключения
// 3. Управляет транзакциями
User findByEmail(String email);
@Query("SELECT u FROM User u WHERE u.active = true")
List<User> findActiveUsers();
}
// Использование
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // Spring внедрит repository
public User getUserByEmail(String email) {
return userRepository.findByEmail(email); // Работает как надо
}
}
5. Сравнение стереотипов
@Component
@Component
public class GenericHelper {
public static String format(String text) {
return text.toUpperCase();
}
}
// Использование
@Service
public class MyService {
@Autowired
private GenericHelper helper; // Инжектируется
}
@Service
@Service
public class UserService {
// Бизнес-логика
public User createUser(UserRequest request) {
User user = new User(request.getName());
return userRepository.save(user);
}
}
// Использование
@RestController
public class UserController {
@Autowired
private UserService userService; // Инжектируется
}
@Repository
@Repository
public class UserRepository {
// Доступ к данным + трансляция исключений
public User findById(Long id) {
return jdbcTemplate.queryForObject(...);
}
}
// Использование
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // Инжектируется + трансляция
}
@Controller / @RestController
@RestController
@RequestMapping("/api/users")
public class UserController {
// Web layer
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}
6. Когда использовать @Repository
✅ Используй когда:
// Класс работает с БД напрямую
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) { }
public void save(User user) { }
}
// Наследуешь от Spring Data интерфейса
@Repository
public interface UserRepository extends JpaRepository<User, Long> { }
// Используешь Hibernate Session
@Repository
public class ProductRepository {
@Autowired
private SessionFactory sessionFactory;
}
❌ Не используй когда:
// Это сервис, не repository
@Service // ← Правильно
public class EmailService {
public void sendEmail(String to, String message) { }
}
// Это контроллер, не repository
@RestController // ← Правильно
public class OrderController { }
// Это утилита, не repository
@Component // ← Правильно
public class DateUtils { }
7. Практический пример: Error Handling
@Repository
public class OrderRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public Order findById(Long id) {
try {
return jdbcTemplate.queryForObject(
"SELECT * FROM orders WHERE id = ?",
new Object[]{id},
new OrderRowMapper()
);
} catch (EmptyResultDataAccessException e) {
// Нет результата
return null;
}
// Spring автоматически переведёт другие исключения
}
public void update(Order order) {
try {
jdbcTemplate.update(
"UPDATE orders SET status = ? WHERE id = ?",
order.getStatus(), order.getId()
);
} catch (DataIntegrityViolationException e) {
// Нарушение констреинта
throw new OrderUpdateException("Cannot update order", e);
}
}
}
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public Order getOrder(Long id) {
Order order = orderRepository.findById(id);
if (order == null) {
throw new OrderNotFoundException("Order not found");
}
return order;
}
}
8. Различие между проверяемыми и непроверяемыми исключениями
// SQLException — проверяемое исключение (checked)
public void oldWayFindUser() throws SQLException { // Нужен throws
Connection conn = DriverManager.getConnection(url);
// ...
}
// DataAccessException — непроверяемое исключение (unchecked)
@Repository
public class UserRepository {
public User findById(Long id) { // Не нужен throws!
// Spring переводит SQLException (checked)
// в DataAccessException (unchecked)
return jdbcTemplate.queryForObject(...);
}
}
// ✅ Это удобнее — не нужно объявлять throws везде
Итоги
- @Repository — специализированная версия @Component для data access
- Регистрация в контейнере — Spring создаёт bean и позволяет инжектировать
- Трансляция исключений — главное преимущество (SQLException → DataAccessException)
- DataAccessException — unchecked исключение, удобнее для обработки ошибок
- Spring Data — @Repository работает с JpaRepository и создаёт реализацию
- Правильное использование — @Repository для доступа к данным, @Service для бизнес-логики, @Controller для web
- Практически — трансляция исключений часто спасает жизнь при обработке ошибок БД