Home » Eclipse Projects » EclipseLink » update in new transaction hangs program
update in new transaction hangs program [message #783675] |
Thu, 26 January 2012 07:08 |
Ari Meyer Messages: 136 Registered: July 2009 |
Senior Member |
|
|
Hi,
I'm using Spring 2.5.6 and Eclipselink JPA 2.1.3 (also tested against
2.3.2) on Oracle 11.2, using a non-JTA datasource. I have a case where
I'm logging messages to a DB using JPA. I have a parent-child
relationship between the basic run info (ProcessRun) and each log
message (ProcessRunLog). Each ProcessRunLog (log message) must be
persisted and committed immediately, and there will be no updates to log
messages. Also, every update to the parent ProcessRun record (status
updates, etc.) must be committed immediately. The ProcessRunLogs are
being persisted and committed properly. ProcessRuns, though, while
initially persisting fine, hang the whole program when I try to update
them in a new transaction:
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public ProcessRun update(ProcessRun aProcessRun)
{
return _entityManager.merge(aProcessRun);
}
If I just let the updates commit along with the rest of the parent
transaction, everything goes through fine, but we need to see the
updates immediately (also, the ProcessRun updates can't be rolled back
if the parent transaction fails). It's strange, but no exception is
thrown -- it just hangs until I kill the process.
I've logged the Spring declarative transactions, and everything looks
fine, so I don't think it's a Spring issue. Here's the closest info
I've found, but I don't think the guy's answer is my issue:
http://stackoverflow.com/questions/8163458/spring-bean-hangs-on-method-with-transactional
Note that this is a single-threaded app, with no other process modifying
any of the data concurrently.
I also tried rewriting the update method to only update the relevant
data, even though I'm not cascading the MERGE, but got the same results:
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void update(ProcessRun aProcessRun)
{
// simple copy of only key fields rather than full merge
ProcessRun pr = _entityManager.find(ProcessRun.class,
aProcessRun.getId());
pr.setBatchRunId(aProcessRun.getBatchRunId());
pr.setProjectId(aProcessRun.getProjectId());
pr.setUser(aProcessRun.getUser());
pr.setStatus(aProcessRun.getStatus());
pr.setStartTime(aProcessRun.getStartTime());
pr.setEndTime(aProcessRun.getEndTime());
pr.setRowsProcessed(aProcessRun.getRowsProcessed());
}
Output just before it hangs:
[2012-01-23 01:10:06,029] DEBUG AnnotationTransactionAttributeSource
Adding transactional method [update] with attribute
[PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT]
[2012-01-23 01:10:06,851] DEBUG Slf4jSessionLog SELECT PROCESS_RUN_ID,
RUN_START_TIME, RUN_STATUS, PROCESS_TYPE_CODE, PROJ_ID, RUN_END_TIME,
RUN_BY_USER, ROWS_PROCESSED, BATCH_RUN_ID FROM CILSTAGE.PROCESS_RUN
WHERE (PROCESS_RUN_ID = ?)
bind => [210150]
[2012-01-23 01:10:06,936] DEBUG Slf4jSessionLog SELECT
PROCESS_TYPE_CODE, CREATE_USER, PROCESS_NAME, ACTIVE_FLAG, CREATE_DATE,
UPDATE_DATE, UPDATE_USER FROM CILSTAGE.PROCESS_TYPE WHERE
(PROCESS_TYPE_CODE = ?)
bind => [RMS]
[2012-01-23 01:10:07,029] DEBUG Slf4jSessionLog UPDATE
CILSTAGE.PROCESS_RUN SET RUN_STATUS = ?, RUN_START_TIME = ?,
RUN_END_TIME = ?, ROWS_PROCESSED = ? WHERE (PROCESS_RUN_ID = ?)
[2012-01-23 01:10:07,030] DEBUG Slf4jSessionLog bind =>
[COMPLETED_WITH_ERRORS, 2012-01-23 01:07:19.744, 2012-01-23
01:10:06.028, 24, 210150]
I'm attaching the 2 entities for your review.
Thanks,
Ari
package mil.army.usace.p2.entity;
import mil.army.usace.p2.constants.ProcessRunStatus;
import mil.army.usace.p2.util.ExtendedEqualsBuilder;
import mil.army.usace.p2.util.JpaUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
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.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
/**
* @version $Revision: 1275 $
* @author $Author: u4iesabm $
* Last Modified: $Date: 2011-07-28 18:16:54 -0500 (Thu, 28 Jul 2011) $
*/
@Entity
@Table(name="PROCESS_RUN", schema="CILSTAGE")
@SequenceGenerator(name="PROCESS_RUN_GEN", sequenceName="PROCESS_RUN_ID_SEQ", allocationSize=1)
public class ProcessRun
implements Serializable, Comparable<ProcessRun>
{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "PROCESS_RUN_ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PROCESS_RUN_GEN")
private Long id;
@Column(name = "PROCESS_TYPE_CODE")
private String processTypeCode = null;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="PROCESS_TYPE_CODE", insertable=false, updatable=false)
private ProcessType processType = null;
@Column(name="BATCH_RUN_ID")
private Long batchRunId;
@Column(name="PROJ_ID")
private Long projectId;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="PROJ_ID", insertable=false, updatable=false)
private UsaceProject project = null;
@Column(name = "ROWS_PROCESSED")
private int rowsProcessed = 0;
@Column(name = "RUN_BY_USER")
private String user;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "RUN_START_TIME")
private Date startTime;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "RUN_END_TIME")
private Date endTime;
@Column(name = "RUN_STATUS")
@Enumerated(EnumType.STRING)
private ProcessRunStatus status;
@Transient
private boolean scheduleChangesMade = false;
// bi-directional many-to-one association to ProcessRunLog
@OneToMany(
cascade={CascadeType.REMOVE, CascadeType.REFRESH, CascadeType.DETACH},
mappedBy = "processRun",
orphanRemoval=true)
@OrderBy
private List<ProcessRunLog> processRunLogs;
public ProcessRun()
{
super();
}
// initializes required fields
public ProcessRun(ProcessType aProcessType, String user)
{
this();
this.setProcessType(aProcessType);
this.user = user;
this.startTime = new Timestamp(System.currentTimeMillis()); // current timestamp
this.status = ProcessRunStatus.STARTED;
}
public ProcessRun(ProcessType aProcessType, String user, UsaceProject aUsaceProject)
{
this(aProcessType, user);
this.setProject(aUsaceProject);
}
public ProcessRun(ProcessType aProcessType, String user, Long batchRunId)
{
this(aProcessType, user);
this.setBatchRunId(batchRunId);
}
public ProcessRun(ProcessType aProcessType, String user, Long projectId, Long batchRunId)
{
this(aProcessType, user);
this.setProjectId(projectId);
this.setBatchRunId(batchRunId);
}
@Override
public boolean equals(Object obj)
{
ExtendedEqualsBuilder anExtendedEqualsBuilder = new ExtendedEqualsBuilder(this, obj);
if (! anExtendedEqualsBuilder.isEquals())
return false;
ProcessRun aProcessRun = (ProcessRun) obj;
return anExtendedEqualsBuilder
.append(this.id, aProcessRun.id)
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder()
.append(this.id)
.toHashCode();
}
@Override
public int compareTo(ProcessRun aProcessRun)
{
return new CompareToBuilder()
.append(this.id, aProcessRun.id)
.toComparison();
}
@Override
public String toString()
{
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", this.id)
.append("processTypeCode", this.processTypeCode)
.append("batchRunId", this.batchRunId)
.append("projectId", this.projectId)
.append("status", this.status)
.append("scheduleChangesMade", this.scheduleChangesMade)
.append("rowsProcessed", this.rowsProcessed)
.append("user", this.user)
.append("startTime", this.startTime)
.append("endTime", this.endTime)
.toString();
}
public Long getId()
{
return this.id;
}
public void setId(Long id)
{
this.id = id;
}
public String getProcessTypeCode()
{
return this.processTypeCode;
}
public void setProcessTypeCode(String processTypeCode)
{
this.processTypeCode = processTypeCode;
}
public ProcessType getProcessType()
{
return this.processType;
}
public void setProcessType(ProcessType processType)
{
if (processType != null)
{
this.processType = processType;
this.processTypeCode = processType.getCode();
}
}
public Long getBatchRunId()
{
return this.batchRunId;
}
public void setBatchRunId(Long batchRunId)
{
this.batchRunId = batchRunId;
}
public Long getProjectId()
{
return this.projectId;
}
public void setProjectId(Long projectId)
{
this.projectId = projectId;
}
public UsaceProject getProject()
{
return this.project;
}
public void setProject(UsaceProject project)
{
if (project != null)
{
this.project = project;
this.projectId = project.getId();
}
}
public int getRowsProcessed()
{
return this.rowsProcessed;
}
public void setRowsProcessed(int rowsProcessed)
{
this.rowsProcessed = rowsProcessed;
}
public String getUser()
{
return this.user;
}
public void setUser(String user)
{
this.user = user;
}
public Date getEndTime()
{
return this.endTime;
}
public void setEndTime(Date endTime)
{
this.endTime = endTime;
}
public Date getStartTime()
{
return this.startTime;
}
public void setStartTime(Date startTime)
{
this.startTime = startTime;
}
public ProcessRunStatus getStatus()
{
return this.status;
}
public void setStatus(ProcessRunStatus status)
{
this.status = status;
}
public boolean isScheduleChangesMade()
{
return this.scheduleChangesMade;
}
public void setScheduleChangesMade(boolean scheduleChangesMade)
{
this.scheduleChangesMade = scheduleChangesMade;
}
public List<ProcessRunLog> getProcessRunLogs()
{
return this.processRunLogs;
}
public void setProcessRunLogs(List<ProcessRunLog> processRunLogs)
{
this.processRunLogs = processRunLogs;
}
public void add(ProcessRunLog aProcessRunLog)
{
this.processRunLogs =
JpaUtils.initialize(this.processRunLogs); // force init/load
this.processRunLogs.add(aProcessRunLog);
}
}
package mil.army.usace.p2.entity;
import mil.army.usace.p2.constants.LogLevel;
import mil.army.usace.p2.constants.RecordSource;
import mil.army.usace.p2.util.ExtendedEqualsBuilder;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
/**
* @version $Revision: 1270 $
* @author $Author: u4iesabm $
* Last Modified: $Date: 2011-07-28 08:55:14 -0500 (Thu, 28 Jul 2011) $
*/
@Entity
@Table(name="PROCESS_RUN_LOG", schema="CILSTAGE")
@SequenceGenerator(name="PROCESS_RUN_LOG_GEN", sequenceName="LOG_ENTRY_ID_SEQ", allocationSize=1)
public class ProcessRunLog
implements Serializable, Comparable<ProcessRunLog>
{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "LOG_ENTRY_ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PROCESS_RUN_LOG_GEN")
private Long id;
@Column(name = "TABLE_NAME")
@Enumerated(EnumType.STRING)
private RecordSource recordSource;
@Column(name = "FK_ID1")
private Long fkId1;
@Column(name = "FK_ID2")
private Long fkId2;
@Column(name = "LOG_LEVEL_TYPE_ID")
@Enumerated(EnumType.ORDINAL)
private LogLevel level;
@Column(name = "LOG_NOTE")
private String note;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "LOG_TIME")
private Date time;
@Column(name="PROCESS_RUN_ID")
private Long processRunId;
// bi-directional many-to-one association to ProcessRun
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="PROCESS_RUN_ID", insertable=false, updatable=false)
private ProcessRun processRun;
public ProcessRunLog()
{
super();
}
public ProcessRunLog(LogLevel aLogLevel,
ProcessRun aProcessRun,
String note)
{
this();
this.level = aLogLevel;
this.note = note;
this.time = new Timestamp(System.currentTimeMillis()); // current timestamp
this.setProcessRun(aProcessRun);
}
public ProcessRunLog(LogLevel aLogLevel,
ProcessRun aProcessRun,
RecordSource aRecordSource,
Long fkId1,
Long fkId2,
String note)
{
this(aLogLevel, aProcessRun, note);
this.recordSource = aRecordSource;
this.fkId1 = fkId1;
this.fkId2 = fkId2;
}
@Override
public boolean equals(Object obj)
{
ExtendedEqualsBuilder anExtendedEqualsBuilder = new ExtendedEqualsBuilder(this, obj);
if (! anExtendedEqualsBuilder.isEquals())
return false;
ProcessRunLog aProcessRunLog = (ProcessRunLog) obj;
return anExtendedEqualsBuilder
.append(this.time, aProcessRunLog.time)
.append(this.processRunId, aProcessRunLog.processRunId)
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder()
.append(this.time)
.append(this.processRunId)
.toHashCode();
}
public int compareTo(ProcessRunLog aProcessRunLog)
{
return new CompareToBuilder()
.append(this.time, aProcessRunLog.time)
.append(this.processRunId, aProcessRunLog.processRunId)
.toComparison();
}
@Override
public String toString()
{
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", this.id)
.append("time", this.time)
.append("level", this.level)
.append("processRunId", this.processRunId)
.append("recordSource", this.recordSource)
.append("fkId1", this.fkId1)
.append("fkId2", this.fkId2)
.append("note", this.note)
.toString();
}
public Long getId()
{
return this.id;
}
public void setId(Long recordId)
{
this.id = recordId;
}
public RecordSource getRecordSource()
{
return this.recordSource;
}
public void setRecordSource(RecordSource recordSource)
{
this.recordSource = recordSource;
}
public Long getFkId1()
{
return this.fkId1;
}
public void setFkId1(Long fkId1)
{
this.fkId1 = fkId1;
}
public Long getFkId2()
{
return this.fkId2;
}
public void setFkId2(Long fkId2)
{
this.fkId2 = fkId2;
}
public LogLevel getLevel()
{
return this.level;
}
public void setLevel(LogLevel logLevel)
{
this.level = logLevel;
}
public String getNote()
{
return this.note;
}
public void setNote(String note)
{
this.note = note;
}
public Date getTime()
{
return this.time;
}
public void setTime(Date time)
{
this.time = time;
}
public Long getProcessRunId()
{
return this.processRunId;
}
public void setProcessRunId(Long processRunId)
{
this.processRunId = processRunId;
}
public ProcessRun getProcessRun()
{
return this.processRun;
}
public void setProcessRun(ProcessRun processRun)
{
if (processRun != null)
{
this.processRun = processRun;
this.processRunId = processRun.getId();
this.processRun.add(this);
}
}
}
|
|
|
Goto Forum:
Current Time: Fri Dec 06 08:54:06 GMT 2024
Powered by FUDForum. Page generated in 0.03586 seconds
|