Mybatis Spring multiple databases Java configuration - java

I'm working with Spring and Mybatis and I have two databases, the configuration for the first database was relative easy, but I can't get to work the second database with Spring and transactions, here is my code
#Configuration
#ComponentScan(basePackages = {"hernandez.service", "hernandez.dao"})
#EnableTransactionManagement
#MapperScan(basePackages="hernandez.mapper" )
#Import(DbConfig2.class)
public class AppConfig {
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/northwind", "root", "");
return ds;
}
#Bean
public SqlSessionFactoryBean sqlSessionFactory() {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
#Configuration
#MapperScan("loli.mapper" )
public class DbConfig2 {
#Bean(name = "dataSource_2")
public DataSource dataSource2() {
DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/dmsolut_dmsms", "root", "");
return ds;
}
#Bean
public SqlSessionFactory sqlSessionFactory2() throws Exception{
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource2());
return factoryBean.getObject();
}
#Bean(name = "transactionManager_2")
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource2());
}
}
Is there a way to get this working with pure Spring Java configuration or at least with some XML? There's no official documentation to get two databases working in the Mybatis-Spring project

Multi datasources with mybatis are used in my project right now. This is an Example, add to your application.xml
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="${center.connectionURL}"/>
<property name="username" value="${userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.dao.center"/>
<property name="sqlSessionFactoryBeanName" value="cneterSqlSessionFactory"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" name="cneterSqlSessionFactory">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath*:mapperConfig/center/*.xml"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--center db end-->
<!--exdb-->
<bean id="dataSourceEx" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="${ex.connectionURL}"/>
<property name="username" value="${userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.dao.ex"/>
<property name="sqlSessionFactoryBeanName" value="exSqlSessionFactory"/>
</bean>
<bean id="sqlSessionFactoryEx" class="org.mybatis.spring.SqlSessionFactoryBean" name="exSqlSessionFactory">
<property name="dataSource" ref="dataSourceEx"></property>
<property name="mapperLocations" value="classpath*:mapperConfig/ex/*.xml"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManagerEx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceEx"/>
</bean>

Add answer with java config example we use in our project:
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
#Configuration
#ComponentScan(basePackages = "com.mycompany")
#EnableTransactionManagement(proxyTargetClass = true)
public class ApplicationConfig2 {
public static final String DATA_SOURCE_NAME_1 = "jdbc/dataSource1";
public static final String DATA_SOURCE_NAME_2 = "jdbc/dataSource2";
public static final String SQL_SESSION_FACTORY_NAME_1 = "sqlSessionFactory1";
public static final String SQL_SESSION_FACTORY_NAME_2 = "sqlSessionFactory2";
public static final String MAPPERS_PACKAGE_NAME_1 = "com.mycompany.mappers.dao1";
public static final String MAPPERS_PACKAGE_NAME_2 = "com.mycompany.mappers.dao2";
#Bean
public DataSource dataSource1() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
}
#Bean
public DataSource dataSource2() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean(name = SQL_SESSION_FACTORY_NAME_1)
public SqlSessionFactory sqlSessionFactory1(DataSource dataSource1) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
sqlSessionFactoryBean.setDataSource(dataSource1);
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
return sqlSessionFactory;
}
#Bean(name = SQL_SESSION_FACTORY_NAME_2)
public SqlSessionFactory sqlSessionFactory2(DataSource dataSource2) throws Exception {
SqlSessionFactoryBean diSqlSessionFactoryBean = new SqlSessionFactoryBean();
diSqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
diSqlSessionFactoryBean.setDataSource(dataSource2);
SqlSessionFactory sqlSessionFactory = diSqlSessionFactoryBean.getObject();
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
return sqlSessionFactory;
}
#Bean
public MapperScannerConfigurer mapperScannerConfigurer1() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(MAPPERS_PACKAGE_NAME_1);
configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_1);
return configurer;
}
#Bean
public MapperScannerConfigurer mapperScannerConfigurer2() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage(MAPPERS_PACKAGE_NAME_2);
configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_2);
return configurer;
}
}

