I'm trying to add one more database/schema/persistenceUnit in my project and I'm receiving the error:
No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
I google/api allot and could not found why spring is complaining about my configuration.
Here is part of my applicationContext.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="transactionManager" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${show.hibernate.sql}" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driver}" />
<property name="url" ...
<property name="testOnBorrow" value="true" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactoryREST" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceREST" />
<property name="persistenceUnitName" value="REST" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${show.hibernate.sql}" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<bean id="dataSourceREST" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driver}" />
...
<property name="testOnBorrow" value="true" />
</bean>
<bean id="transactionManagerREST" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryREST" />
</bean>
<tx:annotation-driven transaction-manager="REST"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
Some questions:
Do I need to have two tx:annotation-driven ?
Do I need to specify persistenceUnitName in the factory ?
I'm putting some notes of my digg in spring forum (LINK)
Well thats it... any help will be glad!
With Spring, you need to have only one EntityManagerFactory.
What you are looking for is describe in the Spring documentation at the chapiter 13.5.1.4 : "Deals with multiple persitence units"
I copy/paste the text :
"13.5.1.4 Dealing with multiple persistence units
For applications that rely on multiple persistence units locations, stored in various JARS in the classpath, for example, Spring offers the PersistenceUnitManager to act as a central repository and to avoid the persistence units discovery process, which can be expensive. The default implementation allows multiple locations to be specified that are parsed and later retrieved through the persistence unit name. (By default, the classpath is searched for META-INF/persistence.xml files.)
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
<value>classpath:/my/package/**/custom-persistence.xml</value>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="dataSources">
<map>
<entry key="localDataSource" value-ref="local-db"/>
<entry key="remoteDataSource" value-ref="remote-db"/>
</map>
</property>
<!-- if no datasource is specified, use this one -->
<property name="defaultDataSource" ref="remoteDataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="pum"/>
<property name="persistenceUnitName" value="myCustomUnit"/>
</bean>
The default implementation allows customization of the PersistenceUnitInfo instances, before they are fed to the JPA provider, declaratively through its properties, which affect all hosted units, or programmatically, through the PersistenceUnitPostProcessor, which allows persistence unit selection. If no PersistenceUnitManager is specified, one is created and used internally by LocalContainerEntityManagerFactoryBean."
This exceptions means that you are trying to autowire EntityManagerFactory by type. Do you have any #Autowired annotation in your code?
Aslo, when using #PersistenceContext, set the unit attribute correctly. And (I'm not sure if this is a proper thing to do) - try setting the name attribute to your respective factory name.
Also, check if you haven't copy-pasted incorrectly the REST transaction manager - now there is no such bean REST
Ensure all of your #PersistenceContext specify unitName. I haven't figured out how to tell Spring that a particular EMF or PersistenceUnit is the default. I thought specifying primary="true" on the default EMF would work but doesn't appear to
Do I need to specify persistenceUnitName in the factory ?
If you've got multiple persistence units, you do need to specify which ones the factories will use.
More to the heart of the matter, see SPR-3955. To summarize, versions prior to Spring 3.0M4 do not support multiple transaction managers with #Transactional. Nor do I believe it honors the "unitName" attribute for #PersistenceContext, so you can't specify that either.
For an example of how I worked around this by explicitly injecting EntityManagerFactorys and using AOP to re-enable #Transactional, see my sample app
Related
I have an Spring MVC 3.2.8 app, and I want to run StandAlone process to generate a PDF. I want to initialize the container and manage beans from an stand-alone app.
I have this piece of code:
public class CreatePDF {
private static final Logger LOGGER = Logger.getLogger (ImportEcolabelToolboxToECAT.class);
public static void main(String[] args) {
String[] configLocations = new String[] {
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/dao/dataAccessContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/webapp/WEB-INF/dao/databaseMessageSource.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/services/impl/servicesContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/webapp/WEB-INF/applicationContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/controller/propertyeditors/propertyeditorsContext.xml"};
FileSystemXmlApplicationContext ctx =
new FileSystemXmlApplicationContext(configLocations, true);
}
}
But I have this error when running the app.
Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
and here the definition from the file dataAccessContext.xml :
<!-- The PropertyPlaceholderConfigurer replaces placeholders in Spring bean definitions with the values from the chosen properties files. -->
<!-- There is an example use in the datasource definition below. Look for the $\{jdbc.*} values. -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/nicinc/dao/jdbc-test.properties</value>
<value>classpath:com/nicinc/dao/dbMessageSource.properties</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="generateDdl" value="false"/>
<property name="showSql" value="false" />
</bean>
</property>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
The javax.naming package comprises the JNDI Api. Since it is just an API its implementation you will have to provide. Generally the implementation is provided by App server. As per the error you are Missing the JNDI implementation.
Possible solution:
If you dont have any javaee related requirement then you should directly use DriverManagerDataSource.
You need to provide your own implementation.Below link might help.
using application data source locally.
I have a problem with my spring boot configuration in xml I created this configuration :
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="database" value="ORACLE"/>
</bean>
<bean id="dataSource" primary="true" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#localhost:20300:test"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="entityManagerFactory" primary="true" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes-->
<property name="packagesToScan" value="model.entity"/>
<property name="persistenceUnitName" value="msPersistenceUnit" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="controllerService"
class="...impl.ControllerServiceImpl">
<property name="entityManager" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<constructor-arg index="0" ref="entityManagerFactory" />
</bean>
And I had the java code like this :
public void setEntityManager(final HibernateEntityManagerFactory entityManager) {
final RepositoryFactorySupport factorySupport = new JpaRepositoryFactory(entityManager.createEntityManager());
controlRepository = factorySupport.getRepository(ObjControlRepository.class);
}
when i'm using find method it's ok, but when I'm doing a save, there are not exception but the value it's not insert.
Thank your for your help.
[Edit]
To save I'm using :
/**
* The Interface ObjControlRepository.
*/
public interface ObjControlRepository extends CrudRepository<ObjControl, String> {
}
And I'm calling the method like that :
controlRepository.save(newValue);
You should try to explicitly set the hibernate.hbm2ddl.auto variable to auto. This will prevent your application to release previous data when you start your application.
You can learn more about the hibernate.hbm2ddl.auto variable here.
You should use transactions and commit the transaction in order to save an entity.
So Use #Transactionl annotation on your service layer, like this:
#Transactional
public class ControllerServiceImpl {
...
}
As ControllerServiceImpl is already declared as a bean in spring configuration file, Spring will take care about committing the transaction once you save an entity.
I am using Spring and trying to setup a global transaction spanning over two MS SQL Server DBs. The app is running inside Tomcat 6.
I have these definitions:
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
....
</bean>
<bean id="sessionFactory1"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource1"/>
....
</bean>
<bean id="hibernateTransactionManager1"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory1"/>
</property>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
....
</bean>
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource2"/>
....
</bean>
<bean id="hibernateTransactionManager2"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory2"/>
</property>
</bean>
Then also, each DAO is linked either to sessionFactory1 or to sessionFactory2.
<bean name="stateHibernateDao" class="com.project.dao.StateHibernateDao">
<property name="sessionFactory" ref="sessionFactory1"/>
</bean>
Also, I recently added these two.
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
<property name="transactionTimeout" value="300" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
I am trying to programmatically manage the global transaction
(this is some old legacy code and I don't want to change it too
much so I prefer keeping this managed programmatically).
So now I have this UserTransaction ut (injected from Spring), so I call ut.begin(), do some DB/DAO operations to the two DBs through the DAOs, then I call ut.commit().
The thing is that even before the ut.commit() call, I can see the data is already committed to the DBs?!
I don't think Atomikos is aware of my two DBs, their data sources, session factories, etc. I don't think it starts any transactions on them. Looks like they are not enlisted at all in the global transaction.
To me it seems that each DB/DAO operation goes to the SQL Server on its own, so SQL Server creates an implicit transaction for just that DAO/DB operation, applies the operation and commits the implicit the transaction.
But 1) and 2) are just guesses of mine.
My questions:
Do I need to start the two DB transactions myself (but OK, this is what I am currently doing and I am trying to get rid of; that's why I am trying to use Atomikos to start with)?
How I can configure all this correctly so that when I call ut.begin() it begins a global transaction to the two DBs and when I call ut.commit() it commits it?
I haven't played with JTA recently so seems to me I am missing something quite basic here. What is it?
Edit 1
<bean id="globalTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="atomikosUserTransaction"/>
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="allowCustomIsolationLevels" value="true" />
<property name="transactionSynchronization" value="2" />
</bean>
i have a spring datasource which looks like this:
<bean id="dataSource1" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database1.url}" />
<property name="username" value="${database1.username}" />
<property name="password" value="${database1.password}" />
</bean>
i need to make this available on jndi or jee. some related things:
<bean id="dataSourceJNDI1" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/dataSource1"/>
<property name="beanClassLoader" ref="dataSource1"></property>
</bean>
or maybe :
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/database1" />
not sure how to get the jndi or jee working with the dbcp. any help would be appreciated.
thanks in advance.
ps: guys this is a special needl. so i have to do it like this. please dont post unnecessary advices saying why i should use tomcat server as datasource. i am aware of setting datasource that way. i repeat again this is a special need. also please dont provide me java code solutions, not required.
ps: those who dont know how to do it, please do not occupy the space of this post saying its not possible. if you dont know the answer no need to post and junk the post.
You would need to bind the DataSource to the JNDI tree. You would need to supply the parameters for connecting to the local JNDI tree. JndiTemplate can do this. Some of the JNDI environment properties probably won't be necessary for a local InitialContext. I think "java.naming.factory.initial" is the only required. The other are for connecting to an out of process JNDI server:
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.provider.url">${jndi.provider.url}</prop>
<prop key="java.naming.factory.initial">${jndi.factory.initial}</prop>
<prop key="java.naming.security.principal">${jndi.security.principal}</prop>
<prop key="java.naming.security.credentials">${jndi.security.credentials}</prop>
</props>
</property>
</bean>
<bean factory-bean="jndiTemplate" factory-method="bind">
<constructor-arg type="java.lang.String" value="java:com/env/DataSoure"/>
<constructor-arg type="java.lang.Object" ref="dataSource"/>
</bean>
If you are performing a JNDI lookup in the same Spring context, you will either need to have the JNDI bean depends-on this lookup bean or make the JNDI lookup lazy so that it will perform the lookup on first use.
Since you are using jndi you have to declare the datasource as a jndi source.
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/database1" />
<bean id="dataSource1" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="dataSource" ref="dataSource" />
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database1.url}" />
<property name="username" value="${database1.username}" />
<property name="password" value="${database1.password}" />
</bean>
That should work assuming your bean definition for dataSource1 is correct.
I am trying to use Envers on a project that also uses Hibernate and Spring - and I appreciate a lot the code reduction offered by HibernateTemplate.
I configured Envers under JPA, and after a few tweaks I was able to have the schema generated by the EnversHibernateToolTask Ant task (including the auditing tables). However, when I write code such as:
hibernateTemplate.saveOrUpdate(f);
the data is persisted, but nothing goes to the auditing tables. Conversely, if I write:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(f);
em.getTransaction().commit();
then data goest to the audit tables (but I'd rather use the former syntax - I know using JPA's EntityManager decouples that code from Hibernate, but it simple does not pay off the hassle - changing ORM engine is not in my wildest dreams for this project.)
It may help to check my applicationContext.xml configuration:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="projetox" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.w2it.projetox.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
...
</bean>
and here is my persistence.xml setup:
<persistence-unit name="projetox" transaction-type="RESOURCE_LOCAL">
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<!-- Hibernate Envers -->
<property name="hibernate.ejb.event.post-insert"
value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.post-update"
value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.post-delete"
value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.pre-collection-update"
value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.pre-collection-remove"
value="org.hibernate.envers.event.AuditEventListener" />
<property name="hibernate.ejb.event.post-collection-recreate"
value="org.hibernate.envers.event.AuditEventListener" />
</properties>
</persistence-unit>
Does anyone have a hint on what is going on here? Thank you!
HibernateTemplate has its JPA counterpart, JpaTemplate which provides a fairly similar functionality.
The reason Envers doesn't work with HibernateTemplate is because it relies on JPA events (you can see the listeners declared in your persistence.xml above) triggered when EntityManager is used. It's possible in theory to write code to trigger those events from Hibernate session when HibernateTemplate is used, but it's rather involved.
All u needed to do was put #Transactional in your Dao or services which call the dao.save()/ update methods.
Even if you register your eventlistener these events are not fired unless you use transcational of the Spring FW. Spring has to know and tell hibernate that these events are fired.