H2 & DBUnit setup - dbunit

I want to initialize an H2 in memory database using DBUnit for unit tests with a schema. I based my code on https://www.baeldung.com/java-dbunit and tried to amend it to use a table with a schema. Using the H2 console, I can see that the schema has been created and that the table has been created in the schema, but the table is empty and the assertion fails.
package de.kn.info.accountplus.add.mediation.energy.importCifE1;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.dbunit.DataSourceBasedDBTestCase;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.h2.jdbcx.JdbcDataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
#RunWith(JUnit4.class)
public class DBUnitByBaeldungTest extends DataSourceBasedDBTestCase {
private Connection connection;
#Override
protected DataSource getDataSource() {
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL(
"jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;mode=Oracle;init=runscript from 'file:C:/Users/me/Projects/add/test-resources/de/kn/info/accountplus/add/mediation/energy/importCifE1/acctSys-schema.sql'");
dataSource.setUser("SA");
return dataSource;
}
#Override
protected IDataSet getDataSet() throws Exception {
IDataSet dataset = new FlatXmlDataSetBuilder().build(new FileInputStream("C:\\Users\\me\\Projects\\add\\test\\de\\kn\\info\\accountplus\\add\\resource\\myDatasetV1.xml"));
return dataset;
}
#Override
protected void setUpDatabaseConfig(DatabaseConfig config) {
config.setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
}
#Before
public void setUp() throws Exception {
super.setUp();
connection = getConnection().getConnection();
}
#After
public void tearDown() throws Exception {
super.tearDown();
}
#Test
public void readDB() throws SQLException {
ResultSet rs = connection.createStatement().executeQuery("select * from AP.ACCTSYS");
assertThat(rs.next(), equalTo(true));
System.out.println(rs.getString(1));
}
}
The schema file
DROP SCHEMA IF EXISTS AP;
CREATE SCHEMA AP;
create table if not exists AP.ACCTSYS
(
EINTRAG VARCHAR2(60) not null
constraint PK_ACCTSYS
primary key,
WERT VARCHAR2(512)
);
and the dataset file
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<AP.ACCTSYS EINTRAG="ONE" WERT="TWO" />
</dataset>
Can anyone see what I am missing

Related

Hive and Impala query result not matching [timestamp]

