Поддержка объекта доступа к данным (Data Access Object/DAO) в Spring направлена на упрощение работы с технологиями доступа к данным (такими как JDBC, Hibernate или JPA). Это позволяет легко переключаться между вышеупомянутыми технологиями поддержки постоянного хранения, а также не беспокоиться о перехвате исключений, характерных для каждой технологии.

Согласованная иерархия исключений

Spring обеспечивает удобный переход от специфичных для технологии исключений, таких как SQLException, к собственной иерархии классов исключений, в которой корневым исключением является DataAccessException. Эти исключения обертывают исходное исключение, поэтому отсутствует риск того, что вы можете утратить какую-либо информацию о том, что могло пойти не так.

В дополнение к исключениям JDBC, Spring также может обернуть специфические исключения JPA и Hibernate, преобразуя их в набор организованных исключений времени выполнения. Это позволяет обрабатывать большинство невосстанавливаемых исключений постоянного хранения только на соответствующих уровнях, не прибегая к раздражающим стереотипным блокам "catch-and-throw" и объявлениям исключений в ваших DAO. (Однако вы все равно можете отлавливать и обрабатывать исключения везде, где это необходимо). Как упоминалось выше, исключения JDBC (включая диалекты, специфичные для баз данных) также преобразуются в ту же самую иерархию, что означает, что вы можете выполнять некоторые операции с JDBC в рамках модели согласованного программирования.

Предшествующее пояснение справедливо и в отношении различных классов шаблонов в средствах поддержки Spring для различных ORM-фреймворков. Если вы используете классы на основе перехватчиков, приложение должно само заниматься обработкой HibernateExceptions и PersistenceExceptions, предпочтительно делегируя её методам convertHibernateAccessException(..) или convertJpaAccessException(..) утилиты SessionFactoryUtils, соответственно. Эти методы преобразуют исключения в исключения, совместимые с исключениями в иерархии исключений org.springframework.dao. Поскольку PersistenceExceptions непроверяемые, они тоже могут быть сгенерированы (при этом, правда, жертвуя типизированной абстракцией DAO в плане исключений).

На следующем изображении показана иерархия исключений, которую предлагает Spring. (Обратите внимание, что иерархия классов, представленная на рисунке, показывает только часть всей иерархии DataAccessException).

Аннотации, используемые для настройки классов DAO или репозитория

Лучший способ обеспечить, чтоб ваши объекты доступа к данным (DAO) или репозитории гарантированно преобразовывали (транслировали) исключения, – это использовать аннотацию @Repository. Эта аннотация также позволяет средствам поддержки сканирования компонентов находить и настраивать ваши DAO и репозитории без необходимости предоставлять для них XML-записи конфигурации. В следующем примере показано, как использовать аннотацию @Repository:

Java
@Repository 
public class SomeMovieFinder implements MovieFinder {
    // ...
}
  1. Аннотация @Repository.
Kotlin
@Repository 
class SomeMovieFinder : MovieFinder {
    // ...
}
  1. Аннотация @Repository.

Любой реализации DAO или репозиторию требуется доступ к ресурсу постоянного хранения, в зависимости от используемой технологии постоянного хранения. Например, репозиторию на основе JDBC необходим доступ к DataSource из JDBC, а хранилищу на основе JPA – доступ к EntityManager. Самый простой способ добиться этого – внедрить зависимость ресурса с помощью одной из аннотаций @Autowired, @Inject, @Resource или @PersistenceContext. Следующий пример рабочий в отношении репозитория JPA:

Java
@Repository
public class JpaMovieFinder implements MovieFinder {
    @PersistenceContext
    private EntityManager entityManager;
    // ...
}
Kotlin
@Repository
class JpaMovieFinder : MovieFinder {
    @PersistenceContext
    private lateinit var entityManager: EntityManager
    // ...
}

Если используются классические API-интерфейсы Hibernate, можно внедрить SessionFactory, как показано в следующем примере:

Java
@Repository
public class HibernateMovieFinder implements MovieFinder {
    private SessionFactory sessionFactory;
    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    // ...
}
Kotlin
@Repository
class HibernateMovieFinder(private val sessionFactory: SessionFactory) : MovieFinder {
    // ...
}

Последний пример, который мы продемонстрируем, относится к типичному средству поддержки JDBC. DataSource можно внедрить в метод инициализации или конструктор, где вы создадите JdbcTemplate и другие классы поддержки доступа к данным (такие как SimpleJdbcCall и т.д.), используя этот DataSource. В следующем примере выполняется автоматическое обнаружение и связывание DataSource:

Java
@Repository
public class JdbcMovieFinder implements MovieFinder {
    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void init(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    // ...
}
Kotlin
@Repository
class JdbcMovieFinder(dataSource: DataSource) : MovieFinder {
    private val jdbcTemplate = JdbcTemplate(dataSource)
    // ...
}
Подробную информацию о том, как настроить контекст приложения, чтобы воспользоваться преимуществами этих аннотаций, см. в специальном описании каждой технологии постоянного хранения.