Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data is not saved in DB when using Transaction annotation in JUnit test

Colleagues, I can not solve a problem with a transactions in Spring more than week. I have created quite similar post (Why data wasn't saved when I use @Transactional annotation?), but could't to solve the problem in it; of course i took into account the recommendations who gave @Florian Schaetz. I kindly ask you to help me.

So, I have the test class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
@Transactional

public class OdValuesServiceTest {
    static final Logger LOG = Logger.getLogger(OdValuesServiceTest.class.getName());

    @Autowired
    OdValuesService odValuesService;
    @Autowired
    DBCommonsService dbCommonsService;

    @Transactional ("txManagerDU")
    @Test
    @Commit

    public void addOdValue() throws Exception {


                OdValuesEntity odValuesEntity = new OdValuesEntity();
                odValuesEntity.setId(dbCommonsService.getNextDocOD("OD_VALUES_ID_GEN"));
                odValuesEntity.setSysname("Name" + DataGenerator.getRandomISIN());
                odValuesEntity.setName("Name");
                odValuesEntity.setIsIn((short) 1);
                odValuesEntity.setvType(2);
                odValuesEntity.setMfu((short) 0);
                odValuesEntity.setIsin("AU000A0JP922");
                odValuesEntity.setCfi("");

                odValuesService.addOdValue(odValuesEntity);
    }
}

Interface class addOdValue looks like:

public interface OdValuesDAO {

    public void addOdValue (OdValuesEntity odValuesEntity);

}

And DAO implementation class is :

@Component
public class OdValuesDAOImpl implemets OdValuesDAO  
{

    static final Logger LOG = Logger.getLogger(OdValuesDAO.class.getName());


    @Autowired
    @Qualifier("emDU")
    private EntityManager em;

    public void addOdValue (OdValuesEntity odValuesEntity) {
        LOG.info(odValuesEntity.toString());

        LOG.info("Transaction is active:" + em.getTransaction().isActive());
        //em.getTransaction().begin();
        em.persist(odValuesEntity);
        //em.getTransaction().commit();

    }

}

Spring context, as config file, is:

@Configuration
@EnableTransactionManagement
@ComponentScan

public class AppConfig {

static final Logger LOG = Logger.getLogger(AppConfig.class.getName());


/*There are some beans to work with properties file*/

    @Bean
    public BasicDataSource primaryDuDataSource() {
        BasicDataSource primaryDuDataSource = new BasicDataSource();
        primaryDuDataSource.setDriverClassName("org.firebirdsql.jdbc.FBDriver");
        primaryDuDataSource.setUrl(primaryDuDbUrl);
        primaryDuDataSource.setUsername(primaryDuDbUser);
        primaryDuDataSource.setPassword(primaryDuDbPassword);
        primaryDuDataSource.setMaxIdle(30);
        primaryDuDataSource.setMaxWaitMillis(10000);

        primaryDuDataSource.setValidationQuery("select 1 from rdb$database");
        primaryDuDataSource.setTestOnBorrow(false);
        primaryDuDataSource.setTestWhileIdle(true);
        primaryDuDataSource.setDefaultAutoCommit(true);

        return primaryDuDataSource;
    }


    @Bean

    public BasicDataSource secondaryDataSource() {
        BasicDataSource secondaryDataSource = new BasicDataSource();
        secondaryDataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        secondaryDataSource.setUrl(scndsysDbUrl);
        secondaryDataSource.setUsername(scndsysDbUser);
        secondaryDataSource.setPassword(scndsysDbPassword);
        secondaryDataSource.setMaxIdle(2);
        secondaryDataSource.setMaxWaitMillis(10000);
        secondaryDataSource.setValidationQuery("select 1");
        secondaryDataSource.setTestOnBorrow(true);
        secondaryDataSource.setTestWhileIdle(true);
        secondaryDataSource.setDefaultAutoCommit(true);
        return secondaryDataSource;
    }


    @Bean
    public  LocalContainerEntityManagerFactoryBean entityManagerFactory (@Qualifier("secondaryDataSource") BasicDataSource secondaryDataSource) {
        LocalContainerEntityManagerFactoryBean localConnectionFactoryBean = new LocalContainerEntityManagerFactoryBean();
        localConnectionFactoryBean.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
        localConnectionFactoryBean.setDataSource(secondaryDataSource);
        localConnectionFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        return localConnectionFactoryBean;
    }


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryprmsys (@Qualifier("primaryDuDataSource")BasicDataSource primaryDuDataSource) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
        emf.setDataSource(primaryDuDataSource);
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.dialect", "org.hibernate.dialect.FirebirdDialect");
        emf.setJpaPropertyMap(properties);
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setGenerateDdl(true);
        hibernateJpaVendorAdapter.setShowSql(true);
        emf.setJpaVendorAdapter(hibernateJpaVendorAdapter);

        return emf;
    }


    @Bean
    public EntityManager emDU (@Qualifier("entityManagerFactoryprmsys") EntityManagerFactory entityManagerFactoryprmsys) {
        return entityManagerFactoryprmsys.createEntityManager();
    }


    @Bean
    public EntityManager emscndsys (@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory ) {
        return entityManagerFactory.createEntityManager();
    }




    @Bean
    public  JpaTransactionManager txManagerDU (@Qualifier("entityManagerFactoryprmsys") EntityManagerFactory entityManagerFactoryprmsys) {
         JpaTransactionManager txManager = new JpaTransactionManager();
         txManager.setEntityManagerFactory(entityManagerFactoryprmsys);
         return txManager;
    }


    @Bean
    public  JpaTransactionManager txManagerscndsys (@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }

}