In my experience, you should also add #Primary to one of the DataSource beans. Otherwise it will throw NoUniqueBeanDefinitionException.
#Bean
#Primary
public DataSource dataSource1() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
}
#Bean
public DataSource dataSource2() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
}

You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey().
Spring Configuration
You can define separate datasource in spring configuration.
<!-- db2 data source -->
<bean id="db2DataSource" class="com.ibm.db2.jdbc.app.DB2Driver">
<property name="serverName" value="${db2.jdbc.serverName}" />
<property name="portNumber" value="${db2.jdbc.portNumber}" />
<property name="user" value="${db2.jdbc.username}" />
<property name="password" value="${db2.jdbc.password}" />
<property name="databaseName" value="${db2.jdbc.databaseName}" />
</bean>
<!-- mysql data source -->
<bean id="mysqlDataSource" class="com.mysql.jdbc.Driver">
<property name="serverName" value="${mysql.jdbc.serverName}" />
<property name="portNumber" value="${mysql.jdbc.portNumber}" />
<property name="user" value="${mysql.jdbc.username}" />
<property name="password" value="${mysql.jdbc.password}" />
<property name="databaseName" value="${mysql.jdbc.databaseName}" />
</bean>
Associate the datasource with customer:
<bean id="customer" class="com.example.Customer">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.example.datasource.CustomerRoutingDataSource">
<property name="targetDataSources">
<map key-type="com.example.Customer">
<entry key="db2" value-ref="mysqlDataSource"/>
<entry key="mysql" value-ref="db2DataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="mysql"/>
</bean>
Java
package com.example;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
#Bean
CustomerContextHolder context;
#Override
protected Object determineCurrentLookupKey() {
return context.getCustomerType();
}
}
Basically, each request will have its context. You can associate datasource with request using mapped key. You can find more details here dynamic-datasource-routing

<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="configLocation">
<value>classpath:com/dtcc/dao/impl/DaoSqlMapConfig_MyBatis1.xml</value>
</property>
<property name="transactionFactory">
<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
</property>
<property name="mapperLocations" value="classpath*:com/dtcc/dao/impl/DaoEmfMyBatis.sp.xml"/>
</bean>
<bean id="sqlSession1" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory1" />
</bean>
<!-- MyBatis Changes Ends -->
<bean id="daoEmf" class="com.dtcc.dao.DaoEmfImpl">
<property name="connectionType"><ref local="com.dtcc.sharedservices.utils.resources.ConnTypes.IBM_DB2_CONNECTION" /></property>
<property name="jndiNameForLogging"><ref local="dataSourceName1" /></property>
<property name="sqlSessionTemplate"> <ref local="sqlSession1" /></property>
<property name="applicationLog"><ref local="appLog" /></property>
</bean>
As mentioned above, we need to give corresponding sessionFactory in your DaoImpl. You can not autowire SqlSessionTemplate in your DaoImpl class if you have more than one sessionFactory. Give unique name for each session factory and map it to your respective DaoImpl class.
All you have to do is just to create object for SqlSessionTemplate with Setter method in DaoImpl class and you can make your db call using sqlSessionTemplate object as below,
this.sqlSessionTemplate.selectList("ProcedureID", parameter);

Related

Use Spring's TransactionAwareDataSourceProxy in code, not xml

