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;
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.
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.
The @Transactional annotation belongs to the Service layer because it is the Service layer's responsibility to define the transaction boundaries.
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.
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.
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 :
[..]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...
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.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With