如何解决Hibernate 如何管理枚举?
我正在编写一个使用 Hibernate 访问数据库的 Micronaut 应用程序。当我尝试使用 enum
值查询实体时,会出现我遇到的问题。如果我将枚举的实例传递到 repo 中,那么一切正常。但是,如果我将枚举的一个实例传递给服务层(标记为 @Transactional
),那么我会收到 Hibernate 异常。我不知道为什么,因为我不相信枚举是 Hibernate 管理的 bean。
我将发布一个简化的示例。
控制器方法:
@Get("/api/frames")
@TransactionalAdvice(readOnly = true)
@Transactional
fun findFrames(): HttpResponse<Frame> {
val response = frameService.findFrames(FrameState.SUCCESS)
return HttpResponse.ok(response)
}
请注意,如果上述方法未标记为 @Transactional
,则此端点将导致 Hibernate 异常,我无法弄清楚为什么会这样。
服务方式:
@TransactionalAdvice(readOnly = true)
@Transactional
open fun findFrames(
state: FrameState
): List<Frame> {
return frameRepository.findFrames(state)
}
请注意,这也被标记为事务性。
存储库方法(类用 @Repository
注释):
fun findFrames(
state: FrameState?
): List<Frame> {
val criteriaBuilder = entityManager.criteriaBuilder
val criteriaQuery = criteriaBuilder.createQuery(Frame::class.java)
val root = criteriaQuery.from(Frame::class.java)
val predicates = mutableListOf<Predicate>()
state?.let { predicates.add(criteriaBuilder.equal(root.get<FrameState>("state"),state)) }
criteriaQuery.select(root).where(*predicates.toTypedArray())
val query = entityManager.createQuery(criteriaQuery)
return query.resultList
}
最后是实体:
@Entity
@Table(name = "frame")
data class Frame(
@Column(nullable = false)
var title: String,@Column(nullable = false)
var width: Short,@Column(nullable = false)
var height: Short,@Enumerated(EnumType.STRING)
@Column(nullable = false)
var state: FrameState,) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "frame_id",insertable = false,nullable = false,updatable = false)
var id: Int = 0
}
这是当控制器方法未标记为 @Transactional
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at io.micronaut.transaction.hibernate5.MicronautSessionContext.currentSession(MicronautSessionContext.java:100)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:479)
at io.micronaut.configuration.hibernate.jpa.TransactionalSessionInterceptor.intercept(TransactionalSessionInterceptor.java:56)
at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:96)
at io.micronaut.configuration.hibernate.jpa.TransactionalSession$Intercepted.getCriteriaBuilder(Unknown Source)
at com.example.repository.FrameRepository.findFrames(FrameRepository.kt:27)
at com.example.service.FrameService.findFrames(FrameService.kt:73)
at com.example.controller.FrameController.findFrames(FrameController.kt:168)
at com.example.controller.$FramesControllerDefinition$Intercepted.$$access$$findFrames(Unknown Source)
at com.example.controller.$FrameControllerDefinition$$exec3.invokeInternal(Unknown Source)
at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:151)
at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:87)
at io.micronaut.validation.ValidatingInterceptor.validateReturnExecutableValidator(ValidatingInterceptor.java:152)
at io.micronaut.validation.ValidatingInterceptor.intercept(ValidatingInterceptor.java:100)
at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:96)
at com.example.controller.$FrameControllerDefinition$Intercepted.findFrames(Unknown Source)
at com.example.controller.$FrameControllerDefinition$$exec3.invokeInternal(Unknown Source)
at ...
我的问题是,如果 @Transactional
只是一个枚举而不是一个 Hibernate 托管 bean,为什么我需要将我的控制器方法标记为 FrameState
?
注意,执行这一行时会抛出异常:
val criteriaBuilder = entityManager.criteriaBuilder
解决方法
我猜它没有连接到 Enum,这是因为 Hibernate 管理会话和连接的方式。
用非常简单的话来说:通过将函数注释为 @Transactional
会打开一个新会话,并且您可能需要一个会话来执行要在存储库函数中执行的操作。
我敢打赌,只需将 Repository.findFrames
函数注释为 @Transactional
而其余部分保持原样。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。