2015-10-12 68 views
1

我有一個SQLite數據庫。我使用EclipseLink和JPA使用它。另外我有一個實體類UserJPA EntityManager不會在SQLite數據庫中提交更改

import com.vaadin.server.VaadinService; 
import java.io.Serializable; 
import javax.persistence.*; 

@Entity 
public class User implements Serializable { 

    @Id @GeneratedValue 
    long id;   // Unique identifier of the user in the DB 
    String username; // Unique name used for login 
    String password; // Password used for login 

    public User() { 
    } 

    public User(String username, String password) { 
     this.username = username; 
     this.password = password; 
    } 

    public Long getId() { 
     return id; 
    } 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 
} 

在登記表我創建了一個用戶,然後調用EntityManagerpersist()的變化:

public int createUser(String username, String password, String password_confirmation) { 
     int regStatus = 0; 
     if(checkValidUsername(username)) { 
      if(checkValidPassword(password, password_confirmation)) { 
       EntityManager em = factory.createEntityManager(); 
       try { 
        em.getTransaction().begin(); 
         User user = new User(username, password); 
         em.persist(user); 
        em.getTransaction().commit(); 
       } 
       catch(Exception e) { 
        System.out.println(e.getMessage()); 
        regStatus = 3; 
       } 
       finally { 
        em.close(); 
       } 
      } 
      else regStatus = 2; // Password mismatch 
     } 
     else regStatus = 1;  // User with selected username already present in DB 

     return regStatus; 
    } 

它的工作沒有任何問題。我在USER表中獲得每個新註冊的用戶。但是,當我嘗試更改密碼時,它不起作用。下面是與此相關的程序方法:

// Inside the controller for my settings view - here the user can change various things related to his/her profile 
public void setCurrentUser() { 
    currentUser = UserController.findUserByName((String)VaadinSession.getCurrent().getAttribute("username")); // findUserByName() is a static method 
} 


// Inside the User controller I have multiple methods for common user-related queries; here I use the username that I have retrieved from the VaadinSession's attribute "username" to execute a query and get the User entity (I make sure that a user's name is unique so getting a single result here is not a problem) 
public static User findUserByName(String username) { 
    if(username == null) return null; 
    factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); 
    EntityManager em = factory.createEntityManager(); 
    User user = null; 

    try{ 
     Query q = em.createQuery("SELECT u FROM User u WHERE u.username = :username"); 
     q.setParameter("username", username); 
     user = (User)q.getSingleResult(); 

    } 
    catch(Exception e){ 
     System.err.println(e.getMessage()); 
    } 
    finally { 
     em.close(); 
    } 

    return user; 
} 


// Inside the controller fpr my settings view (where I change the password) 
public int changePassword(String currentPassword, String newPassword, String newPasswordConfirmation) { 
    if(newPassword.isEmpty()) return 1; 
    if(!newPassword.equals(newPasswordConfirmation)) return 2;   // Incorrect confirmation 
    if(!currentPassword.equals(currentUser.getPassword())) return 3; // Given current password doesn't match the one stored in the database for this user 

    int resStatus = 0; 
    EntityManager em = factory.createEntityManager(); 
    try { 
     em.getTransaction().begin(); 
      currentUser.setPassword(newPassword); 
     em.getTransaction().commit(); // NO ERRORS at all... 
    } 
    catch(Exception e) { 
     System.out.println(e.getMessage()); 
     resStatus = 4; // Exception 
    } 
    finally { 
     em.close(); 
    } 

    return resStatus; 
} 

我也使用EntityManager.find(...),這應該從USER表中返回同一行(和它),但結果又是同樣的嘗試 - 交易開始,完成後,實體經理關閉,但對於所謂的更改用戶表USER是相同的。

任何想法?我在另一個項目中使用了相同的例程,但是用於設置其他項目。那裏的數據庫是PostreSQL,我還沒有遇到這樣的問題。在SQLite數據庫中,我沒有收到任何錯誤,但提交失敗了。

+0

確實的EclipseLink提供SQLite的全力支持?我知道它並不習慣,而且我曾經使用DataNucleus,只要我想使用該數據存儲。查看EclipseLink日誌可能會顯示大量 –

+0

當我觸發密碼更改時,我看不到任何事務提交。另外,我在哪裏可以找到有關EclipseLink支持SQLite的一些信息。我試着在這裏和那裏看,但沒有出現。不過我真的懷疑它會支持'persist()'(使用事務!),而不是列中某個值的簡單更改。我認爲這個錯誤是我給出的代碼中的其他地方。只是不知道在哪裏。調試完全沒有幫助,因爲我沒有任何錯誤。 – rbaleksandar

+0

那麼,如果我搜索「Eclipselink支持的數據庫」,我會得到http://wiki.eclipse.org/EclipseLink/FAQ/JPA#What_databases_are_supported.3F –

回答

1

我剛剛開發與休眠等,但它會是相同的,因爲兩者都實現JPA。 如果您啓動一個事務,JPA會記住您在此事務中加載的所有實體,並且如果您更改了某些內容,則會在db中看到更改(提交後)。

但是在您的事務中,JPA不會識別您的實體,因此這些更改不會持續。嘗試在事務中加載實體。像...的內容與方法

em.getTransaction().begin(); 
     em.find(User.class, currentUser.getId()); //Reload the User from db, so it is attached to the session 
     currentUser.setPassword(newPassword); 
    em.getTransaction().commit(); 

更多信息:

+1

由於未管理該實例,刷新將引發異常。它需要合併或閱讀。 – Chris

+0

如果您嘗試更改用戶的密碼在數據庫中不存在,那將會很奇怪:P但是您是對的,如果對象不在數據庫中,則刷新將會成爲問題。如果在創建對象後刷新對象,也可能會出現問題。所以db中不會有行。在這種情況下,你必須使用沖水。對於這種情況,刷新或合併就可以了。或者,您可以在修改對象後保存對象,這將是執行相同操作的第三種方法。 – Eruvanos

+0

對不起,我並不是說刷新是一個問題,如果行不在那裏,我的意思是,如果您傳入的實例沒有在當前上下文中進行管理,那麼這是一個問題。刷新僅在由此EntityManager管理的實例上有效,因此從其他em讀入並傳遞的實體將導致異常。由於他們在閱讀當前用戶之後關閉了上下文,並獲得了另一個更新,因此我建議您的解決方案需要更新以使用查找操作而不是刷新,或者使用合併。 – Chris

相關問題