EBean does not update! he is trying to do insertions and crash

I have a simple user model:

package models; import java.util.*; import javax.persistence.*; import play.db.ebean.*; @Entity public class User extends Model { @Id public Long id; public String userName; public String email; public String workPlace; public Date birthDate; @Version public Long version; public static Finder<Long,User> find = new Finder<Long,User>( Long.class, User.class ); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getWorkPlace() { return workPlace; } public void setWorkPlace(String workPlace) { this.workPlace = workPlace; } public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } } 

MySql already has an entry with id = 1, version = 1

i create a new model with the same version id +, change the username

then I will try the save () method

failure:

 javax.persistence.PersistenceException: ERROR executing DML bindLog[] error[Duplicate entry '1' for key 'PRIMARY'] at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:116) ~[ebean.jar:na] at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.java:76) ~[ebean.jar:na] at com.avaje.ebeaninternal.server.persist.DefaultPersistExecute.executeInsertBean(DefaultPersistExecute.java:91) ~[ebean.jar:na] at com.avaje.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:527) ~[ebean.jar:na] at com.avaje.ebeaninternal.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:557) ~[ebean.jar:na] at com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:404) ~[ebean.jar:na] Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY' at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [na:1.7.0_05] at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) [na:1.7.0_05] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) [na:1.7.0_05] at java.lang.reflect.Constructor.newInstance(Unknown Source) [na:1.7.0_05] at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) ~[mysql-connector-java-5.1.18.jar:na] at com.mysql.jdbc.Util.getInstance(Util.java:386) ~[mysql-connector-java-5.1.18.jar:na] 

what am I doing wrong? Insert a new record. therefore, it looks like an error in ebean, where it does not recognize that it should do the update. or is it some kind of configuration that I forgot somewhere?

thanks

+4
source share
2 answers

I think this is due to the improvement in bytecode that both the game and ebean do.

I had strange problems, similar to yours, when I mixed public fields with getters and setters. Sometimes values ​​were not set when using the field directly:

 user.id = 1L; // didn't work user.setId(1L); // ok 

It felt like a potential death trap, so I decided to be consistent and use only public fields. The downside was that ebeans autocomplete stopped working, but on the other hand, it made me configure my queries using ebean.

This great Timo post has shed light on how ebean and play do their bytecode magic.

+8
source

If you have a self-created object and save () is called, Ebean does the insert statement as SQL. If you call update (), it will do the update statement as SQL.

There is no logic in Ebean that would make an additional query to the database only to check if the database has a row with the same primary key, and if so, then use the update statement, in other words, the insert statement. This would be simply inefficient behavior, for you will usually know which one to do, and therefore do not want to execute two SQL statements, only one. In this case, you really need to tell him to use the update, and not try to insert the row again.

 // Create user. User user1 = new User(); user1.setId(1L); user1.setVersion(1L); user1.setUserName("foo"); user1.setWorkPlace("bar"); user1.setEmail(" foo@bar.com "); user1.save(); // Change details later and update DB. User user2 = new User(); user2.setId(1L); user2.setVersion(1L); user2.setUserName("scooby_doo"); user2.save(); // This will crash. user2.update(); // This will work. 

However, if you select an object from the database, then calling save () on it will use the update statement in SQL, because Ebean knows that its state is not new, but not existing.

 // Find user (and let Ebean know its state as an existing row). User user3 = User.find.byId(1L); // Now you can change details and save without issues. user3.setEmail(" foo@gmail.com "); user3.setVersion(2L); user3.save(); // This will work. 

See the Ebean Documentation .

+5
source

Source: https://habr.com/ru/post/1214892/


All Articles