How to configure mysql in spring boot with mybatis without using xml? - java

I am using spring boot with mybatis and mysql database in my application, i want to know how to configure database in my application using #configuration annotation.
This is my sample configuration file.
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
#Configuration
public class DatabaseConfig {
#Value("${spring.datasource.driver-class-name}")
private String DB_DRIVER;
#Value("${spring.datasource.username}")
private String DB_USERNAME;
#Value("${spring.datasource.password}")
private String DB_PASSWORD;
#Value("${spring.datasource.url}")
private String DB_URL;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = null;
try {
dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
} catch (Exception e) {
e.getMessage();
}
return dataSource;
}
}

Related

can we create two session factory of same database with different users in spring boot application

I am new to spring boot and I need to use same postgreSQL sql database with two different users in same package in same class
please suggest me the ways which I can do to make it work in my application
I have tried creating two configuration classes and calling session factory in the service class
these are the two configurtion classes
1: Mastercongig file
package com.demo.config;
import java.util.HashMap;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
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;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "masterSessionFactory", transactionManagerRef
= "masterPostgrsTransactionManager", basePackages = {
"com.demo.*" })
public class MasterPostgreSqlConfig {
/*
* #Autowired private EntityManagerFactory entityManagerFactory;
*/
#Value("${spring.database.driverClassName}")
private String driverClassName;
#Value("${spring.datasource.url}")
private String dataSourceUrl;
#Value("${spring.datasource.username}")
private String dataSourceUserName;
#Value("${spring.datasource.password}")
private String dataSourcePassword;
#Value("${spring.jpa.database-platform}")
private String hibernateDialect;
#Bean(name = "masterPostgrsEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean masterSessionFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(masterPostgresqlDataSource());
em.setPackagesToScan(new String[] { "com.demo.entity" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", hibernateDialect);
properties.put("hibernate.physical_naming_strategy",
SpringPhysicalNamingStrategy.class.getName());
properties.put("hibernate.implicit_naming_strategy",
SpringImplicitNamingStrategy.class.getName());
properties.put("hibernate.id.new_generator_mappings", false);
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource masterPostgresqlDataSource() {
DriverManagerDataSource masterdataSource = new DriverManagerDataSource();
masterdataSource.setDriverClassName(driverClassName);
masterdataSource.setUrl(dataSourceUrl);
masterdataSource.setUsername(dataSourceUserName);
masterdataSource.setPassword(dataSourcePassword);
return masterdataSource;
}
#Primary
#Bean(name = "masterPostgrsTransactionManager")
public PlatformTransactionManager masterPostgresTransactionManagerFactory() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(masterSessionFactory().getObject());
return transactionManager;
}
/*
* #Bean public SessionFactory getSessionFactory(){
* if(entityManagerFactory.unwrap(SessionFactory.class)== null){ throw new
* NullPointerException("factory is not a hibernate factory"); } return
* entityManagerFactory.unwrap(SessionFactory.class); }
*/
#Bean(name = "masterSessionFactory")
public SessionFactory masterSessionFactory(HibernateEntityManagerFactory hemf) {
return hemf.getSessionFactory();
}
}
2 common config file and i made it as primary
package com.demo.config;
import java.util.HashMap;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
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;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "commonSessionFactory", transactionManagerRef
= "commonPostgrsTransactionManager", basePackages = {
"com.demo" })
public class CommonPostgreSqlConfig {
/*
* #Autowired private EntityManagerFactory entityManagerFactory;
*/
#Value("${common.connection.driver_class}")
private String driverClassName;
#Value("${common.connection.url}")
private String dataSourceUrl;
#Value("${common.connection.username}")
private String dataSourceUserName;
#Value("${common.connection.password}")
private String dataSourcePassword;
#Value("${spring.jpa.database-platform}")
private String hibernateDialect;
#Bean(name = "commonPostgrsEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean commonSessionFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(commonPostgresqlDataSource());
em.setPackagesToScan(new String[] { "com.demo.entity" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", hibernateDialect);
properties.put("hibernate.physical_naming_strategy",
SpringPhysicalNamingStrategy.class.getName());
properties.put("hibernate.implicit_naming_strategy",
SpringImplicitNamingStrategy.class.getName());
properties.put("hibernate.id.new_generator_mappings", false);
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource commonPostgresqlDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(dataSourceUrl);
dataSource.setUsername(dataSourceUserName);
dataSource.setPassword(dataSourcePassword);
return dataSource;
}
#Primary
#Bean(name = "commonPostgrsTransactionManager")
public PlatformTransactionManager commonPostgresTransactionManagerFactory() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(commonSessionFactory().getObject());
return transactionManager;
}
#Bean
public SessionFactory commonSessionFactory(HibernateEntityManagerFactory hemf) {
return hemf.getSessionFactory();
}
}
i am trying to create session factory object in my class level like this
#Autowired
#Setter
private SessionFactory commonSessionFactory;
#Autowired
#Setter
private SessionFactory masterSessionFactory;
getting this error
Description:
Field session in com.demo.dao.impl.democlass required a bean of type 'org.hibernate.SessionFactory' that could not be found.
Action:
Consider defining a bean of type 'org.hibernate.SessionFactory' in your configuration.

