Spring JPA error: A JTA EntityManager cannot use getTransaction() - java

I've got a problem with my Spring web application with JPA and Glassfish server. When I'm trying to add new entry to a database (entityManager.persist()), I receive:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
Here's my code:
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="LibraryPU">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/sample</jta-data-source>
<properties>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
dispatcher-servlet.xml
<?xml version='1.0' encoding='UTF-8' ?>
<!-- was: <?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-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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<context:component-scan base-package="service, controller, dao" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="persistenceUnitName" value="LibraryPU" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="HSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost:1527/Library" />
<property name="username" value="app" />
<property name="password" value="app" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
UserDao.java
package dao;
import entity.User;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Repository("userDao")
#Transactional
public class UserDao {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void insert(User user) {
entityManager.persist(user);
entityManager.flush();
}
}
Thanks in advance!

if You want to use JTA transaction in your code then
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
remove the JpaTransactionManager and replace it with a JTA transaction manager.
Also define the transacation-type="JTA" like
<persistence-unit name="LibraryPU" transaction-type="JTA">
in persistence.xml.

Related

Spring mvc + hibernate/jpa -> entity manager is not injected despite #PersistenceContext

I have a problem with EntityManager. When I try to use EntityManager in a dao class, I got null pointer exception. So EntityManager is not injected despite #PersistenceContext annotation.
My dao:
package com.fido.pia.dao;
import com.fido.pia.model.User;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Repository
public class UserDao {
#PersistenceContext
protected EntityManager entityManager;
public User save(User row) {
if(row.isNew()) {
entityManager.persist(row);
return row;
} else {
return entityManager.merge(row);
}
}
}
Servlet Config:
<?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"
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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--
Adds some default beans (HandlerAdapter, HandlerMapping, Binding Initializer...). It also turn on some annotations.
Explanation in http://stackoverflow.com/questions/28851306/spring-framework-what-is-the-purpose-of-mvcannotation-driven
WITHOUT THIS, #RequestMapping ANNOTATIONS ARE LOADED, BUT MAPPING DO NOT WORK!!
-->
<mvc:annotation-driven />
<!-- Set loading annotations from classes
<context:component-scan base-package="com.fido.pia"/>-->
<!--manual homepage-->
<mvc:view-controller path="/" view-name="home"/>
<!--view resolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<!--static resources - request will be handeled by ResourceHttpRequestHandler-->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!--database config-->
<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/pia" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!--entity manager factory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.fido.pia" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--<property name="generateDdl" value="true" />-->
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--Set loading annotations from classes-->
<context:component-scan base-package="com.fido.pia"/>
</beans>
Any ideas what is wrong here?
In entityManagerFactory bean definition, try this :
<property name="packagesToScan" value="com.fido.pia.*" />
This should work
I finally solve it. The problem was that I use common dependency injection to inject my dao class in controller. When I change it to DI with autowired (added #autowired to controller constructor), entity manager in dao is initialized.
So now it works, but I'm still curious about why is that change so important. I've asked new question about it.
You need to enable persistence annotations:
<context:annotation-config/>
or
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

Request processing failed; nested exception is javax.persistence.TransactionRequiredException: No transactional EntityManager available

An exception occurs while I'm trying to persist an object.
import org.springframework.transaction.annotation.Transactional;
#Repository("DBRepository")
#Transactional
public class DBRepository implements Repository {
#PersistenceContext
private EntityManager entityManager;
#Override
public void addElement(Element element) {
logger.debug("Element {} is going to be added to database", element);
entityManager.persist(element);
}
}
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<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="p_unit" transaction-type="RESOURCE_LOCAL"/>
</persistence>
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/jpa-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
jpa-config.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"
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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- Using annotation to configure application -->
<context:annotation-config/>
<context:component-scan base-package="web.tmh"/>
<!-- Tells Spring to use persistence context annotation -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<tx:annotation-driven mode="proxy" transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="p_unit"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<entry key="hibernate.hbm2ddl.auto" value="update"/>
</map>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!-- autoReconnect=true param allows our application to reconnect to base if connection was lost -->
<property name="url" value="jdbc:mysql://localhost:3306/TellMeHow?autoReconnect=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
So as you can see I used right Transactional annotation, and have <tx:annotation-driven mode="proxy" transaction-manager="transactionManager"/>in my jpa-config.xml. So I don't really understand why it doesn't want do work
Ok, the problem was solved. I've made a small mistake in my dispatcher-config.xml:
So instead of
<mvc:annotation-driven/>
<context:component-scan base-package="web.tmh"/>
I had to write
<mvc:annotation-driven/>
<context:component-scan base-package="web.tmh.controller"/>
I thought that component-scan worked recursively, but seems like it didn't...

Insert into two tables in two different database

My Java web application on spring framework is using two database say database-1 and database-2. Both database have User table. What I am trying to do is to insert record into both tables at same time.
There are two persistence-unit in the persistence.xml that is pointing out to database.
Here is my persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<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_1_0.xsd"
version="1.0">
<persistence-unit name="p1-jpa" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/MySqlDS2</jta-data-source>
<class>com.xyz.entity.User</class>
<exclude-unlisted-classes />
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
</properties>
</persistence-unit>
<persistence-unit name="p2-jpa" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/MySqlDS2</jta-data-source>
<class>com.mmxhealthcare.entity.MMASCUser</class>
<exclude-unlisted-classes />
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
</properties>
</persistence-unit>
</persistence>
Now Whenever I am trying to add user, it is inserted only in Database-1. I am not getting any exception.
Here is my spring-servlet.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:jaxrs="http://cxf.apache.org/jaxrs"
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:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util" xmlns:security="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="0"/>
</bean>
<!-- <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean> -->
<context:property-placeholder location="classpath:config.properties" />
<context:annotation-config />
<context:component-scan base-package="com.xyz.controller" />
<context:component-scan base-package="com.xyz.service" />
<context:component-scan base-package="com.xyz.dao" />
<context:component-scan base-package="com.xyz.security" />
<context:component-scan base-package="com.xyz.dto" />
<context:component-scan base-package="com.xyz.util" />
<context:component-scan base-package="com.xyz.entity" />
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="aaentityManagerFactory" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="mmascentityManagerFactory" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="d1SourceLocal" />
<property name="persistenceUnitName" value="p1-jpa" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="mmascentityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="d2DataSourceLocal" />
<property name="persistenceUnitName" value="p2-jpa" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<!-- <bean id="dataSourceLocal" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/datasources/MySqlDS2"/>
</bean> -->
<!-- Local -->
<bean id="d1SourceLocal"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="d2DataSourceLocal"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${d2-database.driver}" />
<property name="url" value="${d2-database.url}" />
<property name="username" value="${d2-database.username}" />
<property name="password" value="${d2-database.password}" />
</bean>
</beans>
Here it is my service class:
public class Userservice{
#Autowired
Database2IUserDAO immDao;
#Autowired
Database1IUserDAO iaaDao;
public User saveUser(fname,address){
User u = new User(); // This points Database-1 User table.
u.setFname(fname);
u.setAddress(address);
iaaDao.save(u);
User2 u2 = new User2(); // This points Database-2 User table.
u2.setFname(fname);
u2.setAddress(address);
immDao.save(u2);
}
}
Here is my Database1IUserDAO //This is an Interface
package com.xyz.dao;
public interface Database1IUserDAO {
public Object save(Object ob);
}
Here is my Database2IUserDAO //This is an another Interface for database2
package com.xyz.dao;
public interface Database2IUserDAO {
public Object save(Object ob);
}
** And this is finally DAO class for Database-1 and Database 2**
My both DAO class extends BaseDao class, that have Save() method that we are using to insert or save.
BaseDao.java
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
public class BaseDAO {
protected EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this. entityManager = entityManager;
}
#Transactional
public Object save(Object ob) {
Object object = entityManager.merge(ob);
return object;
}
#Transactional
public void remove(Object ob) {
Object object = entityManager.merge(ob);
entityManager.remove(object);
}
#Transactional
public int update(String query) {
return entityManager.createQuery(query).executeUpdate();
}
}
Please help.
You have to use database specific Transaction Manager as you mentioned in your spring-context.xml file as below.
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="mmascentityManagerFactory" />
</bean>
You should create a save function in your DAO Class with database specific Transaction Manager as follows:
#Transactional(value="transactionManager2")
public Object save(Object ob) {
Object object = entityManager.merge(ob);
return object;
}
I hope it will work for you.
You seem to be using the same EntityManager (EM) from the BaseDAO for all your DAOs. Since you don't specify which TransactionManager the EM is using, it will default to this one:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
... as noted in the documentation http://docs.spring.io/spring/docs/2.0.8/reference/transaction.html (find table 9.2)
If you want to write to another database, you will need to explicity tell Spring which one you want to use. See this answer as an example:
Spring multiple #Transactional datasources
It looks you are using the same datasource for both the persistence unit.
ie java:jboss/datasources/MySqlDS2
so it is inserting into only one DB which is corresponding to above data source mstly Mysql DB.
so add different datasource in both the persistence-unit , and that should help you to insert to both the databases.
it wont give any exception because one datasource that you are using might be valid datasource(i cant guarantee as we dont have data source information in your post).
let me know for any thing else.

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>

