Enhancement 250 : javax.persistence.OptimisticLockException: Data has changed. updated [0] rows
Priority 
High
Reported Version 
 
Logged By 
wstone
Status 
New
Fixed Version 
 
Assigned To 
 
Product 
Ebean - core
Duplicate Of 
 
Created 
17/03/2010
Updated 
17/03/2010
Type 
Enhancement
 
Attachments 
No attachments

Oracle10g DB Column Type is Date,When I use this Date Type column as @Version,when i update entity bean ,will throw Exception:
javax.persistence.OptimisticLockException: Data has changed. updated [0] rows
at com.avaje.ebean.server.core.PersistRequestBean.checkRowCount(PersistRequestBean.java:450)
at com.avaje.ebean.server.persist.dml.UpdateHandler.execute(UpdateHandler.java:88)
at com.avaje.ebean.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:104)
at com.avaje.ebean.server.persist.dml.DmlBeanPersister.update(DmlBeanPersister.java:84)
at com.avaje.ebean.server.persist.DefaultPersistExecute.executeUpdateBean(DefaultPersistExecute.java:121)
at com.avaje.ebean.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:390)
at com.avaje.ebean.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:416)
at com.avaje.ebean.server.persist.DefaultPersister.update(DefaultPersister.java:383)
at com.avaje.ebean.server.persist.DefaultPersister.saveEnhanced(DefaultPersister.java:303)
at com.avaje.ebean.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:275)
at com.avaje.ebean.server.persist.DefaultPersister.save(DefaultPersister.java:259)
at com.avaje.ebean.server.core.DefaultServer.save(DefaultServer.java:1448)
at com.avaje.ebean.server.core.DefaultServer.save(DefaultServer.java:1438)

Entity Pojo Class:
@Version
private java.util.Date vtime;

 
Rob 17 Mar 03:21
java.util.Date does not have nanos precision ...

If you chance to java.sql.Timestamp does it work then?

Rob 17 Mar 09:42
Also just to confirm...

You have stated the Oracle DATE type is used (rather than TIMESTAMP) so just confirming that you want/need to use Oracle DATE.

Ta.

Rob 18 Mar 00:27
My tests ...

ok, I tested with Oracle DATE and Oracle TIMESTAMP. Note that Oracle DATE only has precision to seconds ... which is less than the precision of java.util.Date or java.sql.Timestamp.

So yes, the optimistic concurrency checking is failing against Oracle DATE because it only has 1 sec precision.

Q: Do you really want to use Oracle DATE for @Version?

wstone 18 Mar 03:18
OpenJPA and toplink do not throw this exception

I used to use a JPA, and when I found ebean, the lifted ebean There are many advantages and features, but I found that there are many places ebean incompatible jpa specifications, I would like to still have to ebean basic layer is compatible with JPA specification!

wstone 18 Mar 09:33
Follow-up notes

Java.util.Date an entity if there are types of fields, but no @Version annotation, JPA is work OK, but EBean'll throw an error

Rob 18 Mar 21:56
Ok but ...

Ok but OpenJPA and toplink might also be silently truncating the precision of your java.util.Date?

Have you looked at the actual precision that is stored in the DB?

Is it different when using an Oracle DATE versus and Oracle TIMESTAMP? Specifically are you still getting your millis precision of java.util.Date or is it truncated?

I'm not sure we should be encouraging people to use what I'd suggest is the incorrect DB type to store "DateTime" in Oracle. So although Ebean fails ... the fix might be worse. At this stage you still have not told me if you have to use an Oracle DATE or not.

Rob 18 Mar 21:58
I forgot to ask the obvious...

I forgot to ask the obvious question.

Are you actually storing time in your java.util.Date? ... or are you actually just using it as a "Date only" ala java.sql.Date field?

wstone 19 Mar 09:47
Details.....

I was using the tool to generate entity Object from the database table objects, the database the date column type is Date, the generated JPA entity object date type is java.util.Date, in TopLink, OpenJPA will not run out of an exception,The following is the source code:

