save is not valid without active transaction - hibernate&spring - java

First of all, I have searched other similar questions here before.Though, I couldn't figure out where I have mistaken.
In Eclipse, I have been building a simple Hibernate+Spring+MySQL+Maven project recently.I am having trouble at the stage of database&java connection.When I run the project, it gives the the following error:
WARN : org.hibernate.internal.util.xml.DTDEntityResolver - HHH000223:Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
WARN : org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator - HHH000181: No appropriate connection provider encountered, assuming application will be supplying connections
Transaction began Exception in thread "main" org.hibernate.HibernateException: save is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
at com.sun.proxy.$Proxy19.save(Unknown Source)
at com.test.Main.main(Main.java:33)
The main class:
package com.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import com.hibernate.data.Person;
public class Main {
public static void main(String [] args){
// Create a configuration instance
Configuration configuration = new Configuration();
// Provide configuration file
configuration.configure("hibernate.cfg.xml");
// Build a SessionFactory
SessionFactory factory = configuration.buildSessionFactory(new StandardServiceRegistryBuilder().configure().build());
// Get current session, current session is already associated with Thread
Session session = factory.getCurrentSession();
// Begin transaction, if you would like save your instances, your calling of save must be associated with a transaction
Transaction tx = session.getTransaction();
// Create person
Person newPerson = new Person();
newPerson.setFirstName("Peter");
newPerson.setLastName("Jackson");
newPerson.setGender("Male");
newPerson.setAge(30);
//Save
session.save(newPerson);
session.flush();
tx.commit();
session.close();
}
}
hbm.xml file:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class table="Person" lazy="false" name="com.hibernate.data.Person" >
<id column="PERSON_ID" type="int" name="id" >
<generator class="increment"/>
</id>
<property name="firstName" column="PERSON_FIRSTNAME" type="string" />
<property name="lastName" column="PERSON_LASTNAME" type="string" />
<property name="gender" column="PERSON_GENDER" type="string" />
<property name="age" column="PERSON_AGE" type="int" />
</class>
</hibernate-mapping>
hibernate.cfg.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/PERSONDB</property>
<property name='connection.username'>root</property>
<property name='connection.password'>root</property>
<!-- SQL dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Specify session context -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- Show SQL -->
<property name="show_sql">true</property>
<!-- Referring Mapping File -->
<mapping resource="domain-classes.hbm.xml"/>
<mapping class="com.hibernate.data.Person"/>
</session-factory>
</hibernate-configuration>
applicationContext.xml file:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- Enable Spring Annotation Configuration -->
<context:annotation-config />
<!-- Scan for all of Spring components such as Spring Service -->
<context:component-scan base-package="com.spring.service"></context:component-scan>
<!-- Create Data Source bean -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/PERSONDB" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- Define SessionFactory bean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>domain-classes.hbm.xml</value>
</list>
</property>
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Detect #Transactional Annotation -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
How can I fix this?

You forgot to begin the transaction:
Transaction tx = session.getTransaction();
tx.begin();
or, easier:
Transaction tx = session.beginTransaction();
Note that your problem is unrelated to Spring, since you're not using Spring at all in the posted code. When you do, you'll have to fix your Spring configuration: don't use classes from the hibernate3 package, since you're using hibernate4. Also, learn to use annotations and not hbm.xml files to map your entities. XML was useful in Java 1.4. But we're noaw at Java 1.8.

Related

Spring 4 + Hibernate 4 configuration

