반응형
0. 에러 상황
- TestCode 작성 중 단순 save - find 코드를 작성했는데 아래와 같은 에러가 발생
failed to lazily initialize a collection of role: com.demo.jpastudy.entity.UserEntity.addressList, could not initialize proxy - no Session
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.demo.jpastudy.entity.UserEntity.addressList, could not initialize proxy - no Session
at app//org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:614)
at app//org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at app//org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:591)
at app//org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at app//org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:621)
...
- 에러를 확인해보면 지연 생성된 proxy를 no Session이라는 이유로 생성하지 못했다는 에러이다.
- 아래는 Test Code와 Entity Code 이다
Test Code
@SpringBootTest
internal class UserServiceTest {
@Autowired
lateinit var userRepository: UserRepository
@BeforeEach
fun createUser() {
val user = UserEntity(
name = "demo"
)
val address = AddressEntity(
address = "address1",
user = user
)
user.addressList.add(address)
val saveUser = userRepository.save(user)
}
@Test
fun getAddressByUserId() {
val demo = userRepository.findByName("demo")
println("demo: ${demo?.addressList}")
}
}
Repository
import com.demo.jpastudy.entity.AddressEntity
import com.demo.jpastudy.entity.UserEntity
import org.springframework.data.jpa.repository.JpaRepository
interface UserRepository : JpaRepository<UserEntity, Long> {
fun findByName(name: String): UserEntity?
}
interface AddressRepository : JpaRepository<AddressEntity, Long> {
fun findByAddress(address: String): AddressEntity
}
Entity
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne
import javax.persistence.OneToMany
import javax.persistence.Table
@Table(name = "user")
@Entity
class UserEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@Column(name = "name")
val name: String? = null,
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL])
val addressList: List<AddressEntity> = listOf()
) {
override fun toString(): String {
return "UserEntity(id = $id, name = $name, addressList = $addressList)"
}
}
@Table(name = "address")
@Entity
class AddressEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
@ManyToOne
@JoinColumn(name = "user_id")
val user: UserEntity? = null,
@Column(name = "address")
val address: String? = null
) {
override fun toString(): String {
return "AddressEntity(id = $id, address = $address)"
}
}
- 눈치가 빠른 사람이라면 바로 알아차릴 수 있을 것이다.
- Address는 UserEntity 내부에서 toString() 메소드에서 Lazy 로딩으로 불러오는 상황이고, 영속성 컨텍스트의 범위는 Transaction 단위이다.
- 존재하지 않는 영속성 컨텍스트에서 Address Entity 를 가지고 오려고 하니 no Session 이라는 에러와 함께 lazily initialize proxy를 불러오는데 실패한다고 알려주고 있다.
1. 해결 방법
FetchType.EAGER 사용
- lazy loading방식이 아니라 eager loading 방식으로 변경하면 동일한 영속성 컨텍스트에서 연관 entity를 모두 불러올 수 있기 때문에 해당 에러를 해결할 수 있다.
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
val addressList: MutableList<AddressEntity> = mutableListOf()
@Transactional annotation 사용
- 단일 Transaction 묶어 lazy 로딩 시에도 동일한 영속성 컨텍스트에서 Address Entity를 불로 올 수 있게 한다.
@Transactional
@Test
fun getAddressByUserId() {
val demo = userRepository.findByName("demo")
println("demo: $demo")
}
@DataJpaTest annotation 사용
- DataJpaTest annotation을 확인해보면 이미 @Transactional annotation 이 포함된 걸 볼 수 있다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(DataJpaTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest {
...
}
반응형
'IT > 데이터베이스' 카테고리의 다른 글
[JPA] Null value was assigned to a property exception (0) | 2022.09.18 |
---|---|
JPA 낙관적 잠금 (Optimistic locking)을 알아보자 (0) | 2022.09.13 |
JPA 공부 - 6 (0) | 2021.02.25 |
JPA 공부 - 3 (0) | 2021.02.25 |
JPA 공부 - 5 (0) | 2021.02.07 |