I'm working on a code where we are removing impala connection to hive beeline. changes are working as we expected. but when we try to query some data using impala , it came up with some additional timestamp with the date.
Sample Query: select cob_date from xxx_table where cob_date='2022-03-20';
outcome of the above query in impala is : 2022-03-20 05:00:00
but usually it will return like : 2022-03-20 00:00:00
but the same query giving proper response when try from hive : 2022-03-20 00:00:00
can anyone help me to understand whats going on here.
Thanks in advance .
package com.rest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.rest.controller.PersonController;
import com.rest.entity.Person;
import com.rest.repository.PersonRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(MockitoJUnitRunner.class)
public class PersonControllerTest {
private MockMvc mockMvc;
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer();
#Mock
private PersonRepository personRepository;
#InjectMocks
private PersonController personController;
Person person1 = new Person(1, "Arun", "Ammasai", "aj.amsi#email.com");
Person person2 = new Person(2, "Nancy", "ArulRaj", "nancymaria#email.com");
Person person3 = new Person(3, "Jack", "Daniel", "jack.daniel#email.com");
#Before
public void init() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(personController).build();
}
#Test
public void getAllSuccess() throws Exception {
List<Person> persons = Arrays.asList(person1, person2, person3);
Mockito.when(personRepository.findAll()).thenReturn(persons);
mockMvc.perform(MockMvcRequestBuilders.get("/getall")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[2].firstName", is("Jack")));
}
#Test
public void getByIdSuccess() throws Exception {
Mockito.when(personRepository.findById(person1.getId())).thenReturn(Optional.of(person1));
mockMvc.perform(MockMvcRequestBuilders.get("/findbyId/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath("$.firstName", is("Arun")));
}
#Test
public void createPerson_Success() throws Exception {
Person person = Person.builder().firstName("Arun").lastName("Amsi").email("test#gmail.com").build();
Mockito.when(personRepository.save(person)).thenReturn(person);
String content = writer.writeValueAsString(person);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("/addperson")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(content);
mockMvc.perform(request)
.andExpect(status().isOk())
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath("$.firstName", is("Arun")));
}
#Test
public void updatePerson_Success() throws Exception {
Person person = Person.builder().firstName("Arun").lastName("Amsi").email("test#gmail.com").build();
Mockito.when(personRepository.findById(person.getId())).thenReturn(Optional.of(person));
Mockito.when(personRepository.save(person)).thenReturn(person);
String content = writer.writeValueAsString(person);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.put("/updateperson")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(content);
mockMvc.perform(request).andExpect(status().isOk())
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath("$.firstName", is("Arun")));
}
#Test
public void deletePerson_Success() throws Exception {
Mockito.when(personRepository.findById(person1.getId())).thenReturn(Optional.of(person1));
mockMvc.perform(MockMvcRequestBuilders.delete("/delete/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}

How to use two data source for same entity in spring boot application running on tomcat

I have one micro-service named order-service in spring boot.
:: Spring Boot :: (v2.0.5.RELEASE)
in that micro-service, in service layer I have 2 service class 1. OrderManagerService and OrderService. From OrderService I call Repository Interface IOrderRequestRepository which extends PagingAndSortingRepository interface. so The call is basically OrderManagerService -> OrderService -> IOrderRequestRepository.
Right now I am using one data source for the micro-service. Now my requirement is I have to use 2 data source because in OrderManagerService there is one method getCustomerVisitsForMonth(Long customerID) which frequently used and we don't want to give load on prod DB server. Instead we will use prod-replica server for this one particular method.
I have googled a lot of blogs and tried to implement but ending up getting different exception.
below are exceptions:
could not execute query; SQL [SELECT * FROM ....(this is the actual query)]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query",
Could not open JPA EntityManager for transaction; nested exception is org.hibernate.TransactionException: JDBC begin transaction failed:
Below are my sample code:
application-env.properties
spring.datasource.url=jdbc:mysql://someurl:3306/orders?zeroDateTimeBehavior=convertToNull&useSSL=false
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#replica datasource details
spring.replica.datasource.url=jdbc:mysql://someurl:3306/order?zeroDateTimeBehavior=convertToNull&useSSL=false
spring.replica.datasource.username=<username>
spring.replica.datasource.password=<password>
spring.replica.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.tomcat.initial-size=15
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=5
spring.datasource.tomcat.max-idle=4
spring.datasource.tomcat.min-idle=2
spring.datasource.tomcat.default-auto-commit=true
#replica data source details
spring.replica.datasource.tomcat.initial-size=15
spring.replica.datasource.tomcat.max-wait=20000
spring.replica.datasource.tomcat.max-active=5
spring.replica.datasource.tomcat.max-idle=4
spring.replica.datasource.tomcat.min-idle=2
spring.replica.datasource.tomcat.default-auto-commit=true
Main class
package in.demo.order.web.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#SpringBootApplication(scanBasePackages = "in.demo.order",
exclude = { SecurityAutoConfiguration.class })
public class OrderServiceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(OrderServiceApplication.class);
}
}
I have created 2 different packages for Repository classes and for Entity classes, however my Entity and Repository are same.
packages
in.demo.order.dao
in.demo.order.repodao
Configuration classes
MainDataSourceConfiguration
package in.demo.order.web.config;
import in.demo.order.replicadao.IOrderRequestRepositoryForReplica;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "in.demo.order.dao",
entityManagerFactoryRef = "mainEntityManagerFactory",
transactionManagerRef = "mainTransactionManager"
)
public class MainDataSourceConfiguration {
#Autowired
private Environment environment;
#Primary
#Bean(name = "mainDataSourceProperties")
#ConfigurationProperties("spring.datasource")
public DataSourceProperties mainDataSourceProperties() {
return new DataSourceProperties();
}
#Primary
#Bean(name = "mainDataSource")
#ConfigurationProperties("spring.datasource.configuration")
public DataSource mainDataSource(
#Qualifier("mainDataSourceProperties") DataSourceProperties mainDataSourceProperties) {
return mainDataSourceProperties
.initializeDataSourceBuilder()
.type(org.apache.tomcat.jdbc.pool.DataSource.class)
.build();
}
#Primary
#Bean(name = "mainEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean mainEntityManagerFactory(
EntityManagerFactoryBuilder mainEntityManagerFactoryBuilder,
#Qualifier("mainDataSource") DataSource mainDataSource) {
Map<String, String> mainJpaProperties = new HashMap<>();
mainJpaProperties.put("hibernate.dialect",
environment.getProperty("spring.jpa.properties.hibernate.dialect"));
mainJpaProperties.put("hibernate.hbm2ddl.auto",
environment.getProperty("spring.jpa.hibernate.ddl-auto"));
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = mainEntityManagerFactoryBuilder
.dataSource(mainDataSource)
.packages("in.demo.order.dao.model")
.persistenceUnit("mainDataSource")
.properties(mainJpaProperties)
.build();
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
#Primary
#Bean(name = "mainTransactionManager")
public PlatformTransactionManager mainTransactionManager(
#Qualifier("mainEntityManagerFactory") EntityManagerFactory mainEntityManagerFactory) {
return new JpaTransactionManager(mainEntityManagerFactory);
}
}
ReplicaDataSourceConfiguration
package in.demo.order.web.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "in.demo.order.replicadao",
entityManagerFactoryRef = "replicaEntityManagerFactory",
transactionManagerRef = "replicaTransactionManager"
)
public class ReplicaDataSourceConfiguration {
#Autowired
private Environment environment;
#Bean(name = "replicaDataSourceProperties")
#ConfigurationProperties("spring.replica.datasource")
public DataSourceProperties replicaDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "replicaDataSource")
#ConfigurationProperties("spring.replica.datasource.configuration")
public DataSource replicaDataSource(
#Qualifier("replicaDataSourceProperties") DataSourceProperties replicaDataSourceProperties) {
return replicaDataSourceProperties
.initializeDataSourceBuilder()
.type(org.apache.tomcat.jdbc.pool.DataSource.class)
.build();
}
#Bean(name = "replicaEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean replicaEntityManagerFactory(
EntityManagerFactoryBuilder replicaEntityManagerFactoryBuilder,
#Qualifier("replicaDataSource") DataSource replicaDataSource) {
Map<String, String> replicaJpaProperties = new HashMap<>();
replicaJpaProperties.put("hibernate.dialect",
environment.getProperty("spring.jpa.properties.hibernate.dialect"));
replicaJpaProperties.put("hibernate.hbm2ddl.auto",
environment.getProperty("spring.jpa.hibernate.ddl-auto"));
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = replicaEntityManagerFactoryBuilder
.dataSource(replicaDataSource)
.packages("in.demo.order.replicadao.model")
.persistenceUnit("replicaDataSource")
.properties(replicaJpaProperties)
.build();
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
#Bean(name = "replicaTransactionManager")
public PlatformTransactionManager replicaTransactionManager(
#Qualifier("replicaEntityManagerFactory") EntityManagerFactory replicaEntityManagerFactory) {
return new JpaTransactionManager(replicaEntityManagerFactory);
}
}
OrderManagerService
package in.demo.order.service;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
#Transactional
public class OrderManagerService{
#Autowired
private OrderService orderService;
public CustomerVisitsResponse getCustomerVisitsForMonthForReplicaDataSource(Long customerId) {
return orderService.getTotalCustomerVisitsForMonth(customerId);
}
public CustomerVisitsResponse getCustomerVisitsForMonthForMainDataSource(Long customerId) {
return orderService.getTotalCustomerVisitsForMonthForMainDataSource(customerId);
}
}
OrderService
package in.demo.order.service;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import in.demo.order.replicadao.IOrderRequestRepositoryForReplica;
import in.demo.order.dao.IOrderRequestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
#Transactional(rollbackFor = Exception.class)
public class OrderService {
#Autowired
private IOrderRequestRepositoryForMain orderRequestRepositoryForMain;
#Autowired
private IOrderRequestRepositoryForReplica orderRequestRepositoryForReplica;
public CustomerVisitsResponse getTotalCustomerVisitsForMonthForReplicaDataSource(Long customerId) {
List<Integer> statusIdList= new ArrayList<>();
CustomerVisitsResponse response= new CustomerVisitsResponse();
statusIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
List<Integer> sellerIdList= new ArrayList<>();
sellerIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
Date date = new Date();
String month= dateFormat.format(date)+"%";
try {
List<in.demo.order.replicadao.model.OrderEntity> orders =
orderRequestRepositoryForReplica.getOrderBycustomerIdAndBdMonth(customerId,statusIdList,month,sellerIdList);
if(orders!=null && !orders.isEmpty())
{
double total=0d;
for(in.demo.order.replicadao.model.OrderEntity order:orders)
{
total+=order.getPayableAmount();
}
response.setTotalSpent(total);
response.setTotalVisits((long)(orders.size()));
}
else {
response.setTotalSpent(0d);
response.setTotalVisits(0l);
}
} catch (Exception e) {
logger.info("Error occured while fetching getTotalCustomerVisitsForMonth customerid: " + customerId);
response.setTotalSpent(0d);
response.setTotalVisits(0l);
return response;
}
return response;
}
public CustomerVisitsResponse getTotalCustomerVisitsForMonthForMainDataSource(Long customerId) {
List<Integer> statusIdList= new ArrayList<>();
CustomerVisitsResponse response= new CustomerVisitsResponse();
statusIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
List<Integer> sellerIdList= new ArrayList<>();
sellerIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
Date date = new Date();
String month= dateFormat.format(date)+"%";
try {
List<in.demo.order.dao.model.OrderEntity> orders =
orderRequestRepositoryForMain.getOrderBycustomerIdAndBdMonth(customerId,statusIdList,month,sellerIdList);
if(orders!=null && !orders.isEmpty())
{
double total=0d;
for(in.demo.order.dao.model.OrderEntity order:orders)
{
total+=order.getPayableAmount();
}
response.setTotalSpent(total);
response.setTotalVisits((long)(orders.size()));
}
else {
response.setTotalSpent(0d);
response.setTotalVisits(0l);
}
} catch (Exception e) {
logger.info("Error occured while fetching getTotalCustomerVisitsForMonth customerid: " + customerId);
response.setTotalSpent(0d);
response.setTotalVisits(0l);
return response;
}
return response;
}
}
Repository classes
package in.demo.order.replicadao;
IOrderRequestRepositoryForReplica
package in.demo.order.replicadao;
import in.demo.order.replicadao.model.OrderEntity;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface IOrderRequestRepositoryForReplica extends PagingAndSortingRepository<OrderEntity, Long> {
#Query(nativeQuery = true,
value = "SELECT * FROM orders ...<some query>")
public List<OrderEntity> getOrderBycustomerIdAndBdMonth(
Long customerId, List<Integer> statusIdList, String month, List<Integer> sellerIdList);
}
package in.demo.order.dao;
IOrderRequestRepositoryForMain
package in.demo.order.dao;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import in.demo.order.dao.model.OrderEntity;
#Repository
public interface IOrderRequestRepositoryForMain extends PagingAndSortingRepository<OrderEntity, Long> {
#Query(nativeQuery = true,
value = "SELECT * FROM orders ...<some query>")
public List<OrderEntity> getOrderBycustomerIdAndBdMonth(Long customerId,
List<Integer> statusIdList, String month, List<Integer> sellerIdList);
}
Same Entity in different package with different serialVersionUID
packages are:
package in.demo.order.replicadao.model;
package in.demo.order.dao.model;
OrderEntity
package in.demo.order.replicadao.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "orders")
public class OrderEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4667868888563693990L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String orderId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
Controller class
OrderController
package in.demo.order.controller;
import java.util.List;
import javax.sql.DataSource;
import in.demo.order.service.OrderManagerService;
#RestController
#RequestMapping("/api/order")
public class OrderController {
#Autowired
private OrderManagerService orderManagerService;
#Autowired
private DataSource mainDataSource;
#Autowired
#Qualifier("replicaDataSource")
private DataSource replicaDataSource;
#GetMapping("/replica")
public CustomerVisitsResponse getCustomerVisitResponseForReplica() {
Long customerId = 123L;
return orderManagerService.getCustomerVisitsForMonthForReplicaDataSource(customerId);
}
#GetMapping("/main")
public CustomerVisitsResponse getCustomerVisitResponseForMain() {
Long customerId = 123L;
return orderManagerService.getCustomerVisitsForMonthForMainDataSource(customerId);
}
#GetMapping("/maindatasource")
public String getMainDataSource() {
return mainDataSource.toString();
}
#GetMapping("/replicadatasource")
public String getReplicaDataSource() {
return replicaDataSource.toString();
}
}
I have checked manually in both Database for the query I am running. Data is present. But when I am running from postman to test
for replica, I am getting
Method threw 'org.springframework.dao.InvalidDataAccessResourceUsageException' exception. caused by org.hibernate.exception.SQLGrammarException: could not execute query
for main, I am getting
Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit
When I am using one datasource, the query is working fine.
The issue was with Entity class column name mapping issue, previously we were not mentioning #Column(name="column_name") , once I added the annotation, it started to work. But still I am confused how it is working fine when using single Data source

