Recently in a interview, It was asked from me that is it possible to have Spring Application or Hibernate Application without XML configuration..?
So what could be the best answer of it, Please explain.
Yes you can, e.g:-> Account
#Entity
public class Account {
#Id
#GeneratedValue
private Long id;
#Temporal(TemporalType.DATE)
private Data data;
private Long accountNumber;
private String owner;
private double balance;
public Long getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(Long accountNumber) {
this.accountNumber = accountNumber;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
#Override
public String toString() {
return "Account{" +
"accountNumber=" + accountNumber +
", owner='" + owner + '\'' +
", balance=" + balance +
'}';
}
}
Dao:
#Repository
public class AccountDao {
#PersistenceContext
EntityManager entityManager;
#Transactional
public void save(Account account) {
entityManager.persist(account);
}
protected Account getByKey(Long key) {
return (Account) entityManager.find(Account.class, key);
}
}
Configuration->
#Configuration
#EnableTransactionManagement
#ComponentScan("your scan package path")
public class AppConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/your_data_base_name");
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
driverManagerDataSource.setPassword("password");
return driverManagerDataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
localContainerEntityManagerFactoryBean.setDataSource(dataSource());
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
localContainerEntityManagerFactoryBean.setJpaProperties(additionalProperties());
localContainerEntityManagerFactoryBean.setPackagesToScan("entity_package_name");
return localContainerEntityManagerFactoryBean;
}
#Bean
public JpaVendorAdapter getHibernateJpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(true);
hibernateJpaVendorAdapter.setGenerateDdl(true);
return hibernateJpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
return new JpaTransactionManager(entityManagerFactory().getObject());
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.hbm2ddl.auto", "create");
properties.put("hibernate_show_sql", true);
return properties;
}
}
Test class :
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Account account = new Account();
account.setAccountNumber(123L);
account.setBalance(100056.5);
AccountService accountService = applicationContext.getBean(AccountService.class);
accountService.save(account);
}
}
Related
I am using AbstractRoutingDataSource so as to have multiple data base connections but, even after changing the contextHoler the database remains same
in a single API call it works perfectly fine but if i change the datasource within the same api call it doesn't change the datasource. if i have 2 api calls with different contextHolder it would work
#GetMapping("/getdata2")
public ClaimAmountAndTCD getDetails2() {
ClaimAmountAndTCD claimAmountAndTCD2 = serviceCls.getBook2Data();
System.out.println(claimAmountAndTCD2);
return claimAmountAndTCD2;
}
#GetMapping("/getdata")
public ClaimAmountAndTCD getDetails() {
ClaimAmountAndTCD claimAmountAndTCD = serviceCls.getBook1Data();
// ClaimAmountAndTCD claimAmountAndTCD2 = serviceCls.getBook2Data();
System.out.println(claimAmountAndTCD);
return claimAmountAndTCD;
}
below is my database config code
#Configuration
#Profile("dev")
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "as400EntityManager", transactionManagerRef = "as400TransactionManager", basePackages = {
"com.spring.demo.repository" })
public class DevDataSourceConfig {
#Value("${db.gmrp.sxcd1.servername}")
private String servername;
#Value("${db.gmrp.sxcd1.username}")
private String username;
#Value("${db.gmrp.sxcd1.password}")
private String password;
#Value("${db.gmrp.sxcd1.libraries}")
private String libraries;
#Value("${db.naming}")
private String dbNaming;
#Value("${db.driver}")
private String driver;
#Value("${db.isolation}")
private String dbIsolation;
#Bean
public AS400JDBCDataSource dataSourceDevSXCD1() {
AS400JDBCDataSource as400DataSource = new AS400JDBCDataSource();
System.out.println(driver + " " + libraries + " " + username + " " + password);
as400DataSource.setDriver(driver);
as400DataSource.setLibraries(libraries);
as400DataSource.setServerName(servername);
as400DataSource.setNaming(dbNaming);
as400DataSource.setTransactionIsolation(dbIsolation);
if (password != null && !password.isEmpty() && password.trim().length() > 0) {
as400DataSource.setUser(username);
as400DataSource.setPassword(password);
}
return as400DataSource;
}
#Bean(name = "as400dev")
#Primary
public DataSource dataSource() {
AbstractRoutingDataSource dataSource = new RoutingDataSource();
Map<Object, Object> resolvedDataSources = new HashMap<>();
resolvedDataSources.put(DbType.DEVSXCD1, dataSourceDevSXCD1());
dataSource.setDefaultTargetDataSource(dataSourceDevSXCD1()); // default
dataSource.setTargetDataSources(resolvedDataSources);
return dataSource;
}
#Bean(name = "as400EntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean as400DevEntityManager(EntityManagerFactoryBuilder builder,
#Qualifier("as400dev") DataSource as400DataSource) {
return builder.dataSource(as400DataSource).packages("com.spring.demo.entity").build();
}
#Bean(name = "as400TransactionManager")
public PlatformTransactionManager as400DevTransactionManager(
#Qualifier("as400EntityManager") EntityManagerFactory entityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManager);
return transactionManager;
}
}
DbContextHoler class
package com.spring.demo.config;
public final class DbContextHolder {
private DbContextHolder() {
// default constructor
}
private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();
// set the data source
public static void setDbType(DbType dbType) {
if (dbType == null) {
throw new NullPointerException();
}
contextHolder.set(dbType);
}
// get the current data source in use
public static DbType getDbType() {
return contextHolder.get();
}
// clear data source
public static void clearDbType() {
contextHolder.remove();
}
}
AbstractRoutingDataSource
package com.spring.demo.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class RoutingDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
I went through the link - https://github.com/spring-projects/spring-batch/blob/master/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/ClassifierCompositeItemProcessorTests.java, but did not strike much out of it.
I am trying to replace ETL Informatica mapping logic into the Batch. I am looking to separate out Status=I and Status=U into separate (Individual) processor and then further perform lookup and massage the data and then write those records directly into the table for Status=I and for status=U, perform another complex logic (like lookups, massaging and match and merge logic) and then upsert those records again into the same table.
I've tried to do POC, where I am looking to segregate the records in the processor
CustomerClassifier.java
public class CustomerClassifier implements Classifier<Customer, ItemProcessor<Customer, Customer>> {
private ItemProcessor<Customer, Customer> insertCustomerProcessor;
private ItemProcessor<Customer, Customer> updateCustomerProcessor;
public CustomerClassifier(ItemProcessor<Customer, Customer> evenCustomerProcessor, ItemProcessor<Customer, Customer> oddCustomerProcessor) {
this.insertCustomerProcessor= insertCustomerProcessor;
this.updateCustomerProcessor= updateCustomerProcessor;
}
#Override
public ItemProcessor<Customer, Customer> classify(Customer customer) {
return customer.getStatus().equals("I") ? insertCustomerProcessor : updateCustomerProcessor;
}
}
OddCustomerProcessor.java
public class OddCustomerProcessor implements ItemProcessor<Customer, Customer> {
#Override
public Customer process(Customer item) throws Exception {
Customer customer = new Customer();
// Perform some msaaging and lookups here
customer.setId(item.getId());
customer.setFirstName(item.getFirstName());
customer.setLastName(item.getLastName());
customer.setBirthdate(item.getBirthdate());
customer.setStatus(item.getStatus());
return customer;
}
}
EvenCustomerProcessor.java
public class EvenCustomerProcessor implements ItemProcessor<Customer, Customer> {
#Override
public Customer process(Customer item) throws Exception {
Customer customer = new Customer();
// Perform some msaaging and lookups here
customer.setId(item.getId());
customer.setFirstName(item.getFirstName());
customer.setLastName(item.getLastName());
customer.setBirthdate(item.getBirthdate());
customer.setStatus(item.getStatus());
return customer;
}
}
CustomLineAggregator.java
public class CustomLineAggregator implements LineAggregator<Customer> {
private ObjectMapper objectMapper = new ObjectMapper();
#Override
public String aggregate(Customer item) {
try {
return objectMapper.writeValueAsString(item);
} catch (Exception e) {
throw new RuntimeException("Unable to serialize Customer", e);
}
}
}
Customer.java
#Data
#AllArgsConstructor
#Builder
#NoArgsConstructor
public class Customer {
private Long id;
private String firstName;
private String lastName;
private String birthdate;
private String status;
}
Error-
The method setClassifier(Classifier<? super Customer,ItemProcessor<?,? extends Customer>>) in the type ClassifierCompositeItemProcessor<Customer,Customer> is not applicable for the
arguments (CustomerClassifier)
Configuration
#Configuration
public class JobConfiguration {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private DataSource dataSource;
#Bean
public JdbcPagingItemReader<Customer> customerPagingItemReader(){
// reading database records using JDBC in a paging fashion
JdbcPagingItemReader<Customer> reader = new JdbcPagingItemReader<>();
reader.setDataSource(this.dataSource);
reader.setFetchSize(1000);
reader.setRowMapper(new CustomerRowMapper());
// Sort Keys
Map<String, Order> sortKeys = new HashMap<>();
sortKeys.put("id", Order.ASCENDING);
// MySQL implementation of a PagingQueryProvider using database specific features.
MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
queryProvider.setSelectClause("id, firstName, lastName, birthdate");
queryProvider.setFromClause("from customer");
queryProvider.setSortKeys(sortKeys);
reader.setQueryProvider(queryProvider);
return reader;
}
#Bean
public EvenCustomerProcessor evenCustomerProcessor() {
return new EvenCustomerProcessor();
}
#Bean
public OddCustomerProcessor oddCustomerProcessor() {
return new OddCustomerProcessor();
}
#Bean
public JdbcBatchItemWriter<Customer> customerItemWriter(){
JdbcBatchItemWriter<Customer> batchItemWriter = new JdbcBatchItemWriter<>();
batchItemWriter.setDataSource(dataSource);
batchItemWriter.setSql(""); // Query Goes here
return batchItemWriter;
}
#Bean
public ClassifierCompositeItemProcessor<Customer, Customer> classifierCustomerCompositeItemProcessor() throws Exception{
ClassifierCompositeItemProcessor<Customer, Customer> itemProcessor = new ClassifierCompositeItemProcessor<>();
itemProcessor.setClassifier(new CustomerClassifier(evenCustomerProcessor(), oddCustomerProcessor()));
}
#Bean
public Step step1() throws Exception {
return stepBuilderFactory.get("step1")
.<Customer, Customer> chunk(10)
.reader(customerPagingItemReader())
.processor(classifierCustomerCompositeItemProcessor())
.writer(customerItemWriter())
.build();
}
#Bean
public Job job() throws Exception {
return jobBuilderFactory.get("job")
.start(step1())
.build();
}
}
You can remove the CustomerClassifier and define the composite item processor as follows:
#Bean
public ClassifierCompositeItemProcessor<Customer, Customer> classifierCustomerCompositeItemProcessor(
EvenCustomerProcessor evenCustomerProcessor,
OddCustomerProcessor oddCustomerProcessor
) {
ClassifierCompositeItemProcessor<Customer, Customer> itemProcessor = new ClassifierCompositeItemProcessor<>();
itemProcessor.setClassifier(new Classifier<Customer, ItemProcessor<?, ? extends Customer>>() {
#Override
public ItemProcessor<?, ? extends Customer> classify(Customer customer) {
return customer.getStatus().equals("I") ? evenCustomerProcessor : oddCustomerProcessor;
}
});
return itemProcessor;
}
Then update your step definition as follows:
#Bean
public Step step1() throws Exception {
return stepBuilderFactory.get("step1")
.<Customer, Customer> chunk(10)
.reader(customerPagingItemReader())
.processor(classifierCustomerCompositeItemProcessor(evenCustomerProcessor(), oddCustomerProcessor()))
.writer(customerItemWriter())
.build();
}
When trying to implement a DistributedCommandBus using Spring Cloud, I am getting the following error intermittently. I have reason to believe that there is some sort of race condition happening with the auto-configuration of my aggregate root class, its command handlers, and my configuration bean class.
org.axonframework.commandhandling.NoHandlerForCommandException: No
node known to accept.
I am using Axon Version 3.3.5.
Here is my configurations class:
#Configuration
#AutoConfigureBefore(CustomerAggregate.class)
public class AxonConfig {
#Value("${mongo.servers}")
private String mongoUrl;
#Value("${mongo.db}")
private String mongoDbName;
#Value("${axon.events.collection.name}")
private String eventsCollectionName;
#Value("${axon.snapshot.collection.name}")
private String snapshotCollectionName;
#Value("${axon.saga.collection.name}")
private String sagaCollectionName;
#Bean
#Primary
public CommandGateway commandGateway(#Qualifier("distributedBus") DistributedCommandBus commandBus) throws Exception {
return new DefaultCommandGateway(commandBus, new IntervalRetryScheduler(Executors.newSingleThreadScheduledExecutor(), 1000, 10));
}
#Bean
#Primary
#Qualifier("springCloudRouter")
public CommandRouter springCloudCommandRouter(DiscoveryClient client, Registration localServiceInstance) {
return new SpringCloudCommandRouter(client, localServiceInstance, new AnnotationRoutingStrategy());
}
#Bean
#Primary
#Qualifier("springCloudConnector")
public SpringHttpCommandBusConnector connector() {
return new SpringHttpCommandBusConnector(new SimpleCommandBus(), new RestTemplate(), new JacksonSerializer());
}
#Bean
#Primary
#Qualifier("distributedBus")
public DistributedCommandBus springCloudDistributedCommandBus(#Qualifier("springCloudRouter") CommandRouter router) {
return new DistributedCommandBus(router, connector());
}
#Bean
#Primary
public AggregateFactory<CustomerAggregate> aggregateFactory(){
return new GenericAggregateFactory<CustomerAggregate>(CustomerAggregate.class);
}
#Bean
#Primary
public EventCountSnapshotTriggerDefinition countSnapshotTriggerDefinition(){
return new EventCountSnapshotTriggerDefinition(snapShotter(), 3);
}
#Bean
#Primary
public Snapshotter snapShotter(){
return new AggregateSnapshotter(eventStore(), aggregateFactory());
}
#Bean
#Primary
public EventSourcingRepository<CustomerAggregate> customerAggregateRepository(){
return new EventSourcingRepository<>(aggregateFactory(), eventStore(), countSnapshotTriggerDefinition());
}
#Bean(name = "axonMongoTemplate")
public MongoTemplate axonMongoTemplate() {
return new DefaultMongoTemplate(mongoClient(), mongoDbName)
.withDomainEventsCollection(eventsCollectionName)
.withSnapshotCollection(snapshotCollectionName)
.withSagasCollection(sagaCollectionName);
}
#Bean
public MongoClient mongoClient() {
MongoFactory mongoFactory = new MongoFactory();
mongoFactory.setMongoAddresses(Arrays.asList(new ServerAddress(mongoUrl)));
return mongoFactory.createMongo();
}
#Bean
#Primary
public MongoEventStorageEngine engine() {
return new MongoEventStorageEngine(new JacksonSerializer(), null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
}
#Bean
#Primary
public EventStore eventStore() {
return new EmbeddedEventStore(engine());
}
}
And here is my aggregate class with command handlers:
#Aggregate(repository = "customerAggregateRepository")
public class CustomerAggregate {
Logger logger = LoggerFactory.getLogger(this.getClass());
#AggregateIdentifier
private String id;
private String firstName;
private String lastName;
private String email;
private CustomerAggregate() {}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
#CommandHandler
public CustomerAggregate(CreateCustomer cmd) {
logger.debug("Received creation command: " + cmd.toString());
apply(new CustomerCreated(cmd.getId(),cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
}
#CommandHandler
public void on(UpdateCustomer cmd) {
logger.debug("Received update command: " + cmd.toString());
apply(new CustomerUpdated(this.id,cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
}
#CommandHandler
public void on(UpdateCustomerEmail cmd) {
logger.debug("Received update command for existing customer: " + cmd.toString());
apply(new CustomerUpdated(cmd.getId(), this.firstName, this.lastName, cmd.getEmail()));
}
// Various event handlers...
}
Any help is much appreciated.
What we are doing: Update subscription for received business ID.
We receive business ID on activeMQ queue.
JMSListener picked business ID, find the all associated subscription for received business.
Process all subscription identify who need update (can be zero or more than one).
For each subscription we call service method udate(SubscriptionDTO subscriptionDTO). Find the subscription entity object. This update method update the entity object using dto object. Then we call flush method on it. Note : Update method is annotated with #transactional. Call flush method from service#udpate(dto) method.
We observed different behavior in windows vs Linux. On windows it worked well but on Linux we are getting failure after execution of flush method– javax.persistence.TransactionRequiredException: no transaction is in progress
We tried adding #Transactional on JMSListner but got same error on Linux. But when we tried without call of flush method error gone but no update happened. Subscription data is same as before.
Not sure how good problem was explained above.
Looking for guidance, much appreciated for response.
JPA Configuration
package edu.learn.config;
#Configuration
#EnableJpaRepositories(basePackages = "edu.learn.repositories", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
#EnableTransactionManagement
public class JpaConfiguration
{
private final String DEFAULT_TEST_QUERY = "SELECT 1";
#Autowired
private Environment environment;
#Value("${datasource.maxPoolSize:10}")
private int maxPoolSize;
/*
* Populate SpringBoot DataSourceProperties object directly from
* application.yml based on prefix.Thanks to .yml, Hierachical data is
* mapped out of the box with matching-name properties of
* DataSourceProperties object].
*/
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource")
public DataSourceProperties dataSourceProperties()
{
return new DataSourceProperties();
}
/*
* Configure HikariCP pooled DataSource.
*/
#Bean
public DataSource dataSource()
{
DataSourceProperties dataSourceProperties = dataSourceProperties();
HikariDataSource dataSource = (HikariDataSource) DataSourceBuilder.create()
.type(com.zaxxer.hikari.HikariDataSource.class).username(dataSourceProperties.getUsername())
.password(dataSourceProperties.getPassword()).build();
dataSource.setMaximumPoolSize(PropertyUtil.getMaxPoolSize(environment));
dataSource.setInitializationFailFast(PropertyUtil.getInitializationFailFast(environment));
dataSource.setMinimumIdle(PropertyUtil.getMinIdle(environment));
dataSource.setConnectionTestQuery(DEFAULT_TEST_QUERY);
dataSource.setConnectionTimeout(PropertyUtil.getConnectionTimeout(environment));
dataSource.setIdleTimeout(PropertyUtil.getIdleTimeout(environment));
dataSource.setMaxLifetime(PropertyUtil.getMaxLifetime(environment));
dataSource.setDataSourceClassName(PropertyUtil.getDataSourceClassName(environment));
if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals(PropertyUtil.getDataSourceClassName(environment)))
{
dataSource.addDataSourceProperty("databaseName", PropertyUtil.defaultSchema(environment));
dataSource.addDataSourceProperty("cachePrepStmts", PropertyUtil.getCachePrepStmts(environment));
dataSource.addDataSourceProperty("prepStmtCacheSize", PropertyUtil.getPrepStmtCacheSize(environment));
dataSource.addDataSourceProperty(
"prepStmtCacheSqlLimit", PropertyUtil.getPrepStmtCacheSqlLimit(environment)
);
dataSource.addDataSourceProperty("useServerPrepStmts", PropertyUtil.getUseServerPrepStmts(environment));
dataSource.addDataSourceProperty("serverName", PropertyUtil.dbServerName(environment));
dataSource.addDataSourceProperty("portNumber", PropertyUtil.portNumber(environment));
}
return dataSource;
}
/*
* Entity Manager Factory setup.
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException
{
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[]
{
"edu.learn.model"
});
factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
factoryBean.setJpaProperties(jpaProperties());
return factoryBean;
}
/*
* Provider specific adapter.
*/
#Bean
public JpaVendorAdapter jpaVendorAdapter()
{
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
return hibernateJpaVendorAdapter;
}
/*
* Here you can specify any provider specific properties.
*/
private Properties jpaProperties()
{
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.globally_quoted_identifiers", "true");
properties.put("hibernate.hbm2ddl.auto", "validates");
properties.put("ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("show_sql", "false");
properties.put("format_sql", "true");
return properties;
}
#Bean
#Autowired
public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
{
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(emf);
return txManager;
}
static class PropertyUtil
{
final static String DEFAULT_CHARACTER_ENCODING = "utf-8";
final static String DEFAULT_DATASOURCE_CLASS = "com.mysql.jdbc.Driver";
public static boolean getCachePrepStmts(final Environment environment)
{
String cachePrepStmts = environment.getProperty("spring.datasource.hikari.cachePrepStmts");
if ("false".equalsIgnoreCase(cachePrepStmts))
{
return false;
}
return true;
}
public static int getPrepStmtCacheSize(final Environment environment)
{
String prepStmtCacheSize = environment.getProperty("spring.datasource.hikari.prepStmtCacheSize");
try
{
return Integer.parseInt(prepStmtCacheSize);
}
catch(Exception e)
{
return 250;
}
}
public static int getPrepStmtCacheSqlLimit(final Environment environment)
{
String prepStmtCacheSqlLimit = environment.getProperty("spring.datasource.hikari.prepStmtCacheSqlLimit");
try
{
return Integer.parseInt(prepStmtCacheSqlLimit);
}
catch(Exception e)
{
return 2048;
}
}
public static boolean getUseServerPrepStmts(final Environment environment)
{
String useServerPrepStmts = environment.getProperty("spring.datasource.hikari.useServerPrepStmts");
if ("false".equalsIgnoreCase(useServerPrepStmts))
{
return false;
}
return true;
}
public static boolean getInitializationFailFast(final Environment environment)
{
String initializationFailFast = environment.getProperty("spring.datasource.hikari.initializationFailFast");
if ("false".equalsIgnoreCase(initializationFailFast))
{
return false;
}
return true;
}
public static long getConnectionTimeout(final Environment environment)
{
String connectionTimeout = environment.getProperty("spring.datasource.hikari.connectionTimeout");
try
{
return Integer.parseInt(connectionTimeout);
}
catch(Exception e)
{
return TimeUnit.SECONDS.toMillis(60);
}
}
public static long getIdleTimeout(final Environment environment)
{
String idleTimeout = environment.getProperty("spring.datasource.hikari.idleTimeout");
try
{
return Integer.parseInt(idleTimeout);
}
catch(Exception e)
{
return TimeUnit.SECONDS.toMillis(60);
}
}
public static long getMaxLifetime(final Environment environment)
{
String maxLifetime = environment.getProperty("spring.datasource.hikari.maxLifetime");
try
{
return Integer.parseInt(maxLifetime);
}
catch(Exception e)
{
return TimeUnit.SECONDS.toMillis(90);
}
}
public static int getMinIdle(final Environment environment)
{
String minIdle = environment.getProperty("spring.datasource.hikari.minIdle");
try
{
return Integer.parseInt(minIdle);
}
catch(Exception e)
{
return 5;
}
}
public static int getMaxPoolSize(final Environment environment)
{
String maxPoolSize = environment.getProperty("spring.datasource.maxPoolSize");
try
{
return Integer.parseInt(maxPoolSize);
}
catch(Exception e)
{
return 25;
}
}
public static String getDataSourceClassName(final Environment environment)
{
String dataSourceClassName = environment.getProperty("spring.datasource.dataSourceClassName");
if (dataSourceClassName != null && "".equalsIgnoreCase(dataSourceClassName.trim()) == false)
{
return dataSourceClassName;
}
return DEFAULT_DATASOURCE_CLASS;
}
public static String getCharacterEncoding(final Environment environment)
{
String characterEncoding = environment.getProperty("spring.datasource.characterEncoding");
if (characterEncoding != null && "".equalsIgnoreCase(characterEncoding.trim()) == false)
{
return characterEncoding;
}
return DEFAULT_CHARACTER_ENCODING;
}
public static boolean getUniCode(final Environment environment)
{
String useUnicode = environment.getProperty("spring.datasource.useUnicode");
if ("false".equalsIgnoreCase(useUnicode))
{
return false;
}
return true;
}
public static String showSQL(final Environment environment)
{
String showSQL = environment.getProperty("spring.datasource.hibernate.showSQL");
if ("false".equalsIgnoreCase(showSQL))
{
return "false";
}
return "true";
}
public static String formatSQL(final Environment environment)
{
String formatSQL = environment.getProperty("spring.datasource.hibernate.format_sql");
if ("false".equalsIgnoreCase(formatSQL))
{
return "false";
}
return "true";
}
public static String dbServerName(final Environment environment)
{
String dbServerName = environment.getProperty("spring.datasource.serverName");
if (dbServerName == null || "".equalsIgnoreCase(dbServerName.trim()))
{
return "localhost";
}
return dbServerName;
}
public static int portNumber(final Environment environment)
{
String portNumber = environment.getProperty("spring.datasource.portNumber");
try
{
return Integer.parseInt(portNumber);
}
catch(Exception e)
{
return 3306;
}
}
public static String defaultSchema(final Environment environment)
{
String defaultSchema = environment.getProperty("spring.datasource.defaultSchema");
if (defaultSchema == null || "".equalsIgnoreCase(defaultSchema.trim()))
{
return "subscription";
}
return defaultSchema;
}
}
}
JMS Configuration
#EnableJms
#Configuration
public class JmsConfiguration
{
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer)
{
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
}
Startup class
#Import({JpaConfiguration.class, JmsConfiguration.class})
#SpringBootApplication(scanBasePackages={"edu.learn"})
public class SubscriptionApiApplication
{
public static void main(String[] args)
{
SpringApplication.run(SubscriptionApiApplication.class, args);
}
}
JMS queue listener
#Component
public class OrderTransactionReceiver
{
private static final Logger LOGGER = LoggerFactory.getLogger(OrderTransactionReceiver.class);
#Autowired
private SubscriptionService subsriptionService;
#JmsListener(destination = "OrderTransactionQueue", containerFactory = "myFactory")
public void receiveMessage(String businessID)
{
List<SubscriptionDTO> subscriptions = subsriptionService.findByBusinessID(businessID);
for (SubscriptionDTO subscription : subscriptions)
{
subscription.setStatus("active");
subsriptionService.update(subscription);
}
}
}
Service
#Service
class RepositorySubscriptionService implements SubscriptionService
{
private static final Logger LOGGER = LoggerFactory.getLogger(RepositorySubscriptionService.class);
private final SubscriptionRepository repository;
#Transactional
#Override
public SubscriptionDTO update(SubscriptionDTO updatedSubscriptionEntry)
{
LOGGER.info(
"Updating the information of a subscription entry by using information: {}", updatedSubscriptionEntry
);
SubscriptionEntity updated = findSubscriptionEntryById(updatedSubscriptionEntry.getId());
updated.update(updatedSubscriptionEntry.getStatus());
// We need to flush the changes or otherwise the returned object
// doesn't contain the updated audit information.
repository.flush();
LOGGER.info("Updated the information of the subscription entry: {}", updated);
return SubscriptionMapper.mapEntityIntoDTO(updated);
}
}
Repostiory
public interface SubscriptionRepository extends
Repository<SubscriptionEntity, String>,
JpaSpecificationExecutor<SubscriptionEntity>
{
void delete(SubscriptionEntity deleted);
List<SubscriptionEntity> findAll();
Optional<SubscriptionEntity> findOne(String id);
List<SubscriptionEntity> findByBusinessID(final String businessID);
void flush();
SubscriptionEntity save(SubscriptionEntity persisted);
}
JTA transaction configuration
#Configuration
#EnableJpaRepositories(basePackages = "edu.learn.repositories", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
#EnableTransactionManagement
public class JpaConfiguration
{
private final String DEFAULT_TEST_QUERY = "SELECT 1";
#Autowired
private Environment environment;
#Value("${datasource.maxPoolSize:10}")
private int maxPoolSize;
/*
* Populate SpringBoot DataSourceProperties object directly from
* application.yml based on prefix.Thanks to .yml, Hierachical data is
* mapped out of the box with matching-name properties of
* DataSourceProperties object].
*/
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource")
public DataSourceProperties dataSourceProperties()
{
return new DataSourceProperties();
}
/*
* Configure HikariCP pooled DataSource.
*/
#Bean(initMethod = "init", destroyMethod = "close")
public DataSource dataSource()
{
DataSourceProperties dataSourceProperties = dataSourceProperties();
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setServerName(PropertyUtil.dbServerName(environment));
mysqlXaDataSource.setPort(PropertyUtil.portNumber(environment));
mysqlXaDataSource.setUser(dataSourceProperties.getUsername());
mysqlXaDataSource.setPassword(dataSourceProperties.getPassword());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setDatabaseName(PropertyUtil.defaultSchema(environment));
mysqlXaDataSource.setCachePreparedStatements(PropertyUtil.getCachePrepStmts(environment));
try
{
mysqlXaDataSource.setPrepStmtCacheSqlLimit(PropertyUtil.getPrepStmtCacheSqlLimit(environment));
mysqlXaDataSource.setPrepStmtCacheSize(PropertyUtil.getPrepStmtCacheSize(environment));
}
catch (SQLException e)
{
e.printStackTrace();
}
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("xaSubscription");
xaDataSource.setTestQuery(DEFAULT_TEST_QUERY);
xaDataSource.setMaxPoolSize(PropertyUtil.getMaxPoolSize(environment));
xaDataSource.setMaxIdleTime(PropertyUtil.getMinIdle(environment));
xaDataSource.setMaxLifetime((int)PropertyUtil.getMaxLifetime(environment));
xaDataSource.setBorrowConnectionTimeout((int)PropertyUtil.getConnectionTimeout(environment));
return xaDataSource;
}
/*
* Entity Manager Factory setup.
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException
{
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[]
{
"edu.learn.model"
});
factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
factoryBean.setJpaProperties(jpaProperties());
return factoryBean;
}
/*
* Provider specific adapter.
*/
#Bean
public JpaVendorAdapter jpaVendorAdapter()
{
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
return hibernateJpaVendorAdapter;
}
/*
* Here you can specify any provider specific properties.
*/
private Properties jpaProperties()
{
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.globally_quoted_identifiers", "true");
properties.put("hibernate.hbm2ddl.auto", "validates");
properties.put("ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("show_sql", "false");
properties.put("format_sql", "true");
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
return properties;
}
#Bean
public UserTransaction userTransaction() throws Throwable
{
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(1000);
return userTransactionImp;
}
#Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable
{
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
AtomikosJtaPlatform.transactionManager = userTransactionManager;
return userTransactionManager;
}
#Bean(name = "transactionManager")
#DependsOn({ "userTransaction", "atomikosTransactionManager" })
public PlatformTransactionManager transactionManager() throws Throwable
{
UserTransaction userTransaction = userTransaction();
AtomikosJtaPlatform.transaction = userTransaction;
TransactionManager atomikosTransactionManager = atomikosTransactionManager();
return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
}
}
public class AtomikosJtaPlatform extends AbstractJtaPlatform
{
private static final long serialVersionUID = 1L;
static TransactionManager transactionManager;
static UserTransaction transaction;
#Override
protected TransactionManager locateTransactionManager()
{
return transactionManager;
}
#Override
protected UserTransaction locateUserTransaction()
{
return transaction;
}
}
I have one issue. I integrate my app with Activiti (in the same DB). When I insert, update or delete my entities (not entities's Activiti) by Dao class have use #Transactional but nothing about is being saved to database with no exception.
Here is my config to integrating:
#Configuration
public class ActivitiEngineConfiguration {
private final Logger log = LoggerFactory.getLogger(ActivitiEngineConfiguration.class);
#Autowired
protected Environment environment;
#Bean
public DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
try {
#SuppressWarnings("unchecked")
Class<? extends Driver> driverClass = (Class<? extends Driver>) Class.forName(environment.getProperty("jdbc.driver", "org.postgresql.Driver"));
ds.setDriverClass(driverClass);
} catch (Exception e) {
log.error("Error loading driver class", e);
}
ds.setUrl(environment.getProperty("spring.datasource.url"));
ds.setUsername(environment.getProperty("spring.datasource.username"));
ds.setPassword(environment.getProperty("spring.datasource.password"));
return ds;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
System.out.println("transactionManager: "+transactionManager);
return transactionManager;
}
#Bean(name="processEngineFactoryBean")
public ProcessEngineFactoryBean processEngineFactoryBean() {
ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean();
factoryBean.setProcessEngineConfiguration(processEngineConfiguration());
return factoryBean;
}
#Bean(name="processEngine")
public ProcessEngine processEngine() {
// Safe to call the getObject() on the #Bean annotated processEngineFactoryBean(), will be
// the fully initialized object instanced from the factory and will NOT be created more than once
try {
return processEngineFactoryBean().getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Bean(name="processEngineConfiguration")
public ProcessEngineConfigurationImpl processEngineConfiguration() {
SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
processEngineConfiguration.setDataSource(dataSource());
processEngineConfiguration.setDatabaseSchemaUpdate(environment.getProperty("engine.schema.update", "true"));
processEngineConfiguration.setTransactionManager(annotationDrivenTransactionManager());
processEngineConfiguration.setJobExecutorActivate(Boolean.valueOf(
environment.getProperty("engine.activate.jobexecutor", "false")));
processEngineConfiguration.setAsyncExecutorEnabled(Boolean.valueOf(
environment.getProperty("engine.asyncexecutor.enabled", "true")));
processEngineConfiguration.setAsyncExecutorActivate(Boolean.valueOf(
environment.getProperty("engine.asyncexecutor.activate", "true")));
processEngineConfiguration.setHistory(environment.getProperty("engine.history.level", "full"));
String mailEnabled = environment.getProperty("engine.email.enabled");
if ("true".equals(mailEnabled)) {
processEngineConfiguration.setMailServerHost(environment.getProperty("engine.email.host"));
int emailPort = 1025;
String emailPortProperty = environment.getProperty("engine.email.port");
if (StringUtils.isNotEmpty(emailPortProperty)) {
emailPort = Integer.valueOf(emailPortProperty);
}
processEngineConfiguration.setMailServerPort(emailPort);
String emailUsernameProperty = environment.getProperty("engine.email.username");
if (StringUtils.isNotEmpty(emailUsernameProperty)) {
processEngineConfiguration.setMailServerUsername(emailUsernameProperty);
}
String emailPasswordProperty = environment.getProperty("engine.email.password");
if (StringUtils.isNotEmpty(emailPasswordProperty)) {
processEngineConfiguration.setMailServerPassword(emailPasswordProperty);
}
}
// List<AbstractFormType> formTypes = new ArrayList<AbstractFormType>();
// formTypes.add(new UserFormType());
// formTypes.add(new ProcessDefinitionFormType());
// formTypes.add(new MonthFormType());
// processEngineConfiguration.setCustomFormTypes(formTypes);
return processEngineConfiguration;
}
#Bean
public RepositoryService repositoryService() {
return processEngine().getRepositoryService();
}
#Bean
public RuntimeService runtimeService() {
return processEngine().getRuntimeService();
}
#Bean
public TaskService taskService() {
return processEngine().getTaskService();
}
#Bean
public HistoryService historyService() {
return processEngine().getHistoryService();
}
#Bean
public FormService formService() {
return processEngine().getFormService();
}
#Bean
public IdentityService identityService() {
return processEngine().getIdentityService();
}
#Bean
public ManagementService managementService() {
return processEngine().getManagementService();
}
}
DAO Layer:
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional
public void save(MyEntity obj) {
sessionFactory.getCurrentSession().saveOrUpdate(loaiDanhMuc);
}
Thank all!
I guess #Transactional is not working in this case
Please check following things below:
Check if <tx:annotation-driven /> is defined in your spring xml file.