2008-12-17 14 views
17

J'essaye de configurer Spring en utilisant Hibernate et JPA, mais en essayant de persister un objet, rien ne semble être ajouté à la base de données.Spring, Hibernate & JPA: L'appel persistant sur entitymanager ne semble pas s'engager dans la base de données

Am en utilisant les éléments suivants:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
    <property name="url" value="${jdbc.url}"/> 
    <property name="driverClassName" value="${jdbc.driverClassName}"/> 
    <property name="username" value="${jdbc.username}"/> 
    <property name="password" value="${jdbc.password}"/> 
</bean> 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="persistenceUnitName" value="BankingWeb" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="generateDdl" value="true" /> 
      <property name="showSql" value="true" /> 
      <property name="databasePlatform" value="${hibernate.dialect}" /> 
     </bean> 
    </property> 
</bean> 

<tx:annotation-driven/> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory" ref="entityManagerFactory"/> 
</bean> 

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> 

<bean name="accountManager" class="ssel.banking.dao.jpa.AccountManager" /> 
<bean name="userManager" class="ssel.banking.dao.jpa.UserManager" /> 

Et AccountManager, je fais:

@Repository 
public class AccountManager implements IAccountManager { 

    @PersistenceContext private EntityManager em; 

    /* -- 8< -- Query methods omitted -- 8< -- */ 

    public Account storeAccount(Account ac) { 
    ac = em.merge(ac); 
     em.persist(ac); 
     return ac; 
    } 
} 

Où ca vient de:

Account ac = new Account(); 
    ac.setId(mostRecent.getId()+1); 
    ac.setUser(user); 
    ac.setName(accName); 
    ac.setDate(new Date()); 
    ac.setValue(0); 
    ac = accountManager.storeAccount(ac); 
    return ac; 

Est-ce qu'il ya quelqu'un qui peut pointer dehors ce que je fais mal? L'appel persist retourne sans lancer d'exception. Si par la suite je fais em.contains(ac), cela retourne vrai.

Dans le cas où quelqu'un avait besoin, voici comment compte est défini:

@SuppressWarnings("serial") 
@Entity 
@NamedQueries({ 
     @NamedQuery(name = "Account.AllAccounts", query = "SELECT a FROM Account a"), 
     @NamedQuery(name = "Account.Accounts4User", query = "SELECT a FROM Account a WHERE user=:user"), 
     @NamedQuery(name = "Account.Account4Name", query = "SELECT a FROM Account a WHERE name=:name"), 
     @NamedQuery(name = "Account.MaxId", query = "SELECT MAX(a.id) FROM Account a"), 
     @NamedQuery(name = "Account.Account4Id", query = "SELECT a FROM Account a WHERE id=:id"), 
    }) 
public class Account extends AbstractNamedDomain { 
    @Temporal(TemporalType.DATE) 
    @Column(name = "xdate") 
    private Date date; 

    private double value; 

    @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE}) 
    @JoinColumn(name="userid") 
    private User user; 

    public User getUser() { 
     return user; 
    } 

    public void setUser(User user) { 
     this.user = user; 
    } 

    @OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER) 
    @OrderBy("date") 
    private List<AccountActivity> accountActivity = new ArrayList<AccountActivity>(); 

    public List<AccountActivity> getAccountActivity() { 
     return accountActivity; 
    } 

    public void setAccountActivity(List<AccountActivity> accountActivity) { 
     this.accountActivity = accountActivity; 
    } 

    public Date getDate() { 
     return date; 
    } 

    public void setDate(Date date) { 
     this.date = date; 
    } 

    public double getValue() { 
     return value; 
    } 

    public void setValue(double value) { 
     this.value = value; 
    } 

    public void addAccountActivity(AccountActivity activity) { 
     // Make sure ordering is maintained, JPA only does this on loading 
     int i = 0; 
     while (i < getAccountActivity().size()) { 
      if (getAccountActivity().get(i).getDate().compareTo(activity.getDate()) <= 0) 
       break; 
      i++; 
     } 
     getAccountActivity().add(i, activity); 
    } 
} 

@MappedSuperclass public abstract class AbstractNamedDomain extends AbstractDomain { 

    private String name; 

    public AbstractNamedDomain() { 

    } 

    public AbstractNamedDomain(String name) { 

     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

@MappedSuperclass public abstract class AbstractDomain implements Serializable { 

    @Id @GeneratedValue 
    private long id = NEW_ID; 

    public static long NEW_ID = -1; 

    public long getId() { 
     return id; 
    } 

    public void setId(long id) { 
     this.id = id; 
    } 

    public boolean isNew() { 

     return id==NEW_ID; 
    } 
} 
+0

hey ruben, je fais quelque chose de similaire, mais j'ai un fichier persistence.xml, en avez-vous un, pourquoi ou pourquoi pas? merci – bmw0128

Répondre

18

Merci à Eric et les réponses de Juan Manuel, j'ai pu comprendre que la transaction n'a pas été commise. Ajouter @Transactional à la méthode storeAccount a fait l'affaire!

+0

Est-ce tout ce que vous avez fait pour résoudre le problème? –

+0

Dans mon cas, j'ai dû ajouter @Transactional au point d'entrée de ma classe. Avant j'ai juste eu @Transactional sur ma méthode qui a fait la persistance. Je ne sais pas si je comprends parfaitement ce qui se passe là-bas. –

+3

Apparemment, @Transactional ne fonctionne que sur les méthodes publiques. –

1

Probablement vous gardez la transaction active et il ne demande pas « commettre » jusqu'à ce que d'autres méthodes en cours d'exécution supportant la fin de transaction active (tous " vote » pour engager et aucun rollback)

Si vous êtes sûr que l'entité que vous allez persister est ok, vous pouvez probablement le faire.

@TransactionManagement(TransactionManagementType.BEAN) 
public class AccountManager implements IAccountManager { ..} 

et gérer votre PERSISTANCE entité ajouter:

@Resource 
private SessionContext sessionContext; 

public Account storeAccount(Account ac) { 
    sessionContext.getUserTransaction().begin(); 
    ac = em.merge(ac); 
    em.persist(ac); 
    sessionContext.getUserTransaction().commit(); 
    return ac; 
} 
+0

@TransactionManagement est EJB. –

1

Vous n'avez pas explicitement besoin d'appeler la méthode persist. L'opération de fusion écrit les modifications dans la base de données lors de la validation.

4

Je suis effectivement tombé sur une autre façon que cela peut arriver.

Dans un EntityManager injecté, aucune mise à jour ne se produira jamais si vous avez persistence.xml spécifié comme ceci:

<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">

Vous devez supprimer l'attribut type de transaction et il suffit d'utiliser la valeur par défaut qui est JTA .

+1

Après 6 heures de frapper ma tête, trouvé ceci. – panther