package wjw.ebean.entity;

import com.avaje.ebean.annotation.Sql;
import com.avaje.ebean.annotation.SqlSelect;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

@Entity
@Table(name = "LOG4J_EDI")
@NamedQueries(
{
@NamedQuery(name = "Log4jEdi.findAll", query = "SELECT l FROM Log4jEdi l"),
@NamedQuery(name = "Log4jEdi.findByLogId", query = "SELECT l FROM Log4jEdi l WHERE l.logId = :logId"),
@NamedQuery(name = "Log4jEdi.findByLogDate", query = "SELECT l FROM Log4jEdi l WHERE l.logDate = :logDate"),
@NamedQuery(name = "Log4jEdi.findByLogLevel", query = "SELECT l FROM Log4jEdi l WHERE l.logLevel = :logLevel"),
@NamedQuery(name = "Log4jEdi.findByLogThread", query = "SELECT l FROM Log4jEdi l WHERE l.logThread = :logThread"),
@NamedQuery(name = "Log4jEdi.findByLogClassname", query = "SELECT l FROM Log4jEdi l WHERE l.logClassname = :logClassname")
})

@Sql(select = {
@SqlSelect(
name = "Log4jEdi.findByLogLevel2",
query = "select LOG_ID,LOG_DATE,LOG_LEVEL,LOG_THREAD,LOG_CLASSNAME,LOG_MSG from LOG4J_EDI",
where = "LOG_LEVEL = :logLevel")
})
public class Log4jEdi implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "LOG_ID")
private BigDecimal logId;

@Basic(optional = false)
@Column(name = "LOG_DATE", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date logDate;

@Column(name = "LOG_LEVEL")
private String logLevel;

@Column(name = "LOG_THREAD")
private String logThread;

@Column(name = "LOG_CLASSNAME")
private String logClassname;

@Basic(optional = false)
@Lob
@Column(name = "LOG_MSG")
private String logMsg;

public Log4jEdi() {
}

public Log4jEdi(BigDecimal logId) {
this.logId = logId;
}

public Log4jEdi(BigDecimal logId, Date logDate, String logMsg) {
this.logId = logId;
this.logDate = logDate;
this.logMsg = logMsg;
}

public BigDecimal getLogId() {
return logId;
}

public void setLogId(BigDecimal logId) {
this.logId = logId;
}

public Date getLogDate() {
return logDate;
}

public void setLogDate(Date logDate) {
this.logDate = logDate;
}

public String getLogLevel() {
return logLevel;
}

public void setLogLevel(String logLevel) {
this.logLevel = logLevel;
}

public String getLogThread() {
return logThread;
}

public void setLogThread(String logThread) {
this.logThread = logThread;
}

public String getLogClassname() {
return logClassname;
}

public void setLogClassname(String logClassname) {
this.logClassname = logClassname;
}

public String getLogMsg() {
return logMsg;
}

public void setLogMsg(String logMsg) {
this.logMsg = logMsg;
}

@Override
public int hashCode() {
int hash = 0;
hash += (logId != null ? logId.hashCode() : 0);
return hash;
}

@Override
public boolean equals(Object object) {
if (!(object instanceof Log4jEdi)) {
return false;
}
Log4jEdi other = (Log4jEdi) object;
if ((this.logId == null && other.logId != null) || (this.logId != null && !this.logId.equals(other.logId))) {
return false;
}
return true;
}

@Override
public String toString() {
return "\nLog4jEdi{" +
"logId=" + logId +
", logDate=" + logDate +
", logLevel='" + logLevel + '\'' +
", logThread='" + logThread + '\'' +
", logClassname='" + logClassname + '\'' +
", logMsg='" + logMsg + '\'' +
"}";
}

}

Rob 20 Mar 08:33
Can you ...

Can you answer the questions I asked previously.
Thanks.

wstone 21 Mar 08:50
OK, I would like to ask about such a table structure, how the entity bean is generated EBean compatible?

