G
G
gsaw2022-01-21 22:34:03
Java
gsaw, 2022-01-21 22:34:03

Why might entities not be saved in the database?

I have a task to read in one database (db2) and write to another (oracle).

spring boot jpa, hibernate

I have configured two Datasources, two EntityManagerFactory, two PlatformTransactionManager. for each base.

I also have a set of Entity classes for the second database, and for each I have my own Repository extends JpaRepository.

Actually the setup works. Since the application can certainly read in the database - the data source and update the jdbcTemplate data there with the component. In another database - where you need to write, the application can also read. I see in the traces requests to the database (for example, to count the number of records in the table) of the findById method of the repository.

But then some kind of garbage begins when you try to write through the repositories. The save(entity) method is called, I see in the hibernate log that the entity has been added to the queue.

22-01-21 Fr 20:15:16.830 DEBUG  [actSaveEventListener] : Generated identifier: component[]{}, using strategy: org.hibernate.id.CompositeNestedGeneratedValueGenerator
22-01-21 Fr 20:15:16.830 TRACE  [actSaveEventListener] : Saving [com.batch.vamos2dwh.writer.persistence.dwh.model.StF...
22-01-21 Fr 20:15:16.830 TRACE  [ActionQueue         ] : Adding an EntityInsertAction for [com.batch.vamos2dwh.writer.persistence.dwh.model.StF...] object
22-01-21 Fr 20:15:16.830 TRACE  [ActionQueue         ] : Adding insert with no non-nullable, transient entities: [EntityInsertAction[com.batch.vamos2dwh.writer.persistence.dwh.model.StF...]
22-01-21 Fr 20:15:16.830 TRACE  [ActionQueue         ] : Adding resolved non-early insert action.


But for some reason, the entity is not written to the database as a result. I don't even see inserts in the log.

I think I have some kind of garbage with transactions.

I set up a ChainedTransactionManager to commit to both databases at once on success. But it commits only in one, in the source.

@Bean(name = "chainedTransactionManager")
    public ChainedTransactionManager transactionManager(@Qualifier("dwhTransactionManager") PlatformTransactionManager ds1,
                                                    @Qualifier("vamosTransactionManager") PlatformTransactionManager ds2) {
         return new ChainedTransactionManager(ds1, ds2);
    }


And I use it at the very first entry point of the component, which then does all this.

@Transactional(value="chainedTransactionManager", propagation = Propagation.REQUIRES_NEW)
    public int processSCFZ() {


I don't have transactional anywhere else, and the processSCFZ method is called from another component. Linked by @Autowired, that is, a transaction must be created.

Why am I sinning on transactions, because I see in the log for each save

getting transaction for blablaEntityRepository.save


This doesn't seem to be normal.

Why can this happen? Somehow you can enable tracing of these transactions in order to understand why it is not created. And then everyone is already celebrating Friday, but I still could not write it down in the database. Moreover, when all this read data not from another database, but from MQ, everything worked and wrote to the database as it should. Broke after adding a second base source.

Here is the configuration of the target base that does not want to write data. The other is configured similarly, just a different prefix

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = "com.batch.vamos2dwh.writer.persistence.dwh.repository",
        entityManagerFactoryRef = "dwhEntityManagerFactory",
        transactionManagerRef = "dwhTransactionManager")
public class DwhDatasourceConfiguration {
    @Value("${dwh.jpa.properties.hibernate.dialect}")
    private String hibernateDialect;

    @Bean(name = "dwhDatasource")
    @ConfigurationProperties(prefix = "dwh.datasource")
    @Primary
    public DataSource dwhDatasource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dwhTransactionManager")
    @Primary
    public PlatformTransactionManager dwhTransactionManager(@Qualifier("dwhDatasource") DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }

    @Bean(name = "dwhJdbc")
    public JdbcTemplate vamosJdbc(@Qualifier("dwhDatasource") DataSource ds) {
        return new JdbcTemplate(ds);
    }

    @Bean(name = "dwhEntityManagerFactory")
    @Primary
    public LocalContainerEntityManagerFactoryBean dwhEntityManagerFactory(
            EntityManagerFactoryBuilder entityManagerFactoryBuilder,
            @Qualifier("dwhDatasource") DataSource dwhDatasource) {

        HashMap<String, Object> props = new HashMap<>();
        props.put("hibernate.dialect", hibernateDialect);

        return entityManagerFactoryBuilder
                .dataSource(dwhDatasource)
                .properties(props)
                .packages("com.batch.vamos2dwh.writer.persistence.dwh")
                .persistenceUnit("dwhPersistence")
                .build();
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
G
gsaw, 2022-01-22
@gsaw

My mistake was

@Bean(name = "dwhTransactionManager")
    @Primary
    public PlatformTransactionManager dwhTransactionManager(@Qualifier("dwhDatasource") DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }

Instead of DataSourceTransactionManager, JpaTransactionManager should have been used. It turned out that JpaRepository did not work as it should. It was possible to request data, but the entry into nirvana was gone. Changed to JpaTransactionManager and everything worked.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question