Dynamically set hibernate.dialect properties in spring boot

I have gone through available example and tutorials on how to set hibernate.dialect property correctly but found no approach suitable for my situation.
This tutorial is working best for me, but it lacks the ability to set hibernate.dialect property dynamically as I have different types of databases to connect to:
MS SQL
Oracle
H2
MySQL
With incorrect dialect, my JPA (delete/update) queries fail.
With below implementation of #Configuration, which works perfectly, how may I be able to set hibernate.dialect dynamically at runtime for each datasource?
Thank you in advance.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.example.multidb",
entityManagerFactoryRef = "multiEntityManager",
transactionManagerRef = "multiTransactionManager"
)
public class PersistenceConfiguration {
private final String PACKAGE_SCAN = "com.example.multidb";
#Primary
#Bean(name = "mainDataSource")
#ConfigurationProperties("app.datasource.main")
public DataSource mainDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
#Bean(name = "clientADataSource")
#ConfigurationProperties("app.datasource.clienta")
public DataSource clientADataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
#Bean(name = "clientBDataSource")
#ConfigurationProperties("app.datasource.clientb")
public DataSource clientBDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
#Bean(name = "multiRoutingDataSource")
public DataSource multiRoutingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.MAIN, mainDataSource());
targetDataSources.put(DBTypeEnum.CLIENT_A, clientADataSource());
targetDataSources.put(DBTypeEnum.CLIENT_B, clientBDataSource());
MultiRoutingDataSource multiRoutingDataSource = new MultiRoutingDataSource();
multiRoutingDataSource.setDefaultTargetDataSource(mainDataSource());
multiRoutingDataSource.setTargetDataSources(targetDataSources);
return multiRoutingDataSource;
}
#Bean(name = "multiEntityManager")
public LocalContainerEntityManagerFactoryBean multiEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(multiRoutingDataSource());
em.setPackagesToScan(PACKAGE_SCAN);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibernateProperties());
return em;
}
#Bean(name = "multiTransactionManager")
public PlatformTransactionManager multiTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
multiEntityManager().getObject());
return transactionManager;
}
#Primary
#Bean(name = "dbSessionFactory")
public LocalSessionFactoryBean dbSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(multiRoutingDataSource());
sessionFactoryBean.setPackagesToScan(PACKAGE_SCAN);
sessionFactoryBean.setHibernateProperties(hibernateProperties());
return sessionFactoryBean;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", true);
properties.put("hibernate.format_sql", true);
//set hibernate.dialect for each datasource
return properties;
}
}
I've created a working example for you, I'll describe it here but if you want to jump in the code yourself it's available at this GitHub repo.
In my case, I've created two data sources, one for User and another one for Item.
Here the entities:
package com.marcosbarbero.so.multiple.ds.entity.user;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Data
#Entity
#Table(schema = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
#Column(unique = true, nullable = false)
private String email;
private int age;
}
package com.marcosbarbero.so.multiple.ds.entity.item;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Data
#Entity
#Table(schema = "item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
}
Note, It's important to have distinct packages for each domain.
Then I created the Repositories
package com.marcosbarbero.so.multiple.ds.repository.user;
import com.marcosbarbero.so.multiple.ds.entity.user.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
}
package com.marcosbarbero.so.multiple.ds.repository.item;
import com.marcosbarbero.so.multiple.ds.entity.item.Item;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ItemRepository extends JpaRepository<Item, Integer> {
}
Nothing special about the repos. Let's move to the final piece, the configuration.
I created a #ConfigurationProperties class to externalize my configuration, bear with me, I know the naming is not the best :)
package com.marcosbarbero.so.multiple.ds.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
#Data
#Component
#ConfigurationProperties(prefix = "multi-datasource")
public class MultipleDataSourceProperties {
private UserDataSourceProperties user = new UserDataSourceProperties();
private ItemDataSourceProperties item = new ItemDataSourceProperties();
#Data
public static class UserDataSourceProperties {
private HibernateProperties hibernate = new HibernateProperties();
}
#Data
public static class ItemDataSourceProperties {
private HibernateProperties hibernate = new HibernateProperties();
}
#Data
public static class HibernateProperties {
private Map<String, String> properties = new HashMap<>();
}
}
We'll see the properties configuration file soon.
Now let's create the DataSource for the User:
package com.marcosbarbero.so.multiple.ds.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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 javax.sql.DataSource;
#Configuration
#EnableJpaRepositories(
basePackages = "com.marcosbarbero.so.multiple.ds.repository.user",
entityManagerFactoryRef = "userEntityManager",
transactionManagerRef = "userTransactionManager"
)
public class UserDataSourceConfig {
private final MultipleDataSourceProperties properties;
public UserDataSourceConfig(MultipleDataSourceProperties properties) {
this.properties = properties;
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean userEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(userDataSource());
em.setPackagesToScan("com.marcosbarbero.so.multiple.ds.entity.user");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaPropertyMap(properties.getUser().getHibernate().getProperties());
return em;
}
#Primary
#Bean
#ConfigurationProperties("multi-datasource.user")
public DataSource userDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
#Primary
#Bean
public PlatformTransactionManager userTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(userEntityManager().getObject());
return transactionManager;
}
}
The important part for you at this class is the line em.setJpaPropertyMap(properties.getUser().getHibernate().getProperties()); it's getting the User's Hibernate configuration properties from our #ConfigurationProperties class defined above.
Now let's do the same for the Item:
package com.marcosbarbero.so.multiple.ds.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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 javax.sql.DataSource;
#Configuration
#EnableJpaRepositories(
basePackages = "com.marcosbarbero.so.multiple.ds.repository.item",
entityManagerFactoryRef = "itemEntityManager",
transactionManagerRef = "itemTransactionManager"
)
public class ItemDataSourceConfig {
private final MultipleDataSourceProperties properties;
public ItemDataSourceConfig(MultipleDataSourceProperties properties) {
this.properties = properties;
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean itemEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(itemDataSource());
em.setPackagesToScan("com.marcosbarbero.so.multiple.ds.entity.item");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaPropertyMap(properties.getItem().getHibernate().getProperties());
return em;
}
#Primary
#Bean
#ConfigurationProperties("multi-datasource.item")
public DataSource itemDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
#Primary
#Bean
public PlatformTransactionManager itemTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(itemEntityManager().getObject());
return transactionManager;
}
}
The application.properties
multi-datasource.item.jdbcUrl=jdbc:h2:mem:spring_jpa_item;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS ITEM
multi-datasource.item.username=sa
multi-datasource.item.password=sa
multi-datasource.item.hibernate.properties.hibernate.hbm2ddl.auto=create-drop
multi-datasource.item.hibernate.properties.hibernate.cache.use_second_level_cache=false
multi-datasource.item.hibernate.properties.hibernate.cache.use_query_cache=false
multi-datasource.item.hibernate.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
multi-datasource.user.jdbcUrl=jdbc:h2:mem:spring_jpa_user;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS USER
multi-datasource.user.username=sa
multi-datasource.user.password=sa
multi-datasource.user.hibernate.properties.hibernate.hbm2ddl.auto=create-drop
multi-datasource.user.hibernate.properties.hibernate.cache.use_second_level_cache=false
multi-datasource.user.hibernate.properties.hibernate.cache.use_query_cache=false
multi-datasource.user.hibernate.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect
Some unit tests
package com.marcosbarbero.so;
import com.marcosbarbero.so.multiple.ds.entity.item.Item;
import com.marcosbarbero.so.multiple.ds.entity.user.User;
import com.marcosbarbero.so.multiple.ds.repository.item.ItemRepository;
import com.marcosbarbero.so.multiple.ds.repository.user.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertNotNull;
#SpringBootTest
public class JPAMultipleDBTest {
#Autowired
private UserRepository userRepository;
#Autowired
private ItemRepository itemRepository;
#Test
public void whenCreatingUser_thenCreated() {
User user = new User();
user.setName("John");
user.setEmail("john#test.com");
user.setAge(20);
user = userRepository.save(user);
assertNotNull(userRepository.findById(user.getId()));
}
#Test
public void whenCreatingProduct_thenCreated() {
Item item = new Item();
item.setName("Book");
item.setId(2);
item = itemRepository.save(item);
assertNotNull(itemRepository.findById(item.getId()));
}
}
I think it also worth mentioning, to make it all work I disabled the DataSourceAutoConfiguration, it's simple as that:
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
And again, it all is available at this GitHub repo.

