我对 Spring Web Flow 和 Spring Data JPA 比较陌生。我在网上搜索了没有运气,并真诚地希望我能找到帮助。
我正在尝试利用 PersistenceContext 标记将对象保存在流中。当我省略标签时,一切都运行良好,但这不是我的想法,因为我不希望事务提交到流程结束。
当我使用 PersistenceContext 保存时,我得到了一个不知从何而来的失败更新,如控制台所示,
Hibernate: insert into Tb_Horario (DescripcionRestringido, Fase, FechaFin, FechaInicio, FlagReservado, FlagRestringido, HorasTotal, Operador) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update Tb_Horario set Fase=?, Id=? where id=?
并且因为Id
得到了 Identity 自动生成的值,所以我在错误跟踪中得到了 java.sql.SQLException。正如我所说,当我省略persistente 上下文时,我只得到插入但没有阻塞更新。
我提前感谢任何帮助。
这是我的流程:
<persistence-context />
<input name="solicitudId" required="true" />
<on-start>
<evaluate expression="solicitudService.armarSolicitudDTO(solicitudId)" result="flowScope.solicitudDTO" />
</on-start>
<view-state id="programarSolicitud" model="solicitudDTO">
<on-render>
<render fragments="body" />
</on-render>
<transition on="programarFase" to="programarOperador" >
<set name="viewScope.operadorId" value="currentEvent.attributes.operadorId"/>
<set name="viewScope.ordenFase" value="currentEvent.attributes.ordenFase"/>
<evaluate expression="operadorService.findById(operadorId)" result="flowScope.operador" />
<evaluate expression="solicitudDTO.getFases().get(ordenFase)" result="flowScope.fase" />
</transition>
<transition on="programarSolicitud" to="programacionRegistrada"/>
</view-state>
<view-state id="programarOperador" model="horarioDTO">
<var name="horarioDTO" class="org.mbcorp.sar.model.Horario"/>
<on-render>
<render fragments="body" />
</on-render>
<transition on="programarHorario" to="programarSolicitud">
<evaluate expression="horarioService.save(horarioDTO)" />
</transition>
</view-state>
<end-state id="programacionRegistrada" commit="true"/>
我的网络流配置文件:
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="securityFlowExecutionListener" />
<webflow:listener ref="jpaFlowExecutionListener" />
</webflow:flow-execution-listeners>
</webflow:flow-executor>
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"
development="true" validator="validator" />
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="tilesViewResolver"/>
<property name="useSpringBeanBinding" value="true" />
</bean>
<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="jpaFlowExecutionListener"
class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
<constructor-arg ref="entityManagerFactory" />
<constructor-arg ref="transactionManager" />
</bean>
还有持久性 bean:
<jpa:repositories base-package="org.mbcorp.sar.dao" />
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.mbcorp.sar.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="database" value="SQL_SERVER" />
<property name="databasePlatform" value="org.hibernate.dialect.SQLServerDialect" />
</bean>
</property>
</bean>
编辑:错误跟踪如下:
oct 22, 2013 9:52:24 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: El Servlet.service() para el servlet [Spring MVC Dispatcher Servlet] en el contexto con ruta [/sar] lanzó la excepción [Request processing failed; nested exception is org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@b2a6737 targetAction = [EvaluateAction@2708a9c6 expression = horarioService.save(horarioDTO), resultExpression = [null]], attributes = map[[empty]]] in state 'programarOperador' of flow 'views/programacion' -- action execution attributes were 'map[[empty]]'] con causa raíz
java.sql.SQLException: No se puede actualizar la columna de identidad 'Id'.
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:368)
at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2820)
at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2258)
at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:632)
at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:584)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:546)
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:506)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:58)
at org.hibernate.persister.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1474)
at org.hibernate.persister.collection.OneToManyPersister.insertRows(OneToManyPersister.java:190)
at org.hibernate.action.internal.CollectionUpdateAction.execute(CollectionUpdateAction.java:86)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:278)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:328)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1233)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:403)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:513)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy60.save(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:69)
at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:286)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:82)
at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:98)
at org.springframework.binding.expression.spel.SpringELExpression.getValue(SpringELExpression.java:84)
at org.springframework.webflow.action.EvaluateAction.doExecute(EvaluateAction.java:75)
at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145)
at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
at org.springframework.webflow.engine.support.ActionTransitionCriteria.test(ActionTransitionCriteria.java:82)
at org.springframework.webflow.engine.support.TransitionCriteriaChain.test(TransitionCriteriaChain.java:68)
at org.springframework.webflow.engine.Transition.canExecute(Transition.java:196)
at org.springframework.webflow.engine.Transition.execute(Transition.java:212)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:395)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214)
at org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:116)
at org.springframework.webflow.engine.Flow.handleEvent(Flow.java:547)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:390)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210)
at org.springframework.webflow.engine.ViewState.handleEvent(ViewState.java:231)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:195)
at org.springframework.webflow.engine.Flow.resume(Flow.java:537)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:227)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:125)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
EDIT2:这里的Horario
类
@Entity
@Table(name = "Tb_Horario")
public class Horario implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name = "HorasTotal", nullable = false)
private Integer horasTotal;
@DateTimeFormat(pattern = "dd-MM-yyyy")
@Column(name = "FechaInicio", nullable = false)
private Date fechaInicio;
@Column(name = "FechaFin", nullable = false)
private Date fechaFin;
@Column(name = "FlagRestringido", nullable = false)
private boolean flagRestringido;
@Column(name = "DescripcionRestringido", nullable = true)
private String descripcionRestringido;
@Column(name = "FlagReservado", nullable = false)
private boolean flagReservado;
@JoinColumn(name = "Operador")
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Operador operador;
@JoinColumn(name = "Fase")
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Fase fase;
@Transient
private int horaInicio;
...
//setters and getters
}
和Fase
类:
@Entity
@Table(name = "Tb_Fase")
public class Fase implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name = "Nombre", nullable = false)
private String nombre;
@Column(name = "Descripcion", nullable = false)
private String descripcion;
@Column(name = "FechaRegistro", nullable = false)
private Date fechaRegistro;
@Column(name = "FechaInicio", nullable = true)
private Date fechaInicio;
@Column(name = "FechaFin", nullable = true)
private Date fechaFin;
@Column(name = "Comentarios", nullable = true)
private String comentarios;
@Column(name = "EsfuerzoEstimado", nullable = true)
private Integer esfuerzoEstimado;
@Column(name = "CostoEstimado", nullable = true)
private Integer costoEstimado;
@Column(name = "EsfuerzoReal", nullable = true)
private Integer esfuerzoReal;
@Column(name = "CostoReal", nullable = true)
private Integer costoReal;
@JoinColumn(name = "Solicitud", insertable = false, updatable=false, nullable = false)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Solicitud Solicitud;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "Fase", nullable = true)
@IndexColumn(name= "Id")
private List<Horario> horarios;
@ManyToMany
@LazyCollection(LazyCollectionOption.FALSE)
@JoinTable(name="tb_CompetenciaFase", joinColumns = {@JoinColumn(name="IdFase")},
inverseJoinColumns={@JoinColumn(name="IdCompetencia")})
private List<Competencia> competencias;
@Column(name = "RecursosEstimados", nullable = true)
private Integer recursosEstimados;
@Column(name = "OrdenFase", nullable = true)
private Integer ordenFase;
@Transient
private List<Operador> recursosDisponibles;
@Transient
private int recursosUtilizados;
@Transient
private int horasProgramadas;
...
/getters and setters
}
horarioService.save(horarioDTO) 方法只是调用一个从 .save@Service
调用 save 方法的类JpaRepository
。我对其进行了测试并正在做它的工作,只调用一个INSERT
查询。但我完全不知道是什么产生了UPDATE
(或者如果它是预期的,为什么工作很奇怪),当<persistence-context/>
它出现在流中时出现。
EDIT3:我将 Horario 映射更改为:
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "Fase", nullable = true)
@IndexColumn(name= "HorasTotal")
private List<Horario> horarios;
并抑制(违背我的意愿)列Fase
和HorasTotal
. 它现在部分地处理一些奇怪或预期的行为。让我详细说明:
第一个问题:
插入后我仍然得到更新:
Hibernate: insert into Tb_Horario (DescripcionRestringido, Fase, FechaFin, FechaInicio, FlagReservado, FlagRestringido, HorasTotal, Operador) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: update Tb_Horario set Fase=?, HorasTotal=? where id=?
我没有从中得到任何问题Fase
,但是 的值HorasTotal
正在根据顺序被覆盖,所以我正在考虑创建一个特殊的列来索引表。
第二期:
无论流程结束,即 COMMIT 发生的Horario
位置,信息都保存在数据库中。我应用此解决方案将flushMode 设置为COMMIT,但数据COMMIT 与否。
PS:我用缺少的结束状态更新了流程。