mvc localcontainerentitymanagerfactorybean insertar example entitymanagerfactory datos con java hibernate spring jpa persistence

java - localcontainerentitymanagerfactorybean - spring jpa configuration



Spring, Hibernate y JPA: las llamadas persisten en entitymanager no parecen comprometerse con la base de datos (4)

Intento configurar Spring utilizando Hibernate y JPA, pero cuando intento persistir en un objeto, no parece que se agregue nada a la base de datos.

Estoy usando lo siguiente:

<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" />

Y en AccountManager, estoy haciendo:

@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; } }

De donde viene ac:

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;

¿Hay alguien que pueda señalar lo que estoy haciendo mal? La llamada persistente regresa sin arrojar excepciones. Si luego hago em.contains(ac) , esto devuelve true.

En caso de que alguien lo necesite, así es como se define Account:

@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; } }


Gracias a las respuestas de Eric y Juan, pude darme cuenta de que la transacción no estaba comprometida.

¡Agregar @Transactional al método storeAccount hizo el truco!


No necesita llamar explícitamente al método de persistencia. La operación de fusión escribiría los cambios en el DB al confirmar.


Probablemente mantendrá activa la transacción y no llamará a "commit" hasta que no se ejecuten otros métodos que funcionen con el fin de la transacción activa (todos "votos" para commit y ninguno para rollback).

Si está seguro de que la entidad que va a persistir está bien, probablemente pueda hacer esto:

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

y administrar la persistencia de su entidad agregando:

@Resource private SessionContext sessionContext; public Account storeAccount(Account ac) { sessionContext.getUserTransaction().begin(); ac = em.merge(ac); em.persist(ac); sessionContext.getUserTransaction().commit(); return ac; }


De hecho, me encontré con otra forma en que esto puede suceder.

En un EntityManager inyectado, no se producirán actualizaciones si tiene persistence.xml especificado así:

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

Debe eliminar el atributo de tipo de transacción y simplemente usar el valor predeterminado que es JTA.