Announcement Announcement Module
Collapse
No announcement yet.
Records not inserting when using JpaRepository Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Records not inserting when using JpaRepository

    I've got a small application, configured with annotations rather than XML, that has a test case that is using a JPA Repository to write some instances of an entity to a table. The test runs fine but nothing is written to the database (note that defaultRollBack=false).

    Here's the test:

    Code:
    /**
     * test the database code.
     * 
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { LiveApplicationConfiguration.class })
    @ActiveProfiles("live")
    @TransactionConfiguration(defaultRollback = false)
    @Transactional
    public class DatabaseTestsIT {
    
    	@Autowired
    	private HistoryService historyService;
    
    	/**
    	 * test loading of repository works.
    	 */
    	@Test
    	public void testAnnotationConfigApplicationContextThatWorks() {
    
    		assertNotNull(historyService);
    		History history = new History();
    		history.setSomeData("test");
    
    		History savedHistory = historyService.save(history);
    		historyService.flush();
    	}


    If I leave the flush in there I get this error


    Code:
    javax.persistence.TransactionRequiredException: no transaction is in progress

    If I run it without the flush it doesn't fail but doesn't write the record either:

    Here's the console output - note the before and after transaction printlns which I put in there to prove the test code was running in a transaaction.

    Code:
    org.hibernate.engine.transaction.spi.AbstractTransactionImpl: 158 - begin
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 212 - Obtaining JDBC connection
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 218 - Obtained JDBC connection
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction:  69 - initial autocommit status: true
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction:  71 - disabling autocommit
    org.hibernate.internal.SessionImpl: 315 - Opened session at timestamp: 13723391357
    org.hibernate.internal.SessionImpl:1397 - Setting flush mode to: AUTO
    org.hibernate.internal.SessionImpl:1414 - Setting cache mode to: NORMAL
    org.hibernate.event.internal.AbstractSaveEventListener: 499 - Transient instance of: history.repository.History
    org.hibernate.event.internal.DefaultPersistEventListener: 202 - Saving transient instance
    org.hibernate.event.internal.AbstractSaveEventListener: 167 - Saving [history.repository.History#<null>]
    org.hibernate.engine.spi.ActionQueue: 177 - Adding an EntityIdentityInsertAction for [history.repository.History] object
    org.hibernate.engine.spi.ActionQueue: 193 - Adding insert with no non-nullable, transient entities: [EntityIdentityInsertAction[history.repository.History#<delayed:0>]]
    org.hibernate.engine.spi.ActionQueue: 217 - Adding resolved non-early insert action.
    org.hibernate.action.internal.UnresolvedEntityInsertActions: 214 - No unresolved entity inserts that depended on [[history.repository.History#<delayed:0>]]
    org.hibernate.action.internal.UnresolvedEntityInsertActions: 121 - No entity insert actions have non-nullable, transient entity dependencies.
    org.hibernate.internal.SessionImpl: 342 - Closing session
    org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl: 171 - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@5cf346dc]
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 164 - Closing logical connection
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 176 - Logical connection closed
    org.hibernate.engine.transaction.spi.AbstractTransactionImpl: 173 - committing
    org.hibernate.internal.SessionImpl: 403 - Automatically flushing session
    org.hibernate.internal.SessionImpl: 612 - before transaction completion
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction: 113 - committed JDBC Connection
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction: 126 - re-enabling autocommit
    org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl: 136 - after transaction completion
    org.hibernate.internal.SessionImpl: 624 - after transaction completion
    org.hibernate.internal.SessionImpl: 342 - Closing session
    org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl: 171 - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@2b52b6f5]
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 164 - Closing logical connection
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 232 - Releasing JDBC connection
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 250 - Released JDBC connection
    org.hibernate.engine.jdbc.internal.LogicalConnectionImpl: 176 - Logical connection closed
    org.hibernate.engine.transaction.spi.AbstractTransactionImpl: 173 - committing
    org.hibernate.internal.SessionImpl: 403 - Automatically flushing session
    org.hibernate.internal.SessionImpl: 612 - before transaction completion
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction: 113 - committed JDBC Connection
    org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction: 126 - re-enabling autocommit
    org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl: 136 - after transaction completion
    org.hibernate.internal.SessionImpl: 624 - after transaction completion
    org.hibernate.internal.SessionImpl: 342 - Closing session
    org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl: 171 - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@6d3d422d]
    Finally here's the code:

    1) the configuration (minus the datasource, that's in an a subclass of the main configuration), no need to post that.

    Code:
    /**
     * Configuration for history repositories.
     */
    
    @Configuration
    @EnableJpaRepositories("history.repository")
    @EnableTransactionManagement
    @PropertySource("classpath:historyDatabase.properties")
    @ComponentScan(basePackages={"history.repository"})
    public abstract class BaseApplicationConfiguration implements TransactionManagementConfigurer{
    
    	/**
    	 * injected Spring environment.
    	 */
    	@Autowired
    	protected Environment environment;
    
    	/**
    	 * creates an entity manager factory.
    	 * 
    	 * @return an entity manager factory
    	 */
    	@Bean(name = "entityManagerFactory")
    	public EntityManagerFactory entityManagerFactory() {
    		LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean();
    		lcemfb.setPersistenceUnitName("foo");
    		lcemfb.setDataSource(dataSource());
    		lcemfb.setJpaDialect(new HibernateJpaDialect());
    		lcemfb.setJpaVendorAdapter(jpaVendorAdapter());
    		lcemfb.setPackagesToScan("history.repository");
    		lcemfb.afterPropertiesSet();
    		return lcemfb.getObject();
    	}
    
    	/**
    	 * define an exception translator
    	 * 
    	 * @return the translator
    	 */
    
    	@Bean
    	public final HibernateExceptionTranslator hibernateExceptionTranslator() {
    		return new HibernateExceptionTranslator();
    	}
    
    	/**
    	 * returns a data source.
    	 * 
    	 * @return the datasource.
    	 */
    	protected abstract DataSource dataSource();
    
    	/**
    	 * creates a JPA vendor adaptor bean.
    	 * 
    	 * @return the JPA vendor adapter
    	 */
    	@Bean(name = "jpaVendorAdapter")
    	public JpaVendorAdapter jpaVendorAdapter() {
    		HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
    		jpaVendorAdapter.setShowSql(true);
    
    		// TODO possibly make this configurable
    		jpaVendorAdapter.setDatabase(Database.MYSQL);
    		jpaVendorAdapter.setDatabasePlatform(environment
    				.getProperty("historyDbDialect"));
    		jpaVendorAdapter.setGenerateDdl(Boolean.parseBoolean(environment.getProperty("generatedDDL")));
    		jpaVendorAdapter.setShowSql(Boolean.parseBoolean(environment.getProperty("showSQL")));
    
    		return jpaVendorAdapter;
    	}
    
    	/**
    	 * @see org.springframework.transaction.annotation.TransactionManagementConfigurer#annotationDrivenTransactionManager()
    	 * @return the transaction manager
    	 */
    	@Bean(name = "transactionManager")
    	public PlatformTransactionManager annotationDrivenTransactionManager() {
    		JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    		jpaTransactionManager.setEntityManagerFactory(entityManagerFactory());
    		return jpaTransactionManager;
    	}

    2) My repository interface. Very simple, Just extends the Spring Data jpa one and at run time Spring should create a proxy that implements all the basic crud operations, IN A TRANSACTION


    Code:
    public interface HistoryRepository extends JpaRepository<History, Long> {
    
    	
    	/**
    	 * finds some data.
    	 * @param someData - to find
    	 * @return a list of history records
    	 */
    	List<History> findBySomeData(String someData);
    }
    3) The History service just delegates to the repository, and is transactional itself

    So in summary:

    The test is transactional, the service is transactional, and the repository is transactional, so why isn't a record getting written to the table, and why, if a manual flush is added in the test, does that fail with no transaction in progress ?

    I suspect that something somewhere (maybe the proxying of the repository interface) is interfering with the transaction aop code, and not actually creating a transaction to do the insert. This is despite the configuration class having @EnableTransactionManagement on it.

  • #2
    Some extra info on this. The repository code is obviously not hitting the database at all, as if I delete the table in question, and turn off generateDDL on HibernateJpaVendorAdapter, it doesn't crash, indicating that, for whatever reason, the SQL insert isn't ever executed.

    Comment


    • #3
      Issue caused by the issue described here:

      http://forum.springsource.org/showth...988#post449988

      Comment

      Working...
      X