EntityManager and persist method not working properly

I'm in trouble here..
I'm new using Spring + Hibernate in a Java SE application...
I'm trying to instantiate the entityManager, but it's not working
I'm using the annotation #PersistenceUnit, like this:
#PersistenceUnit
public void setEmf(EntityManager emf) {
this.emf = emf;
}
And it works "fine", but it doesn't persist =/
When I change to
#PersistenceContext
public void setEmf(EntityManager emf) {
this.emf = emf;
}
It came out the following error:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'daoAbstract' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy10 implementing org.hibernate.ejb.HibernateEntityManagerFactory,org.springframework.orm.jpa.EntityManagerFactoryInfo' to required type 'javax.persistence.EntityManager' for property 'emf'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy10 implementing org.hibernate.ejb.HibernateEntityManagerFactory,org.springframework.orm.jpa.EntityManagerFactoryInfo] to required type [javax.persistence.EntityManager] for property 'emf': no matching editors or conversion strategy found
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:532)
Here's my 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: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-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="ConfiguradorDePropriedades"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<description>The service properties file</description>
<property name="location" value="file:AppConfig.properties" />
</bean>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- <property name="persistenceUnitName" value="ChatJpa" /> -->
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="dataSource" ref="dataSourceLocal" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="${database}" />
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSourceLocal"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.pass}" />
</bean>
<bean id="daoAbstract" class="com.planner.pvc.dao.DaoAbstract">
<property name="emf" ref="entityManagerFactory" />
</bean>
<bean id="clienteDao" class="com.planner.pvc.dao.ClienteDaoImpl">
</bean>
<bean id="pvcMainController" class="com.planner.pvc.controller.PVCMainController">
<property name="dao" ref="clienteDao" />
</bean>
</beans>
And 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="ChatJpa">
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.connection.driver_class" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<!-- <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" /> -->
</properties>
</persistence-unit>
</persistence>
Any help would be appreciated.
Thanks
This line is the problem:
<bean id="daoAbstract" class="com.planner.pvc.dao.DaoAbstract">
<property name="emf" ref="entityManagerFactory" />
</bean>
Instead of doing this, let Spring inject the emf field annotated with #PersistenceContext, this will happen if you have a <context:component-scan.../> or <context:annotation-config/> tags in your application context or just add the latter.

Categories