Not able to mock connection.prepareCall method

I am not able to mock connection.prepareCall("{call myStoreProcedure()}"); call in spring boot project.
Every time i am getting "org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "myStoreProcedure" not found; SQL statement:", because i am using h2 database and there we dont have that procedure. But when i mock it should not call the database it should return the mock value only..but its not happening.
Note : I am getting above exception but my test cases are passing.
Below is the my code snippet :
package com.khan;
import static org.mockito.Mockito.mock;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#PrepareForTest({ DataSource.class, Connection.class, CallableStatement.class })
#SpringBootTest
#PowerMockIgnore({ "javax.management.*", "javax.net.ssl.*", "javax.security.auth.*" })
#TestPropertySource({ "classpath:application.properties" })
public class MainClassTest {
#Autowired
MainClass mainClass;
#Autowired
private DataSource dataSource;
#Test
public void testMethod() throws Exception {
ResultSet resultSet = mock(ResultSet.class);
CallableStatement callableStatement = mock(CallableStatement.class);
Mockito.when(dataSource.getConnection()).thenReturn(connection);
Mockito.when(connection.prepareCall("{ call myprocedure()}")).thenReturn(callableStatement);
Mockito.when(callableStatement.executeQuery()).thenReturn(resultSet);
//Tried below one as well but no luck
//PowerMockito.stub(PowerMockito.method(Connection.class, "prepareCall", Mockito.any())).toReturn(callableStatement);
mainClass.callProcedure("Procedure Name");
}
}
Below is my MainClass :
public class MainClass{
#Autowired
private DataSource dataSource;
public void callProcedure(String storedProcName) throws SQLException {
Connection connection = dataSource.getConnection();
try (CallableStatement cs = connection.prepareCall("{call " + storedProcName + "}");) { // I am getting exception here but test cases are passing
cs.executeQuery();
} catch (SQLException e) {
log.error("Exception occured while execution of stored procedure having storedProcName: {} with reason: {} "
+ e.getMessage(), storedProcName, e);
throw e;
}
}
}
I see lot of issues in your testCase.
No need to load Spring Context for testing this class. Mock should be enough.
In your callProcedure you are passing "Procedure Name" but in mock you expect "{ call myprocedure()}" so that mock will never get triggered.
Your test case passes as you not verifying anything.
Try something like below.
#RunWith(PowerMockRunner.class)
public class MainClassTest {
#InjectMocks
MainClass mainClass;
#Mock
private DataSource dataSource;
#Test
public void testMethod() throws Exception {
//Given
ResultSet resultSet = mock(ResultSet.class);
CallableStatement callableStatement = mock(CallableStatement.class);
Mockito.when(dataSource.getConnection()).thenReturn(connection);
Mockito.when(connection.prepareCall(anyString())).thenReturn(callableStatement);
Mockito.when(callableStatement.executeQuery()).thenReturn(resultSet);
//When
mainClass.callProcedure("Procedure Name");
//Then
verify(dataSource, times(1)).getConnection();
}
}

