I am writing application using postgresql database and spring + hibernate frameworks.
I upgraded spring framework from 4.1.5.RELEASE to 4.2.0.RELEASE version and upgraded hibernate framework from 4.3.7.Final to 5.0.0.Final version.
After upgrade I have problems with NamingStrategy. In postgresql database, table column names are in lowercase separated by underscore, in application layer, bean properties are in camelcase.
This is working spring configuration file for older version:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="fms" />
<bean id="microFmsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="***" />
<property name="username" value="***" />
<property name="password" value="***" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="select 1" />
<property name="initialSize" value="5" />
<property name="minIdle" value="10" />
<property name="maxIdle" value="100" />
<property name="maxActive" value="100" />
<property name="removeAbandoned" value="true" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="microFmsDataSource"/>
<property name="packagesToScan">
<list>
<value>fms</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<entry key="hibernate.hbm2ddl.auto" value="validate" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<entry key="hibernate.show_sql" value="true" />
<entry key="hibernate.format_sql" value="true" />
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
After upgrade I changed NamingStrategy configuration:
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
like this:
<entry key="hibernate.implicit_naming_strategy" value="***" />
and tried all variants of options listed in hibernate javadoc: https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/AvailableSettings.html#IMPLICIT_NAMING_STRATEGY
but with no success.
Can you tell me what is alternative of ImprovedNamingStrategy in Hibernate 5 and provide a working configuration example ?
I think I found the solution.
To achieve my goal, I used hibernate.physical_naming_strategy configuration, instead of hibernate.implicit_naming_strategy.
I created an implementation of the PhysicalNamingStrategy interface which simulates part of the functionality of the original ImprovedNamingStrategy class:
package fms.util.hibernate;
import org.apache.commons.lang.StringUtils;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class ImprovedNamingStrategy implements PhysicalNamingStrategy {
#Override
public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
#Override
public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
#Override
public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
#Override
public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
#Override
public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnv) {
return convert(identifier);
}
private Identifier convert(Identifier identifier) {
if (identifier == null || StringUtils.isBlank(identifier.getText())) {
return identifier;
}
String regex = "([a-z])([A-Z])";
String replacement = "$1_$2";
String newName = identifier.getText().replaceAll(regex, replacement).toLowerCase();
return Identifier.toIdentifier(newName);
}
}
After I created this class, I changed my configuration from:
<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
to this:
<entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
and now everything works correctly.
This solution covers only small part of ImprovedNamingStrategy. In my project, for table mapping and join mapping, I always specify the name of table or join column explicitly. I rely on implicit name conversion only for column names. So this simple solution was acceptable for me.
This is a full example of my Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="fms" />
<bean id="microFmsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="***" />
<property name="username" value="***" />
<property name="password" value="***" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="validationQuery" value="select 1" />
<property name="initialSize" value="5" />
<property name="minIdle" value="10" />
<property name="maxIdle" value="100" />
<property name="maxActive" value="100" />
<property name="removeAbandoned" value="true" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="microFmsDataSource"/>
<property name="packagesToScan">
<list>
<value>fms</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<entry key="hibernate.hbm2ddl.auto" value="validate" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<entry key="hibernate.show_sql" value="true" />
<entry key="hibernate.format_sql" value="true" />
<entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
I hope this solution will be helpful for somebody. :)
For anyone looking for a Java Config Solution
The hibernate.ejb.naming_strategy property seems split into two parts in hibernate 5.X:
hibernate.physical_naming_strategy
hibernate.implicit_naming_strategy
Spring provides SpringImplicitNamingStrategy and SpringPhysicalNamingStrategy for this purpose.
Here is my approach:
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
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.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#DependsOn("myDataSource")
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "myEntityManagerFactory",
basePackages={"com.myapp.repo"},
transactionManagerRef="myTransactionManager"
)
public class MyJpaConfig {
private Map<String, Object> properties;
public MyJpaConfig() {
properties = new HashMap<>();
properties.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
properties.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());
}
#Bean(name = "myEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("systemDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean build = builder.dataSource(dataSource)
.packages("com.myapp.entity")
.properties(properties)
.build();
return build;
}
#Bean(name = "myTransactionManager")
public PlatformTransactionManager myTransactionManager(
#Qualifier("myEntityManagerFactory") EntityManagerFactory myEntityManagerFactory) {
return new JpaTransactionManager(myEntityManagerFactory);
}
}
I had the exactly same problem. I fixed it with default implementation from spring boot:
<property name="hibernate.implicit_naming_strategy" value="org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy" />
<property name="hibernate.physical_naming_strategy" value="org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy" />
This work for me, from http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- convert aaBb to aa_bb -->
<property name="PhysicalNamingStrategy">
<bean class="fms.util.hibernate.ImprovedNamingStrategy" />
</property>
<!-- convert aa_bb to aaBb -->
<property name="ImplicitNamingStrategy">
<bean class="org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl" />
</property>
...
</bean>
try this:
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(getDataSource());
localSessionFactoryBean.setHibernateProperties(getHibernateProperties());
localSessionFactoryBean.setPackagesToScan(new String[]{"com.xxx.pojo"});
// -----important-----
localSessionFactoryBean.setPhysicalNamingStrategy(new CustomNamingStrategy());
return localSessionFactoryBean;
}
public class CustomNamingStrategy extends PhysicalNamingStrategyStandardImpl {***
Please find below 3 points that I discovered while working on Naming Strategy:
If you are providing #Table and #Column annotation in your entity classes with names provided with an underscore i.e. user_id i.e. #Column(name="user_id"), it will take the column name as user_id; if you give it as userid then it will change to user_id if you use no strategy or implicit strategy (specifically org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl). So, if you want a strategy where the entity attribute name changes to one with underscore and lowercase letters i.e. something from userId to user_id, you should use implicit or no strategy (which actually uses implicit strategy).
If you don't want your naming strategy to add an underscore to the column name or class name, then the strategy that you need to use would look like:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. The things that you provide in annotations #Table and #Column’s name attribute would remain as it is.
If you don't want to provide annotations and want to manually handle the table name and column names, you should extend the class org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl and override the required methods. If you still use annotations for some of the cases here, remember the overridden methods will apply on the names written in those annotations.
Related
I have a problem with my project. When i browser http://localhost:8080/user/form to display UserForm then occur following error:
WARNING: No mapping found for HTTP request with URI [/user/form] in
DispatcherSe rvlet with name 'userservice'
Here file UserRestServiceController.java
package edu.java.spring.service.user.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import edu.java.spring.service.user.dao.UserDao;
import edu.java.spring.service.user.model.User;
#Controller
public class UserRestServiceController {
#Autowired
private UserDao userDao;
#Autowired
private View jsonView;
#RequestMapping(value="/user/form,",method = RequestMethod.GET)
public ModelAndView user(){
// System.out.println("anh yeu em ");
return new ModelAndView("UserForm","User",new User());
}
#RequestMapping(value="/user/json/{username}")
public ModelAndView loadUser(#PathVariable("username")String name){
return new ModelAndView(jsonView,"data",userDao.loadUser(name));
}
}
Here file userservice-servlet.xml
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd ">
<context:component-scan base-package="edu.java.spring.service.user.controller"></context:component-scan>
<context:component-scan base-package="edu.java.spring.service.user.dao"></context:component-scan>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1" />
<property name="suffix" value=".jsp" />
<property name="prefix" value="/user/" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingLocations">
<list>
<value>classpath:User.hbm.xml</value>
</list>
</property>
<property name="packagesToScan" value="edu.java.spring.service.user.model" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url"
value="jdbc:derby:D:\PROJECTSPRING\userdb;create=true" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="contentType" value="text/plain"/>
</bean>
</beans>
Add #RequestMapping(value="/user") at your class level and remove that part of the path at method level
I have a weird issue: entity manager can't create named query, I'm getting java.lang.IllegalArgumentException: Named query not found while methods, like find() and merge(), works. createQuery() also works. I'm using Hibernate as JPA provider and Spring as DI container. Code and configs are follows:
spring-beans.xml:
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:component-scan base-package="org.example.testapp.database" />
<bean id="newsForm" class="org.example.testapp.presentation.form.NewsForm">
<property name="newsMessage" ref="news" />
<property name="newsList">
<list>
<ref bean="news" />
</list>
</property>
</bean>
<bean name="news" class="org.example.testapp.model.News">
</bean>
<bean name="/news" class="org.example.testapp.presentation.action.NewsAction"
scope="prototype">
<property name="dao" ref="dao" />
</bean>
<bean id="dao" class="org.example.testapp.database.dao.JpaHibernateNewsDao"
scope="singleton">
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.example.testapp.model"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="login" />
<property name="password" value="password" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager" />
news.java
#Entity
#NamedQueries({
#NamedQuery(name="News.select", query="select n from News n order by news_date" ),
#NamedQuery(name="News.delete", query="delete from News where id in :value_list")
})
#Table(name="news")
public class News {
jpadao.java
public class JpaHibernateNewsDao implements Dao {
#PersistenceContext
private EntityManager entityManager;
#SuppressWarnings("unchecked")
#Override
#Transactional
public List<News> getList() throws DaoException {
List<News> news = entityManager.createNamedQuery("News.select").getResultList();
return news;
}
Found a answer: Spring just didn't see #Entity, so there was really no such #NamedQuery. Now I have to figure, why this config didn't work:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.example.testapp.model"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
I have a very simple requirement which has turned complicated and I have spent a day on it without any luck. I have a properties file called jdbc.properties which has the DB connection details. I need to create a datasource connection with the values from the property file. The property value is not being passed right now, leading to DB connectivity error messages. If I hardcode the property values in the bean, it works. My spring config file myBatis.DataSource.config.xml looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="newProperty"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-
init="true">
<property name="locations" value="jdbc.properties.${env}"/>
</bean>
<bean id="newDataSource" class="org.apache.commons.dbcp.BasicDataSource" depends-
on="newProperty" destroy-method="close">
<property name="username" value="${DBUSER}" />
<property name="password" value="${DBPASSWORD}" />
<property name="url" value="${DBURL}" />
<property name="driverClassName" value="${DRIVER}" />
<property name="poolPreparedStatements" value="false" />
<property name="defaultAutoCommit" value="false" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="defaultTransactionIsolation" value="2" />
<property name="timeBetweenEvictionRunsMillis" value="10000" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation"
value="com/automation/config/oneValidation-config.xml" />
<property name="dataSource" ref="newDataSource" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="basePackage" value="com.automation.config" />
</bean>
</beans>
The value for ${env} is passed as a system property to the class. The code for the class is as below:
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MybatisTest {
public static void main(String[] args) {
MybatisTest mybatisTest = new MybatisTest();
mybatisTest.testSelectQuery();
}
public void testSelectQuery(){
String resource = "oneValidation-config.xml";
SqlSession session = null;
try {
ApplicationContext context = new ClassPathXmlApplicationContext("myBatis.DataSource.config.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)context.getBean("sqlSessionFactory");
session = sqlSessionFactory.openSession(ExecutorType.BATCH);
System.out.println("Test" +
session.selectOne("com.automation.config.PostingMapper.
countByExample",null));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(session != null)
session.close();
}
}
}
The error I am getting is as shown below and is sue to the fact that the ${DBUSER}, ${DBPASSWORD} fields are not being retrieved from the property file jdbc.properties:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause:
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC
Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot
create PoolableConnectionFactory (JZ00L: Login failed. Examine the SQLWarnings chained
to this exception for the reason(s).)
I ran accross this as well. In the mybatis documentation here I found why this happens.
From the source: "NOTE sqlSessionFactoryBean and sqlSessionTemplateBean properties were the only option available up to MyBatis-Spring 1.0.2 but given that the MapperScannerConfigurer runs earlier in the startup process that PropertyPlaceholderConfigurer there were frequent errors. For that purpose that properties have been deprecated and the new properties sqlSessionFactoryBeanName and sqlSessionTemplateBeanName are recommended."
Try changing your MapperScannerConfigurer bean from
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="basePackage" value="com.automation.config" />
</bean>
to
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<property name="basePackage" value="com.automation.config" />
</bean>
Try this:
<property name="locations" value="classpath:/yourFolderName/jdbc.properties"/>
I'm building an application that needs CRUD operations on two separate databases. The transactions are applied to one database or the other (never both...so no need for JTA is my understanding). My setup is pretty close to what is found here: Multiple database with Spring+Hibernate+JPA
The problem: My server (JBoss AS7) starts up fine. The application reads from both datasources, say DS1 and DS2, BUT it can only manipulate data from DS1. I can see sequences (Oracle 11g) being updated but no table updates. There are no errors/exceptions thrown. I suspect one of my transaction managers isn't committing.
Below is a list of technologies used and configuration settings...
Tech Stack
JBoss AS7
Oracle 11g
Spring 3.1
JPA 2
Hibernate 4.1
persistence-ds1.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="pu1">
<class>com.somepackage.EntityA</class>
<class>com.somepackage.EntityB</class>
<class>com.somepackage.EntityC</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
</properties>
</persistence-unit>
</persistence>
persistence-ds2.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="pu2">
<class>com.somepackage.EntityD</class>
<class>com.somepackage.EntityE</class>
<class>com.somepackage.EntityF</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
</properties>
</persistence-unit>
</persistence>
applicationContext.xml
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="ds1" jndi-name="java:jboss/datasources/DS1"
expected-type="javax.sql.DataSource" />
<jee:jndi-lookup id="ds2" jndi-name="java:jboss/datasources/DS2"
expected-type="javax.sql.DataSource" />
<bean id="em1" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="emf1" />
<property name="persistenceUnitName" value="pu1" />
</bean>
<bean id="em2" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="emf2" />
<property name="persistenceUnitName" value="pu2" />
</bean>
<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-ds1.xml"/>
<property name="dataSource" ref="ds1" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence-ds2.xml"/>
<property name="dataSource" ref="ds2" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<tx:annotation-driven transaction-manager="txm1" />
<tx:annotation-driven transaction-manager="txm2" />
<bean id="txm1" class="org.springframework.orm.jpa.JpaTransactionManager">
<qualifier value="txMgr1"/>
<property name="entityManagerFactory" ref="emf1" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="txm2" class="org.springframework.orm.jpa.JpaTransactionManager">
<qualifier value="txMgr2"/>
<property name="entityManagerFactory" ref="emf2" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
</beans>
In my DAOs, I reference the transaction managers at the class-level as follows.
#Transactional("txm1")
public class DAO1 { ... }
#Transactional("txm2")
public class DAO2 { ... }
I resolved my issue!
In my applicationContext.xml, I removed the following.
<tx:annotation-driven transaction-manager="txm1" />
<tx:annotation-driven transaction-manager="txm2" />
And used the following instead.
<tx:annotation-driven />
But here's what I believe was the kicker (main problem). In my DAOs, I was assigning the two transaction managers at the class-level. But then I was overriding them with the way I was declaring my methods.
#Transactional(readOnly = false, value = "txm1")
public abstract class AbstractJpaDAO1<T extends Serializable> {
...
#Transactional(readOnly = true)
public T findById(final Long id) {...}
#Transactional
public boolean insert(final T entity) {...}
As you can see, the #Transaction annotations on the methods were overriding the the one at the class-level. And because there was no transaction manager specified on the methods, Spring defaulted to "transactionManager", which I didn't (and still don't) have declared in my applicaitonContext.xml. So, it was trying to commit using a transaction manager that didn't exist.
For the resolution, I just removed the #Transitional annotations on the methods, and kept the one at the class-level.
#Transactional(readOnly = false, value = "txm1")
public abstract class AbstractJpaDAO1<T extends Serializable> {
...
public T findById(final Long id) {...}
public boolean insert(final T entity) {...}
Now everything works! I can read/write to two separate databases.
I get this exception but I can not figure out what is wrong with my configuration
I am posting the relevent files thanks for any help
I am using
Spring 3.1.0.RELEASE
hibernate-entitymanager 3.6.10.Final (Should work with JPA 2)
Trying to run the code from a JUnit file
package com.successcharging.core.dao.jpa;
import junit.framework.Assert;
import org.junit.Before;
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;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import com.successcharging.core.security.dao.UserDao;
import com.successcharging.core.security.model.User;
import com.successcharging.core.security.model.UserImp;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:applicationContext/applicationContext*.xml"})
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
#Transactional
public class UserDaoImplTest {
private static final boolean ENABLED = true;
private static final String PASSWORD = "password";
private static final String USERNAME = "joe.bloggs";
#Autowired
private UserDao userDao;
private User user;
#Before
public void before() {
user = new UserImp();
user.setName(USERNAME);
user.setPassword(PASSWORD);
user.setEnabled(ENABLED);
userDao.save(user);
}
#Test
public void findByUserName() {
Assert.assertNotNull(user);
User user2 = userDao.findById(user.getId());
Assert.assertNotNull(user2);
Assert.assertEquals(USERNAME, user2.getName());
}
}
applicationContext.xml
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.successcharging.core" />
</beans>
applicationContext-persistence.xml
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="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.xsd">
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.successcharging.core" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLInnoDBDialect" />
</bean>
</property>
<property name="persistenceUnitName" value="successcharging.core.security" />
<property name="persistenceUnitManager">
<bean
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" />
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://192.168.1.129:3306/SC_SECURITY" />
<property name="username" value="sc_admin" />
<property name="password" value="123" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
</beans>
persistence.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="successcharging.core.security"
transaction-type="RESOURCE_LOCAL">
<properties>
<property name="cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.query.factory_class"
value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory" />
<property name="hibernate.query.substitutions" value="true 1, false 0" />
</properties>
</persistence-unit>
I found the problem I had to add the datasource to the persistenceUnitManager something like this
<property name="persistenceUnitManager">
<bean class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
I was facing similar issue but was not using datasource in my case issue got resolved by adding hibernate key while providing database details in my persistence.xml file. Note that Hibernate 3.x and 4.x have different syntax as mentioned below (hit this while downgrading Hibernate 4.x to 3.x).
Changed below (Hibernate 4.x syntax) :
<properties>
<property name="javax.persistence.jdbc.driver" value="..."/>
<property name="javax.persistence.jdbc.url" value="..."/>
<property name="javax.persistence.jdbc.user" value="..."/>
<property name="javax.persistence.jdbc.password" value="..."/>
</properties>
With (Hibernate 3.x syntax) :
<properties>
<property name="hibernate.connection.driver_class" value="..."/>
<property name="hibernate.connection.url" value="..."/>
<property name="hibernate.connection.username" value="..."/>
<property name="hibernate.connection.password" value="..."/>
</properties>