data is not persisting to database and showing a null pointer exception in console

i am a beginner to spring boot and I am performing a CRUD operation on database using spring boot .the program complies with no error but during running my application i encounter an error: NullPointerException.
this is my program:-
CrudOperationApplication.java
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CrudOperationApplication {
public static void main(String[] args) {
SpringApplication.run(CrudOperationApplication.class, args);
}
}
DatabaseCon.java
package com;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
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.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#ComponentScan({ "com" })
#Configuration
#EnableTransactionManagement
#PropertySource(value = { "classpath:application.properties" })
public class DatabaseCon {
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
Employee.java
package com;
import javax.persistence.*;
#Entity
#Table(name="Employee")
public class Employee {
#Id
int id;
#Column(name="name")
String name;
#Column(name="salary")
int salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
}
EmployeeDao.java
package com;
public interface EmployeeDao {
String insertValue(Employee e);
String updateValue(Employee e);
String deleteValue(Employee e);
String getValue();
String getSpecificValue( int id);
}
EmployeeController.java
package com;
import java.util.*;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class EmployeeController implements EmployeeDao{
HibernateTemplate ht;
Employee e=new Employee();
void setHt(HibernateTemplate ht)
{
this.ht=ht;
}
// for insertion into database
#RequestMapping(value="/",method=RequestMethod.POST)
public String insertValue(Employee e)
{
e.setId(1);
e.setName("james");
e.setSalary(7000);
ht.persist(e);
return "value saved to database";
}
//for updation
#RequestMapping(value="/",method=RequestMethod.PUT)
public String updateValue(Employee e)
{
ht.update(e);
return "value updated to database";
}
//for deletion
#RequestMapping(value="/",method=RequestMethod.DELETE)
public String deleteValue(Employee e)
{
ht.delete(e);
return "value deleted from database";
}
// get stored values from d.b
#RequestMapping(value="/",method=RequestMethod.GET)
public String getValue()
{
List<Employee> al=new ArrayList<Employee>();
al=ht.loadAll(Employee.class);
return ""+al;
}
// to get particular value from d.b
#SuppressWarnings("unchecked")
#RequestMapping(value="/{id}",method=RequestMethod.GET)
public String getSpecificValue(#PathVariable int id)
{
List<Employee> al=new ArrayList<Employee>();
al=(List<Employee>) ht.load(Employee.class,id);
return ""+al;
}
}
Application.properties
jdbc.driverClassName = org.postgresql.Driver
jdbc.url = jdbc:postgresql://localhost:5432/testc
jdbc.db=testc
jdbc.port=5432
jdbc.ip= 127.0.0.1
jdbc.username = postgres
jdbc.password = root
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
hibernate.show_sql = true
hibernate.format_sql = true
You are using Spring Boot then use Spring Boot. Currently you are trying really hard to NOT use Spring Boot.
First instead of you manually configuration a DataSource let Spring Boot do it for you. Remove the #Bean for DataSource and add spring.datasource properties in your application.properties (or simply rename the existing ones).
spring.datasource.url=jdbc:postgresql://localhost:5432/testc
spring.datasource.username=postgres
spring.datasource.password=root
Next instead of using plain Hibernate I strongly suggest to start using JPA instead. So remove the definition for the LocalSessionFactoryBean and HibernateTransactionManager. Simply add the following properties to your configuration.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Now basically have an empty configuration class simply remove it. Spring Boot will already component-scan for you, create JPA, enable transactions.
In your controller/dao hybrid (which is a bad thing imho!) instead of the HibernateTemplate use the EntityManager instead. However I would suggest separating the dao and controller functionality.
#Repository
#Transactional
public class EmployeeDaoJpa implements EmployeeDao {
#PersistenceContext
private EntityManager em;
// Method implementations using the EntityManager
}
Now in your controller use that dao.
#RestController
public class EmployeeController {
private final EmployeeDao dao;
#Autowired
public EmployeeController(EmployeeDao dao) {
this.dao=dao;
}
// for insertion into database
#RequestMapping(value="/",method=RequestMethod.POST)
public String insertValue(Employee e) {
e.setId(1);
e.setName("james");
e.setSalary(7000);
dao.insertvalue(e);
return "value saved to database";
}
//for updation
#RequestMapping(value="/",method=RequestMethod.PUT)
public String updateValue(Employee e) {
dao.updateValue(e);
return "value updated to database";
}
//for deletion
#RequestMapping(value="/",method=RequestMethod.DELETE)
public String deleteValue(Employee e) {
ht.delete(e);
return "value deleted from database";
}
// get stored values from d.b
#RequestMapping(value="/",method=RequestMethod.GET)
public String getValue() {
return ""+dao.findAll();
}
// to get particular value from d.b
#SuppressWarnings("unchecked")
#RequestMapping(value="/{id}",method=RequestMethod.GET)
public String getSpecificValue(#PathVariable int id) {
return ""+dao.findOne(id);
}
}
Another tip don't use com as your package first it is to lowlevel and when Spring or your container starts scanning the com package it will scan everything in the com package. Like everything in jar files starting with com. So invent a better package naming.
In the end you now only have your controller, repository class and interface and finally your application class. No more configuration class that is all nicely in your application.properties.

Spring mutliple datasources with Hibernate gives: No Session found error

I am using Spring 4 with Hibernate 4 and trying to have multiple datasources configured. When I use the new second one, I always get an error.
package org.miso.vre.config;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
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.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
#ComponentScan("org.miso.vre")
#PropertySource("classpath:database.properties")
public class DatabaseConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_DATABASE_MISOFT_DRIVER = "db.misoft.driver";
private static final String PROPERTY_NAME_DATABASE_MISOFT_PASSWORD = "db.misoft.password";
private static final String PROPERTY_NAME_DATABASE_MISOFT_URL = "db.misoft.url";
private static final String PROPERTY_NAME_DATABASE_MISOFT_USERNAME = "db.misoft.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public DataSource dataSourceMISOFT() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_PASSWORD));
return dataSource;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
#Bean
public LocalSessionFactoryBean sessionFactoryMISOFT() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSourceMISOFT());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
}
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.miso.vre.model.VRE_Record;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
#Repository
public class VRETestTableDAOImpl implements VRETestTableDAO {
#Autowired
#Qualifier(value="sessionFactoryMISOFT")
private SessionFactory sessionFactoryMISOFT;
private Session getCurrentSession() {
return sessionFactoryMISOFT.getCurrentSession();
}
public VRE_Record getVRE_Record(int id) {
VRE_Record vRE_Record = (VRE_Record) getCurrentSession().get(VRE_Record.class, id);
return vRE_Record;
}
}
>
package org.miso.vre.service;
import org.miso.vre.dao.VRETestTableDAO;
import org.miso.vre.model.VRE_Record;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Created by PDuer on 12/29/2015.
*/
#Service
#Transactional
public class TestServiceImpl implements TestService {
#Autowired
private VRETestTableDAO vreTestTableDAO;
#Override
public VRE_Record getVRERecord (int id) {
return vreTestTableDAO.getVRE_Record(id);
}
}
exception org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
org.hibernate.HibernateException: No Session found for current thread
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:943)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
com.github.dandelion.datatables.core.web.filter.DatatablesFilter.doFilter(DatatablesFilter.java:73)
root cause org.hibernate.HibernateException: No Session found for
current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1013)
org.miso.vre.dao.VRETestTableDAOImpl.getCurrentSession(VRETestTableDAOImpl.java:18)
org.miso.vre.dao.VRETestTableDAOImpl.getVRE_Record(VRETestTableDAOImpl.java:22)
org.miso.vre.service.TestServiceImpl.getVRERecord(TestServiceImpl.java:22)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
The reason being, the sessionFactoryMISOFT is not associated with any transaction manager. Only the sessionFactory is associated with a transaction manager through transactionManager() method.
You need to create a similar method, say, transactionManagerMISOFT() and associate sessionFactoryMISOFT with this new transactionManager.
And when using the #Transaction attribute we need to specify which transactionManager needs to be used.
In my case, I have defined two sessionFactories and two transactionManager methods as below:
#Bean
public HibernateTransactionManager transactionManagerABC() {
return new HibernateTransactionManager(sessionFactoryABC().getObject());
}
#Bean
public HibernateTransactionManager transactionManagerXYZ() {
return new HibernateTransactionManager(sessionFactoryXYZ().getObject());
}
And while using it I specify either transactionManagerABC or transactionManagerXYZ along with Transactional attribute in you service classes, as below:
#Transactional(transactionManager="transactionManagerABC")
public Forest getForestById(int id) {
return forestDAO.getForestById(id);
}
You need to use Qualifier with Autowired annotation for sessionFactory, which I believe you already have:
#Qualifier("sessionFactoryABC")
private SessionFactory sessionFactory;

