이번글은 공식 문서에서 소개하는 General ORM Integration Considerations에 대해 정리했습니다.
This section highlights considerations that apply to all ORM technologies. The Hibernate section provides more details and also show these features and configurations in a concrete context.
이 부분은 모든 ORM 기술에 공통적으로 적용되는 사항들을 강조하고 있습니다. Hibernate 섹션에서는 이러한 기능과 설정들이 실제로 어떻게 사용되는지를 더 구체적으로 설명해줍니다.
The major goal of Spring’s ORM integration is clear application layering (with any data access and transaction technology) and for loose coupling of application objects — no more business service dependencies on the data access or transaction strategy, no more hard-coded resource lookups, no more hard-to-replace singletons, no more custom service registries. The goal is to have one simple and consistent approach to wiring up application objects, keeping them as reusable and free from container dependencies as possible. All the individual data access features are usable on their own but integrate nicely with Spring’s application context concept, providing XML-based configuration and cross-referencing of plain JavaBean instances that need not be Spring-aware. In a typical Spring application, many important objects are JavaBeans: data access templates, data access objects, transaction managers, business services that use the data access objects and transaction managers, web view resolvers, web controllers that use the business services, and so on.
Spring의 ORM 통합이 추구하는 핵심 목표는 명확한 애플리케이션 계층 구조를 유지하면서 데이터 접근 방식이나 트랜잭션 기술에 종속되지 않는 느슨한 결합(loose coupling)을 구현하는 것입니다.
즉, 비즈니스 로직이 더 이상 데이터 접근이나 트랜잭션 전략에 의존하지 않도록 하고, 하드코딩된 리소스 조회, 교체하기 어려운 싱글톤 객체, 직접 만든 서비스 레지스트리 등을 없애는 것이 목표입니다.
Spring은 애플리케이션 객체들을 간단하고 일관된 방식으로 연결하면서, 이 객체들이 재사용 가능하고 컨테이너에 의존하지 않도록 유지하는 것을 지향합니다.
개별 데이터 접근 기능들은 각각 독립적으로 사용할 수 있지만, Spring의 ApplicationContext 개념과 자연스럽게 통합되며,
XML 설정이나 평범한 JavaBean 객체 간의 참조를 통해 구성할 수 있습니다. 이때 해당 객체들이 Spring에 특화된 코드를 포함할 필요는 없습니다.
일반적인 Spring 애플리케이션에서는 다음과 같은 많은 중요한 객체들이 JavaBean 형태로 존재합니다.
- 데이터 접근 템플릿
- DAO(Data Access Object)
- 트랜잭션 관리자
- DAO와 트랜잭션 관리자를 사용하는 비즈니스 서비스
- 웹 뷰 리졸버
- 비즈니스 서비스를 사용하는 웹 컨트롤러 등.
Resource and Transaction Management
Typical business applications are cluttered with repetitive resource management code. Many projects try to invent their own solutions, sometimes sacrificing proper handling of failures for programming convenience. Spring advocates simple solutions for proper resource handling, namely IoC through templating in the case of JDBC and applying AOP interceptors for the ORM technologies.
일반적인 비즈니스 애플리케이션에는 반복적인 리소스 관리 코드가 난무합니다. 많은 프로젝트들이 이를 해결하기 위해 자체적인 방법을 만들어내지만, 그 과정에서 종종 예외 처리나 실패 상황에 대한 적절한 대응을 포기하고 편의성만을 추구하기도 합니다.
Spring은 이러한 문제를 해결하기 위해, 간단하면서도 올바른 리소스 처리 방식을 권장합니다.
- JDBC의 경우에는 템플릿 기반 IoC(제어의 역전) 방식으로,
- ORM 기술의 경우에는 AOP 인터셉터를 적용하는 방식으로 처리합니다.
즉, 개발자가 리소스 관리나 예외 처리 코드를 직접 반복해서 작성하지 않아도 되도록 하고, 안정적이고 일관된 방식으로 리소스를 관리할 수 있게 해준다는 것이 핵심입니다.
The infrastructure provides proper resource handling and appropriate conversion of specific API exceptions to an unchecked infrastructure exception hierarchy. Spring introduces a DAO exception hierarchy, applicable to any data access strategy. For direct JDBC, the JdbcTemplate class mentioned in a previous section provides connection handling and proper conversion of SQLException to the DataAccessException hierarchy, including translation of database-specific SQL error codes to meaningful exception classes. For ORM technologies, see the next section for how to get the same exception translation benefits.
Spring의 인프라는 리소스를 올바르게 처리해주고, 특정 API에서 발생하는 예외를 처리하기 쉬운 unchecked 예외 계층으로 변환해주는 기능을 제공합니다.
Spring은 어떤 데이터 접근 방식에서도 사용할 수 있도록 공통 DAO 예외 계층을 도입했으며, 이 계층을 통해 예외를 일관되게 처리할 수 있습니다.
예를 들어, 직접 JDBC를 사용할 경우, 이전에 언급한 JdbcTemplate 클래스가 커넥션 관리를 자동으로 해주고, SQLException을 Spring의 DataAccessException 계층으로 변환해줍니다. 또한, 데이터베이스마다 다른 SQL 오류 코드를 의미 있는 예외 클래스로 자동 번역해줍니다.
ORM 기술을 사용할 때도 동일한 예외 변환 혜택을 누릴 수 있는데, 이에 대해서는 다음 섹션에서 자세히 설명됩니다.
When it comes to transaction management, the JdbcTemplate class hooks in to the Spring transaction support and supports both JTA and JDBC transactions, through respective Spring transaction managers. For the supported ORM technologies, Spring offers Hibernate and JPA support through the Hibernate and JPA transaction managers as well as JTA support. For details on transaction support, see the Transaction Management chapter.
트랜잭션 관리 측면에서 보면, JdbcTemplate 클래스는 Spring의 트랜잭션 지원과 연동되어 동작하며, JTA 트랜잭션과 JDBC 트랜잭션을 모두 지원합니다. 이때 각각에 맞는 Spring의 트랜잭션 매니저를 사용합니다.
ORM 기술을 사용하는 경우에도 마찬가지로, Hibernate는 HibernateTransactionManager, JPA는 JpaTransactionManager,분산 트랜잭션이 필요한 경우에는 JtaTransactionManager를 통해 Spring이 트랜잭션을 지원합니다.
Exception Translation
When you use Hibernate or JPA in a DAO, you must decide how to handle the persistence technology’s native exception classes. The DAO throws a subclass of a HibernateException or PersistenceException, depending on the technology. These exceptions are all runtime exceptions and do not have to be declared or caught. You may also have to deal with IllegalArgumentException and IllegalStateException. This means that callers can only treat exceptions as being generally fatal, unless they want to depend on the persistence technology’s own exception structure. Catching specific causes (such as an optimistic locking failure) is not possible without tying the caller to the implementation strategy. This trade-off might be acceptable to applications that are strongly ORM-based or do not need any special exception treatment (or both). However, Spring lets exception translation be applied transparently through the @Repository annotation. The following examples (one for Java configuration and one for XML configuration) show how to do so:
Hibernate나 JPA를 DAO에서 사용할 때는, 해당 영속성 기술이 던지는 고유한 예외들을 어떻게 처리할지 결정해야 합니다.
사용하는 기술에 따라 DAO는 HibernateException 또는 PersistenceException의 하위 예외를 던지게 됩니다.
이러한 예외들은 모두 런타임 예외이기 때문에 명시적으로 선언하거나 반드시 잡아야 할 필요는 없습니다.
하지만 개발자는 경우에 따라 IllegalArgumentException, IllegalStateException 같은 예외도 함께 처리해야 할 수 있습니다.
이 말은 곧, 호출 측에서는 예외를 치명적인 오류로만 간주하거나, 구체적인 예외 처리를 하려면 해당 ORM 기술의 예외 구조에 의존해야 한다는 것을 의미합니다.
예를 들어 낙관적 락 실패(Optimistic Locking Failure) 같은 구체적인 상황을 잡아내려면, Hibernate나 JPA의 예외 계층 구조에 의존해야 하기 때문에 구현 기술에 종속될 수밖에 없습니다.
이러한 트레이드오프는 ORM 기술에 깊이 의존하는 애플리케이션이거나 특별한 예외 처리가 필요 없는 경우에는 받아들일 수 있습니다.
하지만 Spring에서는 @Repository 애너테이션을 사용하면 예외 변환을 자동으로 처리해주기 때문에, 개발자가 직접 기술별 예외 구조에 의존하지 않고도 통일된 방식으로 예외를 다룰 수 있습니다.
이후에는 Java 설정 방식과 XML 설정 방식에서 이 예외 변환을 적용하는 예제가 이어집니다.
@Repository
public class ProductDaoImpl implements ProductDao {
// class body here...
}
<beans>
<!-- Exception translation bean post processor -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
The postprocessor automatically looks for all exception translators (implementations of the PersistenceExceptionTranslator interface) and advises all beans marked with the @Repository annotation so that the discovered translators can intercept and apply the appropriate translation on the thrown exceptions.
Spring에서는 예외 변환을 자동으로 처리해주는 후처리기(postprocessor)가 존재합니다.
이 후처리기는 PersistenceExceptionTranslator 인터페이스를 구현한 모든 예외 변환기를 자동으로 탐색하고,@Repository 애너테이션이 붙은 모든 빈(Bean)에 대해 AOP 방식으로 예외 변환 로직을 적용합니다.
이로 인해, 해당 빈에서 발생한 예외는 ORM 기술 고유의 예외가 아니라,
Spring이 제공하는 공통 DataAccessException 계층으로 자동 변환되어 처리됩니다.
즉, 개발자는 특정 기술(Hibernate, JPA 등)의 예외 구조에 의존하지 않고, 일관된 방식으로 예외를 다룰 수 있게 됩니다.
In summary, you can implement DAOs based on the plain persistence technology’s API and annotations while still benefiting from Spring-managed transactions, dependency injection, and transparent exception conversion (if desired) to Spring’s custom exception hierarchies.
요약하자면, 개발자는 순수한 영속성 기술의 API와 애너테이션만을 사용하여 DAO를 구현하면서도, 다음과 같은 Spring의 기능들을 그대로 누릴 수 있습니다.
- 트랜잭션 관리: Spring이 트랜잭션을 관리해줍니다.
- 의존성 주입(DI): 필요한 의존성을 자동으로 주입받을 수 있습니다.
- 예외 변환: 원한다면 Spring이 제공하는 공통 예외 계층(DataAccessException)으로 예외를 자동 변환해줍니다.
즉, 구현은 기술에 맞게 단순하게 하면서도, Spring이 제공하는 강력한 인프라 기능들은 그대로 활용할 수 있다는 장점이 있습니다.
'공식문서' 카테고리의 다른 글
[Spring Docs] Hibernate (0) | 2025.04.25 |
---|---|
[Spring Docs] Introduction to ORM with Spring (0) | 2025.04.21 |
[Spring Docs] Data Access with R2DBC (0) | 2025.04.17 |
[Spring Docs] Initializing a DataSource (0) | 2025.04.15 |
[Spring Docs] Embedded Database Support (0) | 2025.04.14 |