Question

I want to persist a JPA entity to a MySQL database using JTA (container managed transactions) with EclipseLink on a Glassfish 3.1.2 application server. However, this is not working at all. The EclipseLink log shows that SELECT queries are executed correctly and that sequences are also updated. But no INSERT queries are executed after persist() has been called.

EclipseLink logging:

persist() operation called on: my.package.name.MyEntity@d39a7b6.
TX beginTransaction, status=NO_TRANSACTION
TX Internally starting
external transaction has begun internally
Connection acquired from connection pool [default].
Execute query DataModifyQuery(name="SEQUENCE" sql="UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + #PREALLOC_SIZE WHERE SEQ_NAME = #SEQ_NAME")
reconnecting to external connection pool
UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
    bind => [50, SEQ_GEN]|#]
Execute query ValueReadQuery(name="SEQUENCE" sql="SELECT SEQ_COUNT FROM SEQUENCE WHERE SEQ_NAME = #SEQ_NAME")
SELECT SEQ_COUNT FROM SEQUENCE WHERE SEQ_NAME = ?
    bind => [SEQ_GEN]
local sequencing preallocation for SEQ_GEN: objects: 50 , first: 14.501, last: 14.550
Connection released to connection pool [default].
TX commitTransaction, status=STATUS_ACTIVE
TX Internally committing

So I can see the sequence updates in the MySQL database, but the table associated with MyEntity remains empty.

Here is my entity class:

    @Entity
    @Table(name = "my_entity")
    public class MyEntity implements Serializable, Cloneable {
         @Id
         @GeneratedValue
         protected long id;

         // (..) more fields
    }

I'm using Java based Spring Configuration regarding the EntityManager, as follows:

@Configuration
public class EntityManagerConfiguration {

    @Bean
    public EntityManagerFactory entities() throws Exception {
        LocalContainerEntityManagerFactoryBean theEntityManager = new LocalContainerEntityManagerFactoryBean();
        theEntityManager.setPackagesToScan(MyEntity.class.getPackage().getName());
        theEntityManager.setJtaDataSource(dataSource());
        theEntityManager.setPersistenceUnitName("entities");
        theEntityManager.setJpaVendorAdapter(jpaVendorAdapter());
        theEntityManager.setJpaProperties(jpaProperties());
        theEntityManager.afterPropertiesSet();
        return theEntityManager.getNativeEntityManagerFactory();
    }

    @Bean
    public Properties jpaProperties() {
        Properties props = new Properties();
        props.setProperty("eclipselink.ddl-generation", "create-tables");
        props.setProperty("eclipselink.weaving", "false");
        props.setProperty("eclipselink.logging.level", "FINEST");
        props.setProperty("eclipselink.logging.parameters", "true");
        props.setProperty("eclipselink.target-server", "SunAS9");
        return props;
    }

    @Bean
    public DataSource dataSource() throws Exception {
        return (DataSource) JNDIUtils.getLocalJNDIResource("jdbc/entitiesDB");
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        EclipseLinkJpaVendorAdapter theVendorAdapter = new EclipseLinkJpaVendorAdapter();
        theVendorAdapter.setDatabase(Database.MYSQL);
        return theVendorAdapter;
    }

    @Bean
    public PlatformTransactionManager platformTransactionManager(){ 
        return new JtaTransactionManager();
    }   
}

Note that persistence.xml is not needed any more when using the setPackagesToScan() method.

And finally, the code that calls the persist() method:

@Repository
public class EntityRepository {

    @PersistenceContext(unitName = "entities")
    private EntityManager entityManager;

    public void persist(MyEntity myEntity) {
        entityManager.persist(myEntity);
    }
}

I have read many similar questions on SO, but none of them seem to reflect my problem precise enough to be able to solve it. What am I missing here?

Was it helpful?

Solution

Well, I managed to solve it. As willome pointed out I needed to use the @Transactional attribute on my persist() method. Furthermore I needed to add the @EnableTransactionManagement annotation to my EntityManagerConfiguration class. This Spring blog gave me the idea.

To complete this answer I've listed the final version of the EntityManagerConfiguration and EntityRepository classes below:

EntityManagerConfiguration

@Configuration
@EnableTransactionManagement
public class EntityManagerConfiguration {

   // class content did not change

}

EntityRepository

@Repository
public class EntityRepository {

    @PersistenceContext(unitName = "entities")
    private EntityManager entityManager;

    @Transactional
    public void persist(MyEntity myEntity) {
        entityManager.persist(myEntity);
    }
}

Now my entities are happily inserted and I can go celebrate the weekend! (well, in a few hours in fact)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top