Transacción JPA no comprometida con DB

I'm working on a small Spring-Hibernate-Mysql test project and for some reason I my transactions are not getting committed to the DB.

In my application-context I got:

<!-- JTA -->

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

</bean>

<tx:annotation-driven transaction-manager="txManager" />

<!-- JPA -->

<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/myPU" />

<!-- In order to enable EntityManager injection -->
<bean
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
    <property name="persistenceUnits">
        <map>
            <entry key="myPU" value="persistence/myPU" />
        </map>
    </property>
</bean>

Mi persistence.xml:

<persistence-unit name="myPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/mysqlResource</jta-data-source>
    <properties>
        <property name="hibernate.connection.shutdown" value="true" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"></property>
        <property name="hibernate.show_sql" value="true" />
    </properties>
</persistence-unit>

I created a simple table called 'persons' in my db:

CREATE TABLE persons(
id VARCHAR(255) PRIMARY KEY,
version int, 
full_name VARCHAR(255),
person_id VARCHAR(255),
email VARCHAR(255));

Created entity a corresponding entity and Dao:

@Entity
@Table(name = "persons")
public class Person implements Serializable {

private static final long serialVersionUID = 4349832844316517922L;

/*--- Members ---*/

/**
 * Hibernate genetared UUID
 */
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;

@Version
private int version;

@Column(name = "full_name")
private String fullName;

@Column(name = "person_id")
private String personId;

@Column(name = "email")
private String eMail;

/*--- Constructor ---*/

public Person() {
}

/*--- Overridden Methods ---*/

@Override
public boolean equals(Object obj) {

    if ((obj == null) || !(obj instanceof Person)) {
        return false;
    }

    // reference comparison
    if (obj == this) {
        return true;
    }

    final Person other = (Person) obj;

    return new EqualsBuilder().append(getPersonId(), other.getPersonId())
            .append(geteMail(), other.geteMail())
            .append(getFullName(), other.getFullName()).isEquals();
}

/**
 * The unique hash code based on the clients' id and citizenship
 * 
 * {@inheritDoc}
 */
@Override
public int hashCode() {

    return new HashCodeBuilder().append(geteMail()).append(this.geteMail())
            .append(this.getFullName()).toHashCode();
}

/*--- Getters & Setters ---*/

public String getId() {
    return id;
}

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

public int getVersion() {
    return version;
}

public void setVersion(int version) {
    this.version = version;
}

public String getFullName() {
    return fullName;
}

public void setFullName(String fullName) {
    this.fullName = fullName;
}

public String getPersonId() {
    return personId;
}

public void setPersonId(String personId) {
    this.personId = personId;
}

public String geteMail() {
    return eMail;
}

public void seteMail(String eMail) {
    this.eMail = eMail;
}

}

dao:

@Repository
public class PersonJpaDao extends BasicJpaDao<Person> implements IPersonDao {

public PersonJpaDao() {
    super(Person.class);
}

}

here is BasicJpaDao:

public class BasicJpaDao<T> implements IBasicDao<T> {

/* --- Members --- */

/** The JPA utility to work with the persistence layer. */
@PersistenceContext
protected EntityManager entityManager;

/** The type of the entity to which this DAO offers access. */
protected Class<T> entityClass;

/* --- Constructors --- */

/**
 * Default constructor.
 * 
 * @param entityClass
 *            The type of the entity to which this DAO offers access.
 */
public BasicJpaDao(Class<T> entityClass) {
    super();
    this.entityClass = entityClass;
}

/* --- Public methods --- */

/**
 * {@inheritDoc}
 */
@Override
public void create(T entity) {
    getEntityManager().persist(entity);
}

/**
 * {@inheritDoc}
 */
@Override
public T read(Object primaryKey) {
    return getEntityManager().find(getEntityClass(), primaryKey);
}

/**
 * {@inheritDoc}
 */
@Override
public T update(T entity) {
    return getEntityManager().merge(entity);
}

/**
 * {@inheritDoc}
 */
@Override
public void delete(T entity) {
    getEntityManager().remove(entity);
}

/**
 * {@inheritDoc}
 */
@Override
public void flush() {
    getEntityManager().flush();
}

/* --- Getters/Setters --- */

/**
 * @return The JPA utility to work with the persistence layer.
 */
public EntityManager getEntityManager() {
    return this.entityManager;
}

/**
 * @param entityManager
 *            The JPA utility to work with the persistence layer.
 */
public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}