I am using a oracle database, table structure is like this:
--
-- LOG4J_EDI (Table)
--
CREATE TABLE LOG4J_EDI
(
LOG_ID NUMBER NOT NULL,
LOG_DATE DATE DEFAULT sysdate NOT NULL,
LOG_LEVEL VARCHAR2(10 BYTE),
LOG_THREAD VARCHAR2(100 BYTE),
LOG_CLASSNAME VARCHAR2(200 BYTE),
LOG_MSG CLOB NOT NULL,
CONSTRAINT LOG4J_EDI_PK
PRIMARY KEY
(LOG_ID)
)
ENABLE ROW MOVEMENT;


--
-- TG_LOG4J_EDI (Trigger)
--
CREATE OR REPLACE TRIGGER "TG_LOG4J_EDI"
BEFORE INSERT ON "TRUEEDI"."LOG4J_EDI" FOR EACH ROW
DECLARE
tmpvar NUMBER;
/******************************************************************************
???????????tTRUEEDI.LOG4J_EDI.log_id?????????????????,?????tTRUEEDI.LOG4J_EDI.log_id??????????
******************************************************************************/
BEGIN
SELECT seq_db.NEXTVAL
INTO tmpvar
FROM DUAL;

:NEW.log_id := tmpvar;
END;
/

Rob 21 Mar 10:45
Can you answer my questions first?

1. Are you actually storing time in your java.util.Date?
2. Can you change your Oracle DATE to an Oracle TIMESTAMP (is it an option) ?
3. Do you care about the lose of precsion (you are losing the sub second precision) ?

Ta.

wstone 22 Mar 01:11
To answer your question

1. I'm sure the use of java.util.Date
2. I can not change the Oracle DATE to an Oracle TIMESTAMP
3. I just need to precise to the second

Rob 31 Mar 03:49
Ok,

Ok, so at this stage I believe you want an Enhancement so the the java timestamp is truncated to seconds (so that it can be used for optimistic concurrency checking).

BUT... you only want this when using the old Oracle DATE and *NOT* when using Oracle TIMESTAMP so you need some way of defining which properties this applies to.

Do you have any suggestions for when this truncation should be applied? ie. Only on Oracle DATE columns but not on Oracle TIMESTAMP columns - how should this be defined or determined?

wstone 31 Mar 16:54
I decided to use DATE type

I decided to use DATE type, instead of TIMESTAMP. Because many Oracle database design based on system date DATE type column is used, I would like to use Ebean framework

Rob 06 Apr 09:59
Hmmm...

You still need to try and answer my question or explain why it is not relevant.

The question was:

Do you have any suggestions for when this truncation should be applied? ie. Only on Oracle DATE columns but not on Oracle TIMESTAMP columns - how should this be defined or determined?

Can you clarify if you use Oracle TIMESTAMP at all?

Thanks.

wstone 06 Apr 10:21
Because a lot of table-based Oracle database design, using only the DATE column, but I do want to use Ebean as O/R mapping!

Because a lot of table-based Oracle database design, using only the DATE column, but I do want to use Ebean as O/R mapping!

Rob 06 Apr 20:39
Please ...

I don't think you answered my questions.

Q: Can you clarify if you use Oracle TIMESTAMP at all?

I'm guessing the answer is that you don't use Oracle TIMESTAMP at all but I want to clarify this.

Q: Do you have any suggestions for when this truncation should be applied (when someone is using both Oracle DATE and Oracle TIMESTAMP)?

If you do not have any suggestions please state this but perhaps you have a suggestion for how to resolve this.

thanks

wstone 07 Apr 01:10
The only suggestion is that it can: java.util.Date and java.sql.Timestamp to determine whether to use the DATE, TIMESTAMP

The only suggestion is that it can: java.util.Date and java.sql.Timestamp to determine whether to use the DATE, TIMESTAMP

Another question is: If the definition of the date columns are: DATE, and I do not have permission change to TIMESTAMP, then how to use EBean?

woResponse

Upload a file