[Java/Intellij] JPA 에러 (javax → jakarta) UnsupportedOperationException, PersistenceException

febCho·2024년 6월 13일
0

오류 해결

목록 보기
15/19
post-thumbnail

문제 1

메인 메서드를 실행해 JPA 쿼리를 작성하고 날렸더니 아래와 같은 오류가 났다.

Exception in thread "main" java.lang.UnsupportedOperationException: The application must supply JDBC connections
at (생략)

h2 콘솔도 제대로 작동 중이었고 강의에서 알려준 대로 pom.xml에 dependency 설정도 했는데, 왜 Hibernate에서 JDBC 연결을 제공하지 못할까 알 수 없었다.

원인 1

우선 에러 메시지 그대로 데이터베이스 연결 설정이 제대로 되어 있지 않거나 드라이버가 제대로 로드되지 않아 insert문을 날리지 못한 거였다.

앞서 언급한 것처럼 EntityManagerFactory와 EntityManager를 제대로 얻어 왔고, 콘솔도 제대로 작동 중이었다면 문제는 persistence.xml 혹은 pom.xml, 즉 설정에 있다.

나의 경우에는 Hibernate 6 버전 이상을 사용하면서 javax 패키지가 아닌 jakarta 패키지로 변경해 의존성이 명시되어 있었기에 이 과정에서 문제가 발생한 것 같다고 추정했다.

해결 1

Dependencies 업데이트

우선 pom.xml에서 dependencies를 업데이트했다. 아래는 업데이트 전 코드이다.

<dependencies>
<!-- JPA 하이버네이트 -->
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-entitymanager</artifactId>
		<version>5.3.10.Final</version>
	</dependency>
<!-- H2 데이터베이스 -->
	<dependency>
		<groupId>com.h2database</groupId>
		<artifactId>h2</artifactId>
		<version>2.2.224</version>
	</dependency>
</dependencies>

이중 첫 번째 <dependency>에는 노란 밑줄이 그어져 있었는데, 찾아 보니 동작 상의 문제는 없다고 해서 그냥 놔뒀었다. 그런데 검색을 해보니 Hibernate 6 버전부터는 hibernate-entitymanager가 hibernate-core에 통합되었다고 한다. 그래서 core만 추가하고 entitymanager 모듈은 제거하기로 했다.

그리고 persistence.xml의 <property>와 패키지 import 시 javax를 jakarta로 변경하기만 했는데, Jakarta Persistence 종속성이 올바르게 포함되어 있어야 한다고 해서 최종적으로 아래와 같이 수정을 마쳤다.

<dependencies>
    <!-- Hibernate Core -->
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.4.2.Final</version>
        </dependency>

        <!-- H2 데이터베이스 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.2.224</version>
        </dependency>

        <!-- Jakarta Persistence API -->
        <dependency>
            <groupId>jakarta.persistence</groupId>
            <artifactId>jakarta.persistence-api</artifactId>
            <version>3.1.0</version>
        </dependency>

        <!--javax.xml.bind.JAXBException-->
  		(생략)
</dependencies>

문제 2

그렇게 수정을 마친 뒤 프로젝트를 Reload 하였는데, 이번엔 또 다른 에러가 났다.

WARNING: jakarta.persistence.spi::No valid providers found.
Exception in thread "main" jakarta.persistence.PersistenceException: No Persistence provider for EntityManager named hello
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:86)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at hellojpa.JpaMain.main(JpaMain.java:10)

원인 2

이번에는 JPA 프로바이더를 찾지 못해 발생한 에러였다. 이 역시 xml 등의 설정 단위에서 문제가 발생하는 거라고 하길래 이번엔 Jakarta 관련 <property>가 명시되어 있는 persistence.xml을 수정했다.

해결 2

Persistence.xml 수정

수정 이전의 코드다. value 값이 틀리지 않았다는 것을 전제로 한다.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          	 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">

<persistence-unit name="hello">
  <properties>
    <!-- 필수 속성 -->
    <property name="jakarta.persistence.jdbc.driver" value="(생략)"/>
    <property name="jakarta.persistence.jdbc.user" value="(생략)"/>
    <property name="jakarta.persistence.jdbc.password" value="(생략)"/>
    <property name="jakarta.persistence.jdbc.url" value="(생략)"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
    <!-- 옵션 -->
    (생략)
</persistence-unit>

그리고 아래는 수정 이후의 코드다.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="3.0"
             xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
    <persistence-unit name="hello">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>hellojpa.Member</class>
        <class>hellojpa.JpaMain</class>
        <properties>
(이하 동일)         

바뀐 부분은 첫째, persistence.xml의 xmlns가 변경되었다.
Persistence 3.0 이상에서는 http://xmlns.jcp.org/xml/ns/persistence가 아닌 https://jakarta.ee/xml/ns/persistence를 사용한다고 한다.

둘째, xsi:schemaLocation에서 대상 네임스페이스를 제대로 참조해줄 수 있도록 jakarta.ee로 맞추어 준다.

셋째, JPA Provider@Entity class를 제대로 명시해 주었다.
Provider를 찾지 못하는 게 에러 메시지의 핵심이었기 때문에 <provider> 태그를 추가해 Hibernate 6 이상 버전에서 사용하는 Provider를 기입했다.

그리고 보통 실무에서는 스프링과 함께 JPA를 사용하게 되는데, 스프링에는 자동으로 엔티티를 스캔하는 기능이 내장되어 있어 <class></class>로 엔티티를 추가할 필요가 없다고 한다. 아직 강의에서 스프링을 접목하기 전이라 추가를 해주었다.

이렇게 크게 3가지 수정을 마친 뒤 프로젝트를 Reload 하니 다음과 같이 Insert 쿼리가 제대로 날라간 걸 확인할 수 있었다.

- 관련 수업

[인프런] 자바 ORM 표준 JPA 프로그래밍 - 기본편 / 김영한

profile
Done is better than perfect.

0개의 댓글