I'm trying to get jOOQ transactions to work, except using code instead of XML configuration. I think it should be as simple as
// inside #Configuration annotated class
#Bean
public DataSource makeTransactionAware(DataSource fromConnectionPool) {
return new TransactionAwareDataSourceProxy(fromConnectionPool);
}
except, I need to tell Spring that the injected DataSource is not the same one as returned from the method. How do I do that?
Bean custom naming & qualifier should do the work for you.
https://www.baeldung.com/spring-qualifier-annotation
#Bean(name = "txAwareDS")
public DataSource makeTransactionAware(#Qualifier("dataSource") DataSource fromConnectionPool) {
return new TransactionAwareDataSourceProxy(fromConnectionPool);
}
Example code is just a starting point.
From the Spring configuration file shared
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" >
<!-- These properties are replaced by Maven "resources" -->
<property name="url" value="${db.url}" />
<property name="driverClassName" value="${db.driver}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="transactionAwareDataSource"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dataSource" />
</bean>
will be configured as
#Configuration
#PropertySource("classpath:config.properties")
public class DataSourceConfig{
#Value("${db.username}")
private String username;
#Value("${db.password}")
private String password;
#Value("${db.url}")
private String url;
#Bean
public DataSource dataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("<driver class name>"); // Spring will load the driver discovered if not specified explicitly.
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
basicDataSource.setUrl(url);
return basicDataSource;
}
#Bean
public TransactionAwareDataSourceProxy transactionAwareDataSource(DataSource dataSource) {
return new TransactionAwareDataSourceProxy(dataSource)
}
}
Hope this helps

Spring with two transaction managers and one within another

I have two transaction managers defined in my context file as follows
<tx:annotation-driven transaction-manager="firstTransactionManager" />
<bean id="secondDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="---" />
<property name="url" value="datasource1" />
<property name="username" value="----" />
<property name="password" value="----" />
</bean>
<bean id="firstTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="firstDataSource" />
<qualifier value="firstTxManager"/>
</bean>
<bean id="secondTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="secondDataSource" />
<qualifier value="secondTxManager"/>
</bean>
<bean id="firstDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="---" />
<property name="url" value="datasource2" />
<property name="username" value="---" />
<property name="password" value="---" />
</bean>
And I my class definitions are as follows
#Transactional("firstTransactionManager")
public class JdbcMain {
#Autowired
private static DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public static void main(String args[]){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
TransactionExample example = (TransactionExample) ctx.getBean("transExample");
example.create();
}
}
And my example class is as follows:
#Transactional("secondTransactionManager")
public void create(DataSource dataSource2) {
try {
this.jdbcTemplate = new JdbcTemplate(dataSource2);
String sql = "insert into testtable values (?,?)";
getJdbcTemplate().update(sql,1,"1244343");
String marksSql="insert into testtable values (?,?)";
int i=2/0; //added to depict roll back behaviour of the transaction when exception occurs
getJdbcTemplate().update(marksSql,2,"sujay");
System.out.println("transaction committed");
} catch (RuntimeException e) {
throw e;
}
}
But the second transaction manager doesn't seem to work and the transaction is not rolled back (The first insert is executed). Can you provide me an idea.

Bean Velocity Config from xml to java

I'd like convert xml bean with velocity to config java class
This is old xml config:
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/view/"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".html"/>
<property name="exposeSpringMacroHelpers" value="true"/>
</bean>
And this is new java class config:
#Bean
public ViewResolver viewResolver()
{
VelocityViewResolver viewResolver= new VelocityViewResolver();
viewResolver.setPrefix("");
viewResolver.setSuffix(".html");
viewResolver.setCache(true);
return viewResolver;
}
#Bean
public VelocityConfigurer velocityConfig()
{
VelocityConfigurer velocityConfig = new VelocityConfigurer();
// ???????????
return velocityConfig;
}
How to do it?
VelocityConfig extends VelocityEngineFactory, so you can use the method setResourceLoaderPath:
velocityConfig.setResourceLoaderPath("/WEB-INF/View/");

how to convert xml notation to annotation based notation : Spring - Java