How to put a lock and transaction on table using spring 4 or above using jdbcTemplate and annotations like #Transactional?

I am trying to put lock on table while writing on table and if something happened in between then roll-back .
Trying to convert below code
lock table test_g1 read;
lock table test_g write;
-- BEGIN;
START TRANSACTION;
insert into test_g1 values(143);
insert into test_g values(145);
select * from test_g1;
select * from test_g;
Rollback;
select * from test_g;
unlock tables;
How to convert above code into #Transactional spring jdbcTemplate code?
#Transactional(rollbackFor={DataAccessException.class})
public void Test(){
jdbcTemplate.execute("insert into test1 (id, nam) values (4, 'A')");
throw new DataAccessException("error") {
};
}
Here i am trying to throw error, so insert statement should rollback but it's not happening .
Thanks
EDIT-1
I am attaching the code , what exactly i am doing
In JdbcDaoImpl.java , i mentioned my problem as a comment above Test() .
App.java
package com.cgiri.javabrains.Spring4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.annotation.Transactional;
public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
App2 app2 = ctx.getBean("app2",App2.class);
app2.call();
}
}
App2.java
package com.cgiri.javabrains.Spring4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
#Component
public class App2 {
#Autowired
private ApplicationContext ctx = null;
JdbcDaoImpl jdbcDaoImpl ;
public void call( )
{
jdbcDaoImpl = ctx.getBean("jdbcDaoImpl",JdbcDaoImpl.class);
System.out.println(jdbcDaoImpl.getCount());
try{
jdbcDaoImpl.Test();
}catch(Exception e)
{
}
System.out.println(jdbcDaoImpl.getCount());
}
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.ctx = context;
}
}
JdbcDaoImpl.java
package com.cgiri.javabrains.Spring4;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
#Component
#Transactional
public class JdbcDaoImpl {
private JdbcTemplate jdbcTemplate;
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int getCount() {
String sql = "SELECT COUNT(*) FROM test1";
// jdbcTemplate.setDataSource(getDataSource());
return jdbcTemplate.queryForObject(sql, Integer.class);
}
public void crateTable() {
String sql = "create table if not exists test1 (id integer, nam char(50))";
jdbcTemplate.execute(sql);
jdbcTemplate.execute("insert into test1 (id, nam) values (1, 'A')");
int count = jdbcTemplate.queryForObject("select count(*) from test1",Integer.class);
System.out.println(count);
}
/**** This is the point where i am trying to rollback insert query ,but it's not happening , instead it's inserting the data into the table and just throwing exception , rollback is not happeneing ****/
#Transactional(rollbackFor={DataAccessException.class})
public void Test(){
jdbcTemplate.execute("insert into test1 (id, nam) values (4, 'A')");
throw new DataAccessException("error") {
};
}
}
AppConfig.java
package com.cgiri.javabrains.Spring4;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionTemplate;
#Configuration
#ComponentScan({ "com.cgiri.javabrains.Spring4" })
#PropertySource("classpath:db.properties")
public class AppConfig {
private JdbcTemplate jdbcTemplate;
private TransactionTemplate transactionTemplate;
#Autowired
private Environment env;
#Bean
public BasicDataSource getBasicDataSource()
{
BasicDataSource dao = new BasicDataSource();
dao.setDriverClassName(env.getProperty("db.driverClassName"));
dao.setUrl(env.getProperty("db.url"));
dao.setUsername(env.getProperty("db.userName"));
dao.setPassword(env.getProperty("db.password"));
dao.setInitialSize(2);
dao.setMaxActive(5);
return dao;
}
#Bean
public DataSourceTransactionManager getTransactionManager(BasicDataSource dataSource) {
DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource);
return manager;
}
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
And for locking the table during DML query, if 2 or more people are updating simultaneously on table , this locking mechanism is taken care by mysql server or we have to configure separately for that the way we are doing for transactions ?
Thanks
If you don't want to use #Transactional then you could try to use TransactionTemplate and something like this:
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
#Component
public SimpleDao {
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private TransactionTemplate transactionTemplate;
private void executeTransactionWithoutResult(DbTransactionTask dbTask) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
dbTask.executeTask();
}
});
}
public void test() {
DbTransactionTask dbTask = new DbTransactionTask() {
#Override
public void executeTask() {
try {
jdbcTemplate.execute("LOCK TABLES Entry WRITE;");
jdbcTemplate.execute("...");
jdbcTemplate.execute("...");
jdbcTemplate.execute("UNLOCK TABLES;")
} catch (Exception e) {
// Cause rollback of transaction
throw new RuntimeException("Reverting DB operations: " + e.getClass().getSimpleName() + " - " + e.getMessage(), e);
}
}
};
executeTransactionWithoutResult(dbTask);
}
abstract class DbTransactionTask { public abstract void executeTask(); }
}
EDIT: With #Transactional you could try something like this:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import dao.EntryDao;
#SpringBootApplication
public class SpringTransactional {
private ConfigurableApplicationContext springContext;
#Autowired
private EntryDao dao;
public void init() {
springContext = SpringApplication.run(SpringTransactional.class);
springContext.getAutowireCapableBeanFactory().autowireBean(this);
}
public static void main(String[] args) {
SpringTransactional st = new SpringTransactional();
try {
st.init();
dao.db_transaction_test();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
st.springContext.close();
}
}
}
Where EntryDao is:
package dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* DB creation and schema:
* CREATE DATABASE db_name;
* CREATE USER db_username;
* <p>
* USE db_name;
* GRANT ALL ON db_name.* TO db_username;
* <p>
* SET PASSWORD FOR spz = PASSWORD('username123');
* FLUSH PRIVILEGES;
* <p>
* CREATE TABLE Entry (
* entry_ID INT NOT NULL AUTO_INCREMENT,
* name TEXT NOT NULL,
* <p>
* PRIMARY KEY (entry_ID)
* );
*/
#Component
public class EntryDao {
/**
* application.properties:
* spring.datasource.driver-class-name = com.mysql.jdbc.Driver
* spring.datasource.url = jdbc:mysql://localhost:3306/db_name?useSSL=false&serverTimezone=UTC
* spring.datasource.username = db_username
* spring.datasource.password = username123
*/
#Autowired
private JdbcTemplate jdbcTemplate;
#Transactional
public void db_transaction_test() {
jdbcTemplate.execute("LOCK TABLES Entry WRITE;");
for (int i = 0; i < 10; i++) {
try {
int entry_name = getEntryId("entry_" + i);
System.out.println("Created entry id=" + entry_name);
} catch (EntryDao.DaoException e) {
e.printStackTrace();
}
if (i == 5) {
throw new RuntimeException("Testing data upload procedure break.");
}
}
jdbcTemplate.execute("UNLOCK TABLES;")
}
public int getEntryId(String entryName) throws DaoException {
List<DbEntry> dbEntries = retrieveEntriesFor(entryName);
if (dbEntries.size() == 1) {
return dbEntries.get(0).getEntry_ID();
} else if (dbEntries.size() == 0) {
String sqlInsert = "INSERT INTO Entry (name) VALUES (?)";
jdbcTemplate.update(sqlInsert, entryName);
dbEntries = retrieveEntriesFor(entryName);
if (dbEntries.size() == 1) {
return dbEntries.get(0).getEntry_ID();
} else {
throw new DaoException("Invalid results amount received after creating new (" + dbEntries.size() + ") when getting entry for name: " + entryName);
}
} else {
throw new DaoException("Invalid results amount received (" + dbEntries.size() + ") when getting entry for name: " + entryName);
}
}
private List<DbEntry> retrieveEntriesFor(String entryName) {
return jdbcTemplate.query("SELECT * FROM Entry WHERE name=?;", (ResultSet result, int rowNum) -> unMarshal(result), entryName);
}
private DbEntry unMarshal(ResultSet result) throws SQLException {
DbEntry dbEntry = new DbEntry();
dbEntry.setEntry_ID(result.getInt("entry_ID"));
dbEntry.setName(result.getString("name"));
return dbEntry;
}
public class DbEntry {
private int entry_ID;
private String name;
int getEntry_ID() { return entry_ID; }
void setEntry_ID(int entry_ID) { this.entry_ID = entry_ID; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public class DaoException extends Throwable { DaoException(String err_msg) { super(err_msg); } }
}

why #autowired doos not instanciate my field?

I'm using Spring boot annotation style, and I don't understand after several searches, why the annotated field returns null.
Please below my java code:
package app.ui;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
#Service
public class MyFrame extends JFrame {
private JMenu fileMenu;
private JMenuBar menuBar;
private JMenuItem openMenuItem;
#Autowired
MyDialog myDialog;
#Autowired
JdbcTemplate jdbcTemplate;
public MyFrame() {
initComponents();
setVisible(true);
}
private void initComponents() {
jdbcTemplate.toString();
this.setTitle("Vue de ma fenĂȘtre");
this.setSize(new Dimension(300, 150));
this.setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.getContentPane().setLayout(new FlowLayout());
menuBar = new JMenuBar();
fileMenu = new JMenu();
openMenuItem = new JMenuItem();
fileMenu.setText("File");
openMenuItem.setText("Inscription");
openMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
myDialog.setVisible(true);
}
});
fileMenu.add(openMenuItem);
menuBar.add(fileMenu);
setJMenuBar(menuBar);
//
final JButton cmd1 = new JButton("Créer Table");
getContentPane().add(cmd1);
cmd1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jdbcTemplate.execute("DROP TABLE customers IF EXISTS");
jdbcTemplate.execute(
"CREATE TABLE customer(id bigint(11), nom VARCHAR(55), prenom VARCHAR(55), dnaiss date)");
cmd1.setEnabled(false);
}
});
//
in this sample, jdbcTemplate.toString() returns null, and I can't understand why, because it works below in the action Performed method
Thank you for Help.
this is the way Java initializes class , first constructor got executed later class variables got initialized . untill and unless variables are part of static block .same logic is followed by spring as well .
in your example jdbcTemplate is a class variable, jdbcTemplate.toString(); is called via default constructor , while actionperformed is called on instance of MyFrame .
to know more about class initialization please check below link
http://www.javaworld.com/article/2075796/java-platform/java-101--class-and-object-initialization.html?nsdr=true

Resources