2012-07-28 22 views
4

我有一個簡單的用戶模型是這樣的:EBean沒有更新!它試圖執行插入和失敗

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已經有id爲1,版本記錄= 1

我創建一個新模式相同的id +版本,更改用戶名

然後我嘗試save()方法

它失敗:

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] 

我做錯了什麼?插入新記錄的作品。所以它在我看來就像一些ebean bug,它不承認它應該進行更新。或者它是一些配置,我忘了什麼地方?

感謝

+0

請顯示您調用'save()'方法的代碼。 – 2012-07-28 10:36:00

+0

爲什麼不調用'update()' – adis 2012-07-30 08:21:08

回答

8

我認爲這是相關的字節碼增強,無論播放和ebean執行。

當我將公有字段與getter和setter混合使用時,我有類似於你的奇怪問題。有時在直接使用字段時沒有設置數值:

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

這感覺就像一個潛在的死亡陷阱,所以我決定保持一致,只使用公共領域。缺點是ebeans自動提取停止工作,但另一方面卻迫使我使用ebean提取來調整查詢。

This excellent post Timo對ebean和play如何執行他們的字節碼魔術做了一些說明。

+0

有一個類似的問題,試圖在Eclipse中運行EBean測試,它會抱怨,因爲該類沒有增強(說沒有setter/getters)。所以我添加了它們,但添加它們會導致一些EBean測試在從播放命令行運行時失敗。你不能在eclipse中運行單元測試。 – 2013-08-01 19:34:43

+0

我剛剛有一個非常類似的問題,很奇怪的行爲。這就是我喜歡Spring JdbcTemplate的原因。真的幫助 – 2014-02-08 16:54:33

+0

喬爾S,你的解決方案爲我工作。 – 2014-10-25 01:35:01

5

如果您有自己創建的對象,並且調用save(),那麼Ebean將插入語句作爲SQL。如果您致電更新()它將更新語句爲SQL。

Ebean本身沒有任何邏輯可以爲數據庫創建額外的查詢來檢查數據庫中是否有類似主鍵的行,如果是,則使用更新語句,否則使用insert語句。這隻會是低效率的行爲,因爲通常你會知道要製作哪一個,因此不想執行兩條SQL語句,只有一條。在這種情況下,您實際上必須告訴它使用更新,而不是嘗試再次插入行。

// Create user. 
User user1 = new User(); 
user1.setId(1L); 
user1.setVersion(1L); 
user1.setUserName("foo"); 
user1.setWorkPlace("bar"); 
user1.setEmail("[email protected]"); 
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. 

但是,如果從數據庫獲取對象,然後調用保存()它會在SQL中使用的更新語句,因爲Ebean知道它的狀態是不是新的,而不是現有的。

// 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("[email protected]"); 
user3.setVersion(2L); 
user3.save(); // This will work. 

請參閱Ebean documentation

+0

謝謝!在我看來,'.save()'的行爲是不一致的(例如.save()會更新,下一個會嘗試INSERT),但也許我只是在沒有意識到的情況下手動刪除數據。無論如何,這個解決方案工作正常! 在我的情況下,我能夠測試以查看該項目是否具有「id」屬性集,如果它確實存在,我知道它已經存在,所以我可以調用'.update()',否則我調用'.save()'。這節省了我的數據庫電話。 – 2014-02-19 14:26:37

+0

嗯。像這樣的問題使得EBean很難與Scala/Play一起使用。 – Ashesh 2016-04-20 13:30:06

+0

@Ashesh:所以你寧願Ebean做額外的SQL查詢,以確定它是否應該插入或更新'save()'?那隻會是糟糕的表現。 – t0mppa 2016-04-20 14:31:50