/**
 * @return The type of the entity to which this DAO offers access.
 */
public Class<T> getEntityClass() {
    return entityClass;
}

/**
 * @param entityClass
 *            The type of the entity to which this DAO offers access.
 */
public void setEntityClass(Class<T> entityClass) {
    this.entityClass = entityClass;
}

Soo.. basically it works, but nothing gets committed, I mean, if I run

@Transactional(propagation = Propagation.REQUIRED)
private void crearePerson() {
    Person p1 = myDao.read("12345");
    p1.setFullName("kiko too");
    myDao.update(p1);
}

I can see (in debug) that p1 gets back from the DB but the update never takes place. The only close thing I could find was this:

JPA - transacciones no comprometidas

And I tried adding

<property name="hibernate.connection.shutdown" value="true" />

to my persistence.xml following this thread but it didn't help. I also added a property to my connection pool (in my application server gui) called connection.shutdown with the value of true but it didn't help either.

Actualizar: Since I'm using JTA I figured my transaction manager is wrongly configured. While I was using org.springframework.orm.jpa.JpaTransactionManager I should have used org.springframework.transaction.jta.JtaTransactionManager. So I have changed my application context and now I have:

<bean id="txManager"
    class="org.springframework.transaction.jta.JtaTransactionManager" />

<tx:annotation-driven transaction-manager="txManager" />

Unfortunately, I'm still experiencing the same issue :( In my console I can see the hibernate query as follows ()I've changed some of my original entity fields, but it doesn't really matters):

INFO: Hibernate: select user0_.id as id0_0_, user0_.email as email0_0_, user0_.full_name as full3_0_0_, user0_.password as password0_0_, user0_.update_by_email as update5_0_0_, user0_.user_name as user6_0_0_, user0_.version as version0_0_ from users user0_ where user0_.id=?

¿Alguna idea?

Gracias de antemano, Yogi

preguntado el 22 de mayo de 12 a las 19:05

3 Respuestas

The reason it is probably not working is because you are using @Transactional on a private method. @Transactional will have no effect on a non-public method, because the proxy generator ignores them. From the Documentación de primavera:

Visibilidad del método y @Transactional

Al usar proxies, debe aplicar la anotación @Transactional solo a los métodos con visibilidad pública. Si anota métodos protegidos, privados o visibles en el paquete con la anotación @Transactional, no se genera ningún error, pero el método anotado no muestra la configuración transaccional configurada. Considere el uso de AspectJ (ver más abajo) si necesita anotar métodos no públicos.

contestado el 23 de mayo de 12 a las 01:05

Thanks! But changing the method visibility did not help,Moreover, I thought that since my class (the one that contains the crearePerson method) implements an interfate that does not define a crearePerson method, spring will not be able to use the transactional annotation. So, I tried two different approaches, the first adding the method declaration to the interface - still not working. Second, adding cglig and declaring <aop:aspectj-autoproxy proxy-target-class="true"/> in order for spring to ignore the interface. This didn't help as well. I'm lost here.. - porhas

I was having a similar issue, and for me the fix came from the following:

In PersistenceXML:

<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup">

Spring file:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="nameOfUnitInPersistenceXml" />
</bean>

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManagerName" value="java:/TransactionManager" />
</bean>

Java class (name the persistence context)

private EntityManager em;

@PersistenceContext(name="nameOfUnitInPersistenceXml")
public void setEntityManager(EntityManager em) {
    this.em = em;
}

Respondido el 11 de diciembre de 15 a las 17:12

add "@Transactional" to your create() method.

edit: it's better practice to put @Transactional at the service layer and not dao layer just fyi

contestado el 22 de mayo de 12 a las 19:05

Hi, thanks for that. I do run in a transaction, just edited my question. still can't see my table getting updated after running the code, and I sure agree - the @Transactional annotation should usually take place at the business-logic layer - porhas

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.