Stacktrace is :

>     "C:\Program Files\Java\jdk1.8.0_77\bin\java" -ea
>     -Didea.launcher.port=7537 "-Didea.launcher.bin.path=C:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.3\bin"
>     -Didea.junit.sm_runner
>     -Dfile.encoding=UTF-8 -classpath "jars"
>     com.intellij.rt.execution.application.AppMain
>     com.intellij.rt.execution.junit.JUnitStarter -ideVersion5
>     au.acap.app.JpaEntities.Service.OdValuesServiceTest,addOdValue
>     log4j:WARN Continuable parsing error 86 and column 23 log4j:WARN The
>     content of element type "log4j:configuration" must match
>     "(renderer*,throwableRenderer?,appender*,plugin*,(category|logger)*,root?,(categoryFactory|loggerFactory)?)". INFO : [sep-16 15:08:48,172]
>     context.support.DefaultTestContextBootstrapper - Loaded default
>     TestExecutionListener class names from location
>     [META-INF/spring.factories]:
>     [org.springframework.test.context.web.ServletTestExecutionListener,
>     org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener,
>     org.springframework.test.context.support.DependencyInjectionTestExecutionListener,
>     org.springframework.test.context.support.DirtiesContextTestExecutionListener,
>     org.springframework.test.context.transaction.TransactionalTestExecutionListener,
>     org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
>     INFO : [sep-16 15:08:48,213]
>     context.support.DefaultTestContextBootstrapper - Could not instantiate
>     TestExecutionListener
>     [org.springframework.test.context.web.ServletTestExecutionListener].
>     Specify custom listener classes or make the default listener classes
>     (and their required dependencies) available. Offending class:
>     [org/springframework/web/context/request/RequestAttributes] INFO :
>     [sep-16 15:08:48,215] context.support.DefaultTestContextBootstrapper -
>     Using TestExecutionListeners:
>     [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@67784306,
>     org.springframework.test.context.support.DependencyInjectionTestExecutionListener@335eadca,
>     org.springframework.test.context.support.DirtiesContextTestExecutionListener@210366b4,
>     org.springframework.test.context.transaction.TransactionalTestExecutionListener@eec5a4a,
>     org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@2b2948e2]INFO
>     : [sep-16 15:08:48,402] context.support.GenericApplicationContext -
>     Refreshing
>     org.springframework.context.support.GenericApplicationContext@3712b94:
>     startup date [Fri Sep 16 15:08:48 MSK 2016]; root of context hierarchy
>     INFO : [sep-16 15:08:48,956] app.Commons.QortCommons - StartDate:
>         24.06.2016 00:00:00 INFO : [sep-16 15:08:48,958] app.Commons.QortCommons - EndDate: 11.08.2016 23:59:59 INFO : [sep-16
>     15:08:48,970] acap.app.AppConfig -  mainClassLocation:
>     /C:/Users/maya/Documents/GIT/qort-integration/prmsys/target/classes/
>     INFO : [sep-16 15:08:48,971] acap.app.AppConfig - Properties will read
>     from:
>     /C:/Users/maya/Documents/GIT/qort-integration/prmsys/target/classes/application.properties
>     INFO : [sep-16 15:08:49,238]
>     orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA
>     container EntityManagerFactory for persistence unit 'PersistenceUnit'
>     INFO : [sep-16 15:08:50,587]
>     orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA
>     container EntityManagerFactory for persistence unit 'PersistenceUnit'
>     Hibernate: create table HT_OD_A_SHARES (SHARE integer not null,
>     hib_sess_id CHAR(36)) Hibernate: create table HT_OD_DOLS (ID integer
>     not null, hib_sess_id CHAR(36)) Hibernate: create table HT_OD_VALUES
>     (ID integer not null, hib_sess_id CHAR(36)) .... INFO : [sep-16
>     15:08:52,350] java.sql.DatabaseMetaData - HHH000262: Table not found:
>     ...... ERROR: [sep-16 15:08:52,442] tool.hbm2ddl.SchemaUpdate -
>     HHH000388: Unsuccessful: create table ..... ERROR: [sep-16
>     15:08:52,444] tool.hbm2ddl.SchemaUpdate - GDS Exception. 335544569.
>     Dynamic SQL Error SQL error code = -104 Token unknown - line 1, column
>     17 . ERROR: [sep-16 15:08:52,449] tool.hbm2ddl.SchemaUpdate -
>     HHH000388: Unsuccessful: create table .....
>     INFO : [sep-16 15:08:52,741] context.transaction.TransactionContext - Began transaction (1) for
>     test context [DefaultTestContext@222afc67 testClass =
>     OdValuesServiceTest, testInstance =
>     au.acap.app.JpaEntities.Service.OdValuesServiceTest@4c2fb9dd,
>     testMethod = addOdValue@OdValuesServiceTest, testException = [null],
>     mergedContextConfiguration = [MergedContextConfiguration@58cf8f94
>     testClass = OdValuesServiceTest, locations = '{}', classes = '{class
>     au.acap.app.AppConfig}', contextInitializerClasses = '[]',
>     activeProfiles = '{}', propertySourceLocations = '{}',
>     propertySourceProperties = '{}', contextLoader =
>     'org.springframework.test.context.support.AnnotationConfigContextLoader',
>     parent = [null]]]; transaction manager
>     [org.springframework.orm.jpa.JpaTransactionManager@54f4a7f0]; rollback
>     [false] Hibernate: select gen_id(OD_VALUES_ID_GEN,1) as DOC_ID from
>     rdb$database INFO : [sep-16 15:08:52,872]
>     JpaEntities.Service.DBCommonsService - docId = 10465 INFO : [sep-16
>     15:08:52,931] app.DAO.OdValuesDAO -
>     au.acap.app.JpaEntities.OdValuesEntity@70c0a3d5[   id=10465  
>     sysname=NameJP3228600007   name=Name   vType=2   isin=AU000A0JP922  
>     mfu=0   isIn=1   cfi= ] INFO : [sep-16 15:08:52,933]
>     app.DAO.OdValuesDAO - Transaction is active:false Hibernate: insert
>     into OD_VALUES (B_DATE, BASE_VAL, CFI, IS_IN, ISIN, MFU, NAME,
>     SYSNAME, V_TYPE, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) INFO :
>     [sep-16 15:08:53,004] context.transaction.TransactionContext -
>     Committed transaction for test context [DefaultTestContext@222afc67
>     testClass = OdValuesServiceTest, testInstance =
>     au.acap.app.JpaEntities.Service.OdValuesServiceTest@4c2fb9dd,
>     testMethod = addOdValue@OdValuesServiceTest, testException = [null],
>     mergedContextConfiguration = [MergedContextConfiguration@58cf8f94
>     testClass = OdValuesServiceTest, locations = '{}', classes = '{class
>     au.acap.app.AppConfig}', contextInitializerClasses = '[]',
>     activeProfiles = '{}', propertySourceLocations = '{}',
>     propertySourceProperties = '{}', contextLoader =
>     'org.springframework.test.context.support.AnnotationConfigContextLoader',
>     parent = [null]]]. INFO : [sep-16 15:08:53,007]
>     context.support.GenericApplicationContext - Closing
>     org.springframework.context.support.GenericApplicationContext@3712b94:
>     startup date [Fri Sep 16 15:08:48 MSK 2016]; root of context hierarchy
>     INFO : [sep-16 15:08:53,013]
>     orm.jpa.LocalContainerEntityManagerFactoryBean - Closing JPA
>     EntityManagerFactory for persistence unit 'PersistenceUnit' INFO :
>     [sep-16 15:08:53,030] orm.jpa.LocalContainerEntityManagerFactoryBean -
>     Closing JPA EntityManagerFactory for persistence unit 'PersistenceUnit'
>     Process finished with exit code 0