I am trying to do Spring 4 + Hibernate 4 configuration. But I am facing sessionFactory = null in the Controller. Below are the configurations and code.
What is the mistake in this configuration?
spring-database.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- MySQL data source -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/personal" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>/orm/Song.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="songDao" class="com.letsdo.impl.SongImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- MUST have transaction manager, using aop and aspects -->
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</beans>
orm/Song/hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.letsdo.model.Song" table="song" catalog="personal">
<id name="id" type="int">
<column name="id" length="45" />
<generator class="increment"/>
</id>
<property name="filePath" column="filepath"/>
<property name="fileName" column="filename"/>
<property name="album" column="album"/>
<property name="title" column="title"/>
<property name="size" column="size"/>
</class>
</hibernate-mapping>
SongDao.java
public interface SongDao {
public List<String> getAllAlbums();
}
SongImpl.java
#Service
#Transactional
public class SongImpl implements SongDao{
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public List<String> getAllAlbums(){
List<String> allAlbums = new ArrayList<String>();
Query query = getSessionFactory().getCurrentSession().createQuery("Select DISTINCT Album from song");
allAlbums = query.list();
return allAlbums;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Controller: HomeController.java
public class HomeController {
#Autowired private SongImpl songDao;
#RequestMapping(value="/", method=RequestMethod.GET)
public ModelAndView welcomePageBeforeLogin(HttpServletRequest request, HttpServletResponse response,HttpSession session){
ModelAndView model = new ModelAndView();
List<String> album = songDao.getAllAlbums();
model.addObject("albumsize",album.size());
model.setViewName("hello");
return model;
}
}
I think you are ending up with two beans of class SongImpl - one that is defined in xml (named songDao), and another one annotated with #Service (named by default songImpl). The latter one has no SessionFactory autowired, that's why it is null.
You can find more info about it in one of the answers here.
If component scanning is enabled, spring will try to create a bean
even though a bean of that class has already been defined in the
spring config xml. However if the bean defined in the spring config
file and the auto-discovered bean have the same name, spring will not
create a new bean while it does component scanning.
The solution is to remove the xml version of the bean (if you don't need it), and to autowire SessionFactory in SongImpl.

Insert into DB non-English characters with Spring 4 + Hibernate 4

I have Spring 4 + Hibernate 4 + MySQL web application. I need initialize DB tables when app are starting. For this goal I use import.sql file and set Hibernate hbm2ddl.auto to create. When Hibernate execute requests I have hieroglyphs in DB. I try use
<property name="url" value="jdbc:mysql://localhost:3306/foxrest_db?useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8" />
for connection, but it has no effect.
I think Spring open files with standard system environment encoding (in my case it's Windows 8.1, encoding: win1251), that's why all Hibernate configurations has no effect.
My question is:
1.How can I fix this?
2.If I will use PostgreSQL in future what I will change in DB connection or another configs?
Here is my sources:
spring.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<context:annotation-config />
<context:component-scan base-package="org.foxresult" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/foxrest_db" />
<property name="username" value="lekarto" />
<property name="password" value="1" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.internal.NoCachingRegionFactory</property>
<property name="hibernate.cache.default_cache_concurrency_strategy">transactional</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create</property>
<property name="hibernate.connection.useUnicode">true</property>
<property name="hibernate.connection.characterEncoding">UTF-8</property>
<property name="hibernate.connection.charSet">UTF-8</property>
</session-factory>
</hibernate-configuration>
import.sql
INSERT INTO `departments` (`name`) VALUES ('Developers'), ('QA'), ('Managers'), ('Support');
INSERT INTO `employees` (`first_name`, `last_name`, `salary`, `sex`, `department_id`) VALUES ('Sergey', 'Fedorov', '100', 1, '1'), ('Иван', 'Демидов', '120', 1, '1'), ('الحسيب', 'عبد', '140', 1, '2'), ('Angelina', 'Feofilaktova', '160', 0, '3'), ('湧', '阮', '180', 0, '3'), ('Test', 'Ivanovna', '180', 0, NULL);
I think the character encoding property for the JVM needs to be set.
Have you tried starting the Java App with this:
java -Dfile.encoding=UTF-8
If you are using Tomcat, then you may have to set this System property in one of the Tomcat's (catalina) script files.
Note: In past I have used only ISO-8559-1. both the Java app, and the Database were set to ISO-8559-1
UPDATE:
If maven surefire plugin is being used, then system property should be given according to this link:
http://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html
Note that the website mentions special case for JVM system properties:
<argLine>-Djava.endorsed.dirs=...</argLine>

resource: net/codejava/spring/model/User.hbm.xml not found - Spring and Hibernate Configuration Errors

I downloaded a tutorial project in an attempt to get Spring and Hibernate working. However, after running it on the server I get this message:
Invocation of init method failed; nested exception is org.hibernate.MappingNotFoundException: resource: net/codejava/spring/model/User.hbm.xml not found
Here is my project structure:
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping resource="net/codejava/spring/model/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
user.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="net.codejava.spring.model">
<class name="User" table="users">
<id name="id" column="user_id">
<generator class="native"/>
</id>
<property name="username" column="username" />
<property name="password" column="password" />
<property name="email" column="email" />
</class>
</hibernate-mapping>
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<context:component-scan base-package="net.codejava.spring" />
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://domain:3306/databaseHere"/>
<property name="username" value="insertUserHere"/>
<property name="password" value="insertPassHere"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDao" class="net.codejava.spring.dao.UserDAOImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
</beans>
Any ideas as to what's going wrong?
You have a maven project so the User.hbm.xml should be inside src/main/resources/ instead of src/main/java
When you build a maven project then it compiles are the .java files present in src/main/java and it will not consider any other files which are present in this directory. So the maven project has a folder structure src/main/resources where you can place all your configuration files like .xml, .properties etc. So when you build the maven project then it will compile all the java files from src/main/resources and places the .class files in classpath and also maven will copy all the resources from src/main/resources and places them in classpath. So when you run the application then the configuration files will also available in classpath.
But if you just place the configuration files in src/main/java then maven will just ignore them so they will not be available in classpath.
But if the project you are working on is a simple java project instead of maven project then the code setup mentioned in your question will work without any issues even when you have the configuration files in src/main/java. Hope this explanation helps.
To make sure the maven project is build properly you can verify by opening the directory target/classes/ and then the path to your configuration files.
So, to sum up all this information, here's what you need to do:
Creat a package structure in /src/main/resources that mimics the one in /src/main/java - that is, create the net.codejava.spring.model package in /src/main/resources and place User.hbm.xml in there. After running a Maven clean package (or some other build goal) command, the User.hbm.xml file will be in it's correct location (which is not shown in the picture below) - /target/SpringMvcHibernateXML-1.0.0-BUILD-SNAPSHOT/WEB-INF/classes/net/codejava/spring/model/User.hbm.xml.
Ultimately, after building in Maven, the project should look like this:

Using Multiple Entity managers in DAO

I'm trying to configure Spring+Hibernate+JPA for work with two databases ( one for write only i.e insertion & updation & other is only for retrieval.
I did some research & found these possible solutions:
http://www.studytrails.com/frameworks/spring/spring-hibernate-jpa.jsp
Multiple database with Spring+Hibernate+JPA
How do I connect to multiple databases using JPA?
But I stuck at one place & getting this error
No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: entityManagerFactoryReadOnly,entityManagerFactoryWriteOnly
What am I doing wrong ?
persistent.read.only.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="readOnly" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.demo.domain.Contact</class>
</persistence-unit>
</persistence>
persistent.write.only.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="writeOnly" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.demo.domain.Contact</class>
</persistence-unit>
</persistence>
mcv-dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.2.xsd">
<!-- Activates various annotations to be detected in bean classes -->
<context:annotation-config />
<!-- Scans the classpath for annotated components that will be auto-registered
as Spring beans. For example #Controller and #Service. Make sure to set the
correct base-package -->
<context:component-scan base-package="com.demo" />
<!-- Setup a simple strategy: 1. Take all the defaults. 2. Return XML by
default when not sure. -->
<!-- Total customization - see below for explanation. -->
<bean id="cnManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true" />
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="application/json" />
<property name="useJaf" value="false" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>
<!-- Make this available across all of Spring MVC -->
<mvc:annotation-driven
content-negotiation-manager="cnManager" />
<bean class="com.demo.view.MvcConfiguringPostProcessor" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<!-- ******************************************************************** -->
<!-- START: Multiple C3P0 data-sources for DB instance -->
<!-- ******************************************************************** -->
<!-- https://stackoverflow.com/questions/12922351/can-i-use-multiple-c3p0-datasources-for-db-instance -->
<!-- Using Apache DBCP Data Sources -->
<bean id="dataSource"
abstract="true" >
<property name="driverClass" value="${db.driverClassName}" />
<property name="user" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="idleConnectionTestPeriod" value="${db.idleConnectionTestPeriod}" />
<property name="preferredTestQuery" value="select 1" />
<property name="testConnectionOnCheckin" value="true" />
</bean>
<bean id="dataSourceReadOnly"
parent="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="jdbcUrl" value="${db.readOnlyDataBaseUrl}" />
</bean>
<bean id="dataSourceWriteOnly"
parent="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="jdbcUrl" value="${db.writeOnlyDataBaseUrl}" />
</bean>
<!-- ******************************************************************** -->
<!-- END: Multiple C3P0 data-sources for DB instance -->
<!-- ******************************************************************** -->
<bean id="jpaVendorProvider"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="${db.dialect}" />
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
<!-- <bean -->
<!-- class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"> -->
<!-- <property name="defaultPersistenceUnitName" value="readOnly" /> -->
<!-- </bean> -->
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<!-- defining multiple persistence unit -->
<property name="persistenceXmlLocations">
<list>
<value>/META-INF/persistence.read.only.xml</value>
<value>/META-INF/persistence.write.only.xml</value>
</list>
</property>
<property name="defaultDataSource" ref="dataSourceReadOnly" />
<property name="dataSources">
<map>
<entry key="readOnlyDsKey" value-ref="dataSourceReadOnly" />
<entry key="writeOnlyDsKey" value-ref="dataSourceWriteOnly" />
</map>
</property>
</bean>
<bean id="entityManagerFactoryReadOnly"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- <property name="dataSource" ref="dataSourceReadOnly" /> -->
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="jpaVendorAdapter" ref="jpaVendorProvider" />
<property name="persistenceUnitName" value="readOnly" />
<!-- entityManagerFactory does not specify persistenceUnitName property
because we're defining more than one persistence unit -->
<!-- <property name="persistenceUnitName" value="hello_mysql" /> -->
<!-- <property name="persistenceXmlLocation" value="/META-INF/persistence.xml" /> -->
</bean>
<bean id="entityManagerFactoryWriteOnly"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- <property name="dataSource" ref="dataSourceWriteOnly" /> -->
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="jpaVendorAdapter" ref="jpaVendorProvider" />
<property name="persistenceUnitName" value="writeOnly" />
</bean>
<!-- ******************************************************************** -->
<!-- Mark bean transactions as annotation driven -->
<!-- ******************************************************************** -->
<tx:annotation-driven transaction-manager="transactionManagerReadOnly" />
<tx:annotation-driven transaction-manager="transactionManagerWriteOnly" />
<!-- ******************************************************************** -->
<!-- Setup the transaction manager -->
<!-- ******************************************************************** -->
<bean id="transactionManagerReadOnly" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryReadOnly" />
</bean>
<bean id="transactionManagerWriteOnly" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryWriteOnly" />
</bean>
</beans>
My DAO:
package com.demo.dao;
import java.util.Collections;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.demo.domain.Contact;
//import java.util.Collections;
#Repository("ContactDAO")
#Transactional
public class ContactDAOImpl extends AppDAOimpl<Contact> implements ContactDAO {
/**
*
*/
private static final long serialVersionUID = 3986253823316728444L;
/**
* EntityManager injected by Spring for persistence unit MYSQL
*
*/
#PersistenceContext(unitName = "readOnly")
#Qualifier("entityManagerFactoryReadOnly")
private EntityManager entityManager;
/**
* Get the entity manager that manages persistence unit MYSQL
*
*/
public EntityManager getEntityManager() {
return entityManager;
}
/**
* EntityManager injected by Spring for persistence unit MYSQL
*
*/
#PersistenceContext(unitName = "writeOnly")
#Qualifier("entityManagerFactoryWriteOnly")
private EntityManager woEntityManager;
/**
* Get the entity manager that manages persistence unit MYSQL
*
*/
public EntityManager getWoEntityManager() {
return woEntityManager;
}
// other functions goes here
}
Both the databases have the same schema ( read & write ).
We have a similar setup in a project here, and I think
#PersistenceContext(unitName = "writeOnly")
private EntityManager woEntityManager;
is sufficient, you don't need the additional Qualifier. But in my experience, you have to set the attribute on Transactional, too. So drop the Transactional annotation on the DAO class and start marking individual methods with
#Transactional(value="transactionManagerReadOnly")
and i believe the tx:annotation-driven element in the context doesn't work with multiple contexts, too.
And ideally, the whole stuff belongs into the service layer anyway, you don't want your DAOs to decide or even know which Persistence context they're called from. So you'd have a ReadContactService:
#PersistenceContext(unitName = "readOnly")
private EntityManager em;
#Transactional(value="transactionManagerReadOnly")
public Contact readContact(int id) {
return dao.findById(em, id);
}
and a WriteContactService:
#PersistenceContext(unitName = "writeOnly")
private EntityManager em;
#Transactional(value="transactionManagerWriteOnly")
public void writeContact(String name, String address) {
return dao.writeContact(em, name, address);
}
and a DAO that is unaware of the context. Then you need only N entity classes and you can reuse DAO methods (even writeOnly will eventually have to read from the database, trust me).
JTA transaction manager. is answer to my question. Below are links for references.
JPA Multiple Transaction Managers
Spring multiple #Transactional datasources
& here is nice tutorial about integrating JTA with spring.
http://www.javacodegeeks.com/2013/07/spring-jta-multiple-resource-transactions-in-tomcat-with-atomikos-example.html
Add two classes
ContactWrite.java
on top declare the schema and table like below
#Table(name = "Contact", schema="DB1")
Do the same for the other table in the DB2
ContactRead.java
#Table(name = "Contact", schema="DB2")
Now use these two classes in the persistance xml files like below.
persistent.read.only.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="readOnly" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.demo.domain.ContactWrite</class>
</persistence-unit>
</persistence>
persistent.write.only.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="writeOnly" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.demo.domain.ContactRead</class>
</persistence-unit>
</persistence>

problems with Hibernate's integration in Spring

I have a simple Java application and I'm trying to integrate Hibernate in Spring but it seems that the Spring configuration file can't find the *.hbm.xml (the mapping resource):
I have a file named persistence-context.xml that I use it as a Spring config file and I have the following bean declared:
org.hibernate.dialect.MySQLDialect
But is being thrown the exception:
java.io.FileNotFoundException: class path resource [pool.hbm.xml] cannot be opened because it does not exist
I've even tried giving the mapping resources property an absolute path value. It doesn't work.
Thank you!
UPDATE:
My Spring conf file:
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value='jdbc:mysql://localhost/bestofs_seinfeld' />
<property name="username" value="root" />
<property name="password" value="futifuti825300" />
<property name="initialSize" value="5" />
<property name="maxActive" value="10" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources" value="pool.hbm.xml" />
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="voteDao" class="bestofs.persistence.HibernatePoolDao">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
</beans>
And my pool.hbm.xml is:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="bestofs.persistence.PoolBean" table="sein_pool">
<id name="idVote" column="ID_Vote">
<generator class="assigned"/>
</id>
<property name="IdActor">
<column name="ID_Actor"/>
</property>
<property name="IdUser">
<column name="ID_User"/>
</property>
<property name="IdSession">
<column name="ID_Session"/>
</property>
</class>
</hibernate-mapping>
And both configuration files are on the same folder.
If you are giving absolute path to the file location on disk (e.g. c:/mapings/pool.hbm.xml), it will not work, because it searches for mapping on a class path. Mapping file should be inside your jar or in IDE class path.
If you are using Tomcat + web project, you should create resource folder inside your src folder and put your mapping files there it will be equal to:
<property name="mappingResources">
<list>
<value>object.hbm.xml</value>
</list>
</property>
Hope it helps.
Use
<property name="mappingResources" value="pool.hbm.xml" />
and put pool.hbm.xml in the root of your classpath. I.e. your bestofs.persistence.PoolBean will be in a directory structure like <somewhere>/bestofs/persistence/PoolBean.class. The mapping file should be inside <somewhere>, right alongside bestofs.
That's all you need to do unless you have some strange ClassLoader magic happening.

Categories