I have following xml configuration in my spring context xml, I have used annotation based approach very less and unable to figure out how to represent following using annotation, need help.
<bean id="myPolicyAdmin" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg>
<bean class="org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails">
<property name="accessTokenUri" value="${accessTokenEndpointUrl}" />
<property name="clientId" value="${clientId}" />
<property name="clientSecret" value="${clientSecret}" />
<property name="username" value="${policyAdminUserName}" />
<property name="password" value="${policyAdminUserPassword}" />
</bean>
</constructor-arg>
</bean>
In my java class(Policy manager) it is referred as following, I am actually referring a sample and trying to convert it all annotation baesed.
#Autowired
#Qualifier("myPolicyAdmin")
private OAuth2RestTemplate myPolicyAdminTemplate;
EDIT:
I tried creating a bean for org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails but not sure how to set its properties and how to access it as constructor args to myPolicyAdminTemplate
You can configure the same beans using JavaConfig as follows:
#Component
#Configuration
public class AppConfig
{
#Value("${accessTokenEndpointUrl}") String accessTokenUri;
#Value("${clientId}") String clientId;
#Value("${clientSecret}") String clientSecret;
#Value("${policyAdminUserName}") String username;
#Value("${policyAdminUserPassword}") String password;
#Bean
public OAuth2RestTemplate myPolicyAdmin(ResourceOwnerPasswordResourceDetails details)
{
return new OAuth2RestTemplate(details);
}
#Bean
public ResourceOwnerPasswordResourceDetails resourceOwnerPasswordResourceDetails()
{
ResourceOwnerPasswordResourceDetails bean = new ResourceOwnerPasswordResourceDetails();
bean.setAccessTokenUri(accessTokenUri);
bean.setClientId(clientId);
bean.setClientSecret(clientSecret);
bean.setUsername(username);
bean.setPassword(password);
return bean;
}
}
To set the props of a bean you can either use #Value during construction:
How to inject a value to bean constructor using annotations
and this one:
Spring: constructor injection of primitive values (properties) with annotation based configuration
Or #Value in the variables. You could also actually use #Resource, but I wouldn't recommend it.
In your case, the constructor for the
org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails
Would be kinda like
#Autowired
public ResourceOwnerPasswordResourceDetails(
#Value("${accessTokenEndpointUrl}") String accessTokenUri,
#Value("${clientId}") String clientId,
#Value("${clientSecret}") String clientSecret,
#Value("${policyAdminUserName}") String username,
#Value("${policyAdminUserPassword}") String password
)
I shall give you a XML configuration with it anotation based config equivalent respectively, so that you will easily see how to change your bean from xml to java and vice-versa
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.mycompany.backendhibernatejpa.controller" />
<mvc:annotation-driven />
<bean id="iAbonneDao" class="com.mycompany.backendhibernatejpa.daoImpl.AbonneDaoImpl"/>
<bean id="iAbonneService" class="com.mycompany.backendhibernatejpa.serviceImpl.AbonneServiceImpl"/>
<!-- couche de persistance JPA -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:bd.properties"/>
</bean>
<!-- la source de donnéees DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="${bd.driver}" />
<property name="url" value="${bd.url}" />
<property name="username" value="${bd.username}" />
<property name="password" value="${bd.password}" />
</bean>
<!-- le gestionnaire de transactions -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- traduction des exceptions -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<!-- annotations de persistance -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
this file is named springrest-sevlet. actually you can give the name you want followed by "-servlet" and mention that name in the file web.xml
<web-app>
<display-name>Gescable</display-name>
<servlet>
<servlet-name>springrest</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springrest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
the two files should be place in the folder "WEB-INF".
Now the equivalent with anotation based config
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.backendhibernatejpaannotation.configuration;
import com.mycompany.backendhibernatejpaannotation.daoImpl.AbonneDaoImpl;
import com.mycompany.backendhibernatejpaannotation.daoInterface.IAbonneDao;
import com.mycompany.backendhibernatejpaannotation.serviceImpl.AbonneServiceImpl;
import com.mycompany.backendhibernatejpaannotation.serviceInterface.IAbonneService;
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.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
*
* #author vivien saa
*/
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mycompany.backendhibernatejpaannotation")
public class RestConfiguration {
#Bean
public IAbonneDao iAbonneDao() {
return new AbonneDaoImpl();
}
#Bean
public IAbonneService iAbonneService() {
return new AbonneServiceImpl();
}
// #Bean
// public PropertyPlaceholderConfigurer placeholderConfigurer() {
// PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
// placeholderConfigurer.setLocations("classpath:bd.properties");
// return placeholderConfigurer;
// }
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/gescable");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public HibernateJpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setLoadTimeWeaver(loadTimeWeaver());
return entityManagerFactory;
}
#Bean
public JpaTransactionManager jpaTransactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
#Bean
public PersistenceExceptionTranslationPostPro`enter code here`cessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
}
this file must be accompanied by this one
package com.mycompany.backendhibernatejpaannotation.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
*
* #author vivien saa
*/
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RestConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}

