Spring Boot 2.5.5, Java 11, Maven, MyBatis 기반의 프로젝트에 JPA를 추가하면서 겪은 설정 및 오류 해결 과정을 정리합니다.
MyBatis와 JPA를 병행하고자 할 때 주의해야 할 설정 방식과 실제 발생했던 오류의 원인을 함께 소개합니다.
프로젝트 환경
- Spring Boot: 2.5.5
- Java: 11
- 빌드 도구: Maven
- ORM 프레임워크: MyBatis (기존), JPA (추가)
- 데이터베이스: PostgreSQL
1. JPA 기본 설정 방법
1-1. Maven 의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
1-2. application.yml 설정 예시
spring:
datasource:
url: jdbc:postgresql://localhost:5432/sample_db
username: dbuser
password: dbpass
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: validate
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
1-3. Entity 및 Repository 구성
@Entity
@Table(name = "log_data")
@IdClass(LogDataId.class)
public class LogData {
@Id
@Column(name = "log_time")
private String logTime;
@Id
@Column(name = "source_id")
private String sourceId;
@Column(name = "score_value")
private Double scoreValue;
@Column(name = "meta_info")
private String metaInfo;
@Column(name = "category_name")
private String categoryName;
@Column(name = "category_rate")
private Double categoryRate;
@Column(name = "type_name")
private String typeName;
@Column(name = "type_value")
private String typeValue;
@Column(name = "factor_name")
private String factorName;
@Column(name = "factor_ratio")
private Double factorRatio;
}
public class LogDataId implements Serializable {
private String logTime;
private String sourceId;
public LogDataId() {}
public LogDataId(String logTime, String sourceId) {
this.logTime = logTime;
this.sourceId = sourceId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LogDataId)) return false;
LogDataId that = (LogDataId) o;
return Objects.equals(logTime, that.logTime) &&
Objects.equals(sourceId, that.sourceId);
}
@Override
public int hashCode() {
return Objects.hash(logTime, sourceId);
}
}
public interface LogDataRepository extends JpaRepository<LogData, LogDataId> {
}
1-4. 애플리케이션 클래스 설정
@SpringBootApplication
@EnableJpaRepositories("com.example.jpa.repository")
@EntityScan("com.example.jpa.entity")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 발생했던 오류와 원인
오류 메시지 예시
IllegalArgumentException: Not a managed type: class com.example.jpa.entity.LogData
주요 원인
원인 | 설명 |
---|---|
@Id 없음 |
JPA는 반드시 @Id 또는 복합키 설정 필요 |
@EntityScan 누락 |
Entity 클래스의 패키지가 스캔되지 않음 |
EntityManager 설정 누락 | MyBatis의 데이터소스가 우선 적용되어 JPA의 EntityManager가 초기화되지 않음 |
3. 해결 방법 – JPA 수동 구성
MyBatis 전용 설정이 존재하는 프로젝트에서는 JPA가 정상 작동하지 않을 수 있습니다. 이 경우, JPA 전용 설정 클래스를 명시적으로 구성해 충돌을 방지할 수 있습니다.
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.jpa.repository",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager"
)
public class JpaDatabaseConfig {
@Primary
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.example.jpa.entity");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "validate");
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
em.setJpaPropertyMap(properties);
return em;
}
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory().getObject());
}
}
정리
- JPA를 사용할 때는 반드시
@Entity
와@Id
를 포함한 클래스 구조를 갖추어야 합니다. - MyBatis와 함께 사용할 경우에는 각각의 데이터소스, 트랜잭션, 매퍼 패키지를 명확하게 분리해야 안정적으로 작동합니다.
- Spring Boot의 자동 구성에 의존하기보다, 직접
EntityManagerFactory
와TransactionManager
를 명시하는 방식이 더 안정적입니다.
결론
MyBatis 기반 프로젝트에 JPA를 추가하는 과정에서 충돌이나 예외가 발생할 수 있지만,
설정 클래스를 명시적으로 분리하고 엔티티 구조를 정확히 구성하면 MyBatis와 JPA를 병행하여 안정적으로 운영할 수 있습니다.
JPA를 점진적으로 도입하거나 혼합 구조로 개발하는 프로젝트에서는 이와 같은 구성이 큰 도움이 됩니다.
반응형
'개발 (Development) > Java' 카테고리의 다른 글
[Java] MyBatis와 JPA 속도 비교: 어떤 상황에 어떤 선택이 더 나을까? (0) | 2025.08.03 |
---|---|
[Java] MyBatis만 쓰던 내가 JPA를 처음 접했을 때 이해한 구조 정리 (0) | 2025.08.03 |
[Java] Spring Boot 2.x + Java 11 환경에서 JPA Native Query와 DTO 매핑 문제 해결 기록 (4) | 2025.08.03 |
[Java] PostgreSQL의 timestamptz를 Java MyBatis에서 Instant로 받는 방법 (2) | 2025.07.28 |
[Java] ISO 8601 형식의 시간 출력하기 (현재 시간과 과거 시간 구하기) (2) | 2025.07.20 |