Spring Data - NoSuchMethodError JpaRepositoryFactoryBean.setMappingContext()

I wrote a DAL following this guide. In particular this is my DALConfig.java configuration file
package my.pack;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.hibernate.ejb.HibernatePersistence;
import org.hibernate.jpa.HibernatePersistenceProvider;
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.context.annotation.PropertySources;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#ComponentScan(basePackages = { "my.pack" })
#PropertySource("classpath:dbconnection.properties")
#EnableJpaRepositories("my.pack.repository")
#EnableTransactionManagement
public class DALConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver_class";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_POOL_INITIAL_SIZE = "pool.initialsize";
private static final String PROPERTY_NAME_POOL_MAX_IDLE = "pool.maxidle";
private static final String PROPERTY_NAME_DAL_CLASSES_PACKAGE = "entities.packages_to_scan";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.showsql";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
#Resource
private Environment environment;
#Bean
public DataSource dataSource()
{
Properties props = new Properties();
props.put("driverClassName", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
props.put("url", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
props.put("username", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
props.put("password", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
props.put("initialSize", environment.getRequiredProperty(PROPERTY_NAME_POOL_INITIAL_SIZE));
props.put("maxIdle", environment.getRequiredProperty(PROPERTY_NAME_POOL_MAX_IDLE));
BasicDataSource bds = null;
try {
bds = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bds;
}
#Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor()
{
PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
return b;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator(){
return new HibernateExceptionTranslator();
}
#Bean
public PlatformTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_DAL_CLASSES_PACKAGE));
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
Properties jpaProterties = new Properties();
jpaProterties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
jpaProterties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
jpaProterties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProterties);
return entityManagerFactoryBean;
}
}
This is the Repository I wrote
package my.pack.repository;
import my.pack.entity.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface IUserRepository extends CrudRepository<User, String>{
}
Finally this is the test I run
package my.pack.tests;
import static org.junit.Assert.assertTrue;
import futureservice.UserService;
import my.pack.DALConfig;
import my.pack.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#ContextConfiguration(classes = { DALConfig.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class DALTest {
#Autowired
UserService userService;
#Test
public void testGetUser() {
User user = null;
user = userService.findOne("mrossi");
assertTrue(null != user);
}
}
When I run the test I get the following exception stack and the test fails.
...
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'entityManager' threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.setMappingContext(Lorg/springframework/data/mapping/context/MappingContext;)V
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:108)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:62)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1489)
... 41 more
It seems like the JpaRepositoryFactoryBean misses the setMappingContext method but as you can see from the documentation the method is supported. I'm using the 1.5.1.RELEASE version of spring-data-jpa artifact.
What can be the issue?
Thank you

Categories