我正在用我以前的JPA知识学习Springboot。目前正在尝试使用MySQL DB创建一个简单的Web应用程序。首先,我创建了两个表users
和users_session_data
。users_session_data
具有OneToOne
关系,这意味着每个用户可以同时拥有会话数据。现在我想创建一个用户,但它给了我以下例外:
org.hibernate.PersistentObjectException: detached entity passed to persist: com.simpleapp.entities.EntityUsersSessionData
at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:88)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:54)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:755)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:739)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360)
at jdk.proxy2/jdk.proxy2.$Proxy137.persist(Unknown Source)
at com.simpleapp.core.AbstractFacade.createRecord(AbstractFacade.kt:100)
at com.simpleapp.flows.FlowUsersSessions.create(FlowUsersSessions.kt:42)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at com.simpleapp.flows.FlowUsersSessions$$SpringCGLIB$$0.create(<generated>)
at com.simpleapp.flows.FlowUsers.login(FlowUsers.kt:71)
at com.simpleapp.controllers.restful.services.users.ServiceUsersLogin.getData(ServiceUsersLogin.kt:38)
at com.simpleapp.controllers.restful.services.users.ServiceUsersLogin.getData(ServiceUsersLogin.kt:12)
at com.simpleapp.core.restful.AbstractRestService.getResponse(AbstractRestService.kt:26)
at com.simpleapp.controllers.restful.ControllerUsers.getUserLogin(ControllerUsers.kt:34)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at com.simpleapp.filters.AppSecurityFilter.doFilter(AppSecurityFilter.kt:62)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at com.simpleapp.filters.AppSecurityFilter.doFilter(AppSecurityFilter.kt:62)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
我的课程如下:BaseEntity
:
@MappedSuperclass
abstract class BaseEntity : java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "ID", nullable = false)
open var id: Int? = null
@Basic(optional = false)
@Column(name = "STATUS", nullable = false)
@Enumerated(EnumType.STRING)
open var status: DBEntryStatusTypeEnum = DBEntryStatusTypeEnum.ACTIVE
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = Utils.JSON_DATE_FORMAT)
@Basic(optional = false)
@Column(name = "CREATED_AT", nullable = false)
@Temporal(TemporalType.DATE)
open var createdAt = Date()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BaseEntity
if (id != other.id) return false
if (status != other.status) return false
return true
}
override fun hashCode(): Int {
var result = id ?: 0
result = 31 * result + (status.hashCode())
return result
}
}
BaseUserEntity
:
@MappedSuperclass
open class BaseUserEntity : BaseEntity() {
@Id
@Basic(optional = false)
@Column(name = "ID", nullable = false)
@JsonIgnore
@XmlTransient
override var id: Int? = null
@JsonIgnore
@XmlTransient
@JoinColumn(name = "ID", referencedColumnName = "ID", nullable = false, insertable = false, updatable = false)
@OneToOne(optional = false, fetch = FetchType.LAZY)
open var users: EntityUsers? = null
}
EntityUsers
:
@Entity
@Table(name = "users")
@XmlRootElement
class EntityUsers : BaseEntity() {
@Column(name = "NICK", length = 255)
var nick: String? = null
@Basic(optional = false)
@Column(name = "NAME_SURNAME", nullable = false, length = 255)
var nameSurname: String? = null
@Column(name = "ABOUT", length = 300)
var about: String? = null
@Column(name = "BIRTHDAY")
@Temporal(TemporalType.DATE)
var birthday: Date? = null
@Column(name = "LAST_LOGIN")
@Temporal(TemporalType.TIMESTAMP)
var lastLogin = Date()
@XmlTransient
@JsonIgnore
@OneToOne(cascade = [CascadeType.ALL], mappedBy = "users", fetch = FetchType.LAZY)
var usersSessionData: EntityUsersSessionData? = null
}
EntityUsersSessionData
:
@Entity
@Table(name = "users_session_data")
@XmlRootElement
class EntityUsersSessionData : BaseUserEntity() {
@Basic(optional = false)
@Column(name = "TOKEN", nullable = false, length = 255)
var token: String? = null
}
FlowUsers
:
@Component
class FlowUsers {
@Autowired
@org.springframework.context.annotation.Lazy
lateinit var daoFactory: DaoFactory
@Autowired
@org.springframework.context.annotation.Lazy
lateinit var flowUserSessions: FlowUsersSessions
/**
* Returns dao object of users.
*/
fun getDao() = daoFactory.getDaoUsers()
/**
* Checks if user exists and if exists returns user, if not, creates user then returns.
*/
fun login(data: RequestModelUserLogin, ipAddress: String?): EntityUsers? {
// Get user from the token via Firebase.
val userData = FirebaseClientAuth.getCredentialsForToken(data.token) ?: return null
// Otherwise create the user.
var user = EntityUsers().apply {
avatar = userData.photoUrl
nameSurname = userData.displayName
birthday = null // This will be filled by user.
email = if (userData.email.isNullOrEmpty()) data.email else userData.email
}
// attached new id to the mUser (by creating database row instance)
user = getDao().createRecord(user)
// creates session for the first time for user and attaches it to user
user.usersSessionData = flowUserSessions.create(user)
return getDao().updateRecord(user)
}
}
FlowUsersSessions
:
@Component
class FlowUsersSessions {
@Autowired
@org.springframework.context.annotation.Lazy
lateinit var daoFactory: DaoFactory
@Autowired
@org.springframework.context.annotation.Lazy
lateinit var flowUsers: FlowUsers
/**
* Returns the dao object of user sessions.
*/
fun getDao() = daoFactory.getDaoUsersSessions()
/**
* Returns a session for the given token.
*/
fun getByToken(token: String) = getDao().getByToken(token = token)
/**
* Creates a user session entity, right after creating the user.
*/
fun create(user: EntityUsers): EntityUsersSessionData? {
val record = EntityUsersSessionData().apply {
id = user.id
status = user.status
createdAt = Date()
token = UUID.randomUUID().toString()
}
return getDao().createRecord(record)
}
}
我尝试将CascadeType.ALL替换为CascadeType.PERSIST和CascadeType.MERGE,但没有成功。
1条答案
按热度按时间5kgi1eie1#
发生这种情况的原因是,您正在持久化一个新的PsychologyUsers,但已将现有(分离的)PsychologyUsersSessionData包括在用户的usersSessionData中,并且您将Map设置为级联持久化操作。这与在现有的EntityUsersSessionData示例上调用entityManager.persist(entityUsersSessionData)相同-因为它已经存在,所以需要JPA抛出错误。
您需要确定要对这些IdentyUsersSessionData示例执行什么操作;你想不想把它们合并进去最简单的解决方案是不要在Map上放置cascade选项:
在Map上应用CascadeType选项时要谨慎,并且只在需要时才应用,因为它们对应用程序的影响并不总是预先被注意到。