Spring JPA Config IllegalArgumentException: No persistence unit with name found

I am having a weird issue I'm not able to wrap my head around. I have used JPA/Hibernate is Spring before with NO persistence.xml file, Spring handled everything. I'm working on a new project and this time I decided to go all Java Config. I am having some issues with my PersistenceConfig.java, it keeps saying it can't find a persistence unit. If I comment out the line the sets the PersistenceUnitName then it complains IllegalStateException: No persistence units parsed from {classpath*:META-INF/persistence.xml}.
I don't understand why its trying to use a persistence.xml when I use Java Config and not when I use XML. Any solutions?
Here is my PersistenceConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.JpaDialect;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
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.Properties;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.testapp.ots.repository"})
public class PersistenceConfig {
#Autowired
Environment environment;
#Bean(name = "datasource")
public DataSource dataSource() {
JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(true);
return dsLookup.getDataSource("jdbc/postgres");
}
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPersistenceUnitName("postgres");
entityManagerFactory.setJpaProperties(jpaProperties());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setJpaDialect(jpaDialect());
return entityManagerFactory;
}
#Bean(name = "jpaVendorAdapter")
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean(name = "jpaDialect")
public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);
jpaTransactionManager.setDataSource(dataSource());
jpaTransactionManager.setJpaDialect(jpaDialect());
return jpaTransactionManager;
}
#Bean(name = "persistenceExceptionTranslation")
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
public Properties jpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", environment.getProperty("hibernate.hbm2ddl.auto"));
properties.setProperty("hibernate.dialect", environment.getProperty("hibernate.dialect"));
properties.setProperty("hibernate.show_sql", environment.getProperty("hibernate.show_sql"));
properties.setProperty("hibernate.format_sql", environment.getProperty("hibernate.format_sql"));
properties.setProperty("hibernate.connection.charSet", environment.getProperty("hibernate.connection.charSet"));
properties.setProperty("hibernate.cache.use_second_level_cache", environment.getProperty("hibernate.cache.use_second_level_cache"));
properties.setProperty("hibernate.cache.use_query_cache", environment.getProperty("hibernate.cache.use_query_cache"));
properties.setProperty("hibernate.cache.use_structured_entries", environment.getProperty("hibernate.cache.use_structured_entries"));
properties.setProperty("hibernate.generate_statistics", environment.getProperty("hibernate.generate_statistics"));
return properties;
}
}
As a reference here is the XML configuration I used a few months back.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<context:annotation-config />
<jpa:repositories base-package="net.jkratz.bloodpressure.api.repository" />
<jee:jndi-lookup jndi-name="jdbc/BloodPressureDB" id="dataSource" expected-type="javax.sql.DataSource" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="BPPersistenceUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="packagesToScan">
<list>
<value>net.jkratz.bloodpressure.api.model</value>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.connection.charSet">${hibernate.connection.charSet}</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="${jpa.vendor.database}" />
<property name="showSql" value="${jpa.vendor.showSql}"/>
<property name="generateDdl" value="${jpa.vendor.generateDdl}"/>
<property name="databasePlatform" value="${jpa.vendor.databasePlatform}"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
From LocalEntityManagerFactoryBean documentation:
In case of Spring-based scanning, no persistence.xml is necessary; all
you need to do is to specify base packages to search here.
So, try change your bean entityManagerFactory to this:
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPersistenceUnitName("postgres");
entityManagerFactory.setJpaProperties(jpaProperties());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setJpaDialect(jpaDialect());
entityManagerFactory.setPackagesToScan("net.jkratz.bloodpressure.api.model");
return entityManagerFactory;
}

Categories