1、報錯日誌:
在儲存xx資訊時,如果選了裝置資訊,後台不會報錯,如果沒選裝置,就會報錯,報錯資訊如下:
[2017-08-10 08:41:02] org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:173) <ERROR> HandlerInterceptor.afterCompletion threw exceptionorg.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.hcepms.model.device.Device org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:279) at org.hibernate.type.EntityType.getIdentifier(EntityType.java:462) at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:281) at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:291) at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:296) at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:4144) at org.hibernate.event.internal.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:532) at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:215) at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:142) at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216) at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) at com.hcepms.base.dao.BaseDaoImpl.save(BaseDaoImpl.java:38) at com.hcepms.base.service.BaseServiceImpl.save(BaseServiceImpl.java:38) at com.hcepms.base.interceptor.SecurityAndLogInterceptor.afterCompletion(SecurityAndLogInterceptor.java:150) at org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:170) at org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletion(DispatcherServlet.java:1297) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:976) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869) at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.springframework.orm.hibernate5.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)log4j:ERROR Failed to write [[2017-08-10 08:41:02] <http-nio-8080-exec-5> org.springframework.web.servlet.HandlerExecutionChain.triggerAfterCompletion(HandlerExecutionChain.java:173) <ERROR> HandlerInterceptor.afterCompletion threw exception
2、hibernate.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.hcepms.model.device.enter" default-access="field"><class name="DeviceEnterDetail" table="T_DEVICE_ENTER_DETAIL"> <many-to-one name="device" class="com.hcepms.model.device.base.Device" fetch="select" lazy="false"//不消極式載入 not-found="ignore">//指定引用的外鍵不存在時"忽略" <column name="DEVICE_"/> </many-to-one></class></hibernate-mapping>
3、controller中儲存方法的代碼:
/** * * 儲存XX資訊 * @author zhangsan * @date 2016年8月2日 * @param deviceEnterDetail XX資訊 * @param session * @return * @throws Exception */@ResponseBody@RequestMapping("/saveOrUpdateDetail")public Json saveOrUpdateDetail(DeviceEnterDetail deviceEnterDetail,HttpSession session)throws Exception{ Json json = new Json(); String operat = (deviceEnterDetail.getId() == null ? "新增" : "編輯"); try { SessionInfo sessionInfo = (SessionInfo)session.getAttribute("sessionInfo"); UserDetail user = new UserDetail(); user.setId(sessionInfo.getUserId()); if(deviceEnterDetail.getId() == null){ deviceEnterDetail.setCreateDate(new Date()); deviceEnterDetail.setCreateUser(user); deviceEnterDetail.setStatus(1); }else{ deviceEnterDetail.setUpdateDate(new Date()); deviceEnterDetail.setUpdateUser(user); } dEDetailService.saveOrUpdate(deviceEnterDetail); json.setSuccess(true); json.setMsg(operat + "XX資訊成功"); } catch (Exception e) { log.error(operat + "XX信資訊異常",e); json.setSuccess(true); json.setMsg(operat + "XX信細資訊失敗"); } return json;}
4、頁面如下圖
裝置可選,可不選
<label for="useDev" class="col-xs-1 control-label" style="white-space: nowrap;"><a class="require"><i class="icon-Asterisk"></i></a>裝置名稱</label><div class="col-xs-3"> <div class="threepoint icon-DownMenu3" onclick="selectDevice()"> </div> <input type="text" class="form-control sel" id="useDev" placeholder="請選擇裝置" readonly> <input type="hidden" id="deviceId" name="device.id" /> </div>
5、解決方案
在controller中saveOrUpdateDetail方法中,在dEDetailService.saveOrUpdate(deviceEnterDetail);之前添加
if(deviceEnterDetail.getDevice() == null || deviceEnterDetail.getDevice().getId() == null){ deviceEnterDetail.setDevice(null);}
6、小結:
本人並沒有使用級聯。是儲存單個對象,而這個有關聯的對象,你的頁面可以對這個關聯對象不選值,就是給關聯對象不選id值,這樣的話?springmvc會把你的關聯對象重新new一個Null 物件賦給此對象,而這個Null 物件在資料庫肯定是沒有的,所以在儲存該對象的時候就會報關聯的沒選值的對象為瞬時態的錯誤。解除決辦法就是在hibernate儲存單個對象之前,做一下判斷關聯的對象是否為空白(注意關聯的對象實體配置必須配製關聯對象可為null),如果為空白,則將關聯對象set為null。