The problem is that transaction is not commited. Please, help me to save data in DB during the test. Thank you.

Update: Help still needed!

May be problem in my imports?

import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
like image 709
May12 Avatar asked Sep 16 '16 12:09

May12


People also ask

What does @transactional annotation do?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

What is the annotation required for JUnit test methods?

A JUnit test is a method contained in a class which is only used for testing. This is called a Test class. To mark a method as a test method, annotate it with the @Test annotation. This method executes the code under test.

Where does the @transactional annotation belong?

The @Transactional annotation belongs to the Service layer because it is the Service layer's responsibility to define the transaction boundaries.

What happens when a JUnit method has the annotation before?

The @Before annotation is used when different test cases share the same logic. The method with the @Before annotation always runs before the execution of each test case. This annotation is commonly used to develop necessary preconditions for each @Test method.

What is the @testinstance annotation in JUnit 5?

By default, both JUnit 4 and 5 create a new instance of the test class before running each test method. This provides a clean separation of state between tests. In this tutorial, we are going to learn how JUnit 5 allows us to modify the lifecycle of the test class using the @TestInstance annotation.

What is @after and @ignore In JUnit?

In the same way @After in JUnit, @afterClass (method m3 () and m4 ()) will be executed after each and after all test cases respectively. @ignore (method m6 ())will be treated as ignoring the test. Let’s analyse test cases used in above java class in detail: Consider method m5 () as given below :

Does @transactional create a transaction for each test?

[..]By default, the framework will create and roll back a transaction for each test . [..] So, if your "problem" is, that no data is written to the database in your tests when using @Transactional, then that's no problem at all, it's how the spring default works. If that's not what you want...

What are the member variables in JUnit tests?

Introduction Test classes often contain member variables referring to the system under test, mocks, or data resources used in the test. By default, both JUnit 4 and 5 create a new instance of the test class before running each test method. This provides a clean separation of state between tests.


1 Answers

From the @Commit documentation:

Warning: @Commit can be used as direct replacement for @Rollback(false); however, it should not be declared alongside @Rollback. Declaring @Commit and @Rollback on the same test method or on the same test class is unsupported and may lead to unpredictable results."

So mixing @Commit and @Rollback is a bad idea.

Another thing that is the class/method @Transactional tag with different configuration (but I'm not sure if this is the problem here.)

like image 68
Gev Avatar answered Sep 22 '22 10:09

Gev