I have two databases which I want to access from my Spring application. I configured two SharedEntityManagerBean for both databases. Here is the config:
<jpa:repositories base-package="xxx" entity-manager-factory-ref="entityManagerFactory1" />
<jpa:repositories base-package="xxx" entity-manager-factory-ref="entityManagerFactory2" />
<tx:annotation-driven/>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager1">
<property name="entityManagerFactory" ref="entityManagerFactory1" />
<property name="dataSource" ref="dataSource1" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager2">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
<property name="dataSource" ref="dataSource2" />
</bean>
<bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="xxxxxx"
....
</bean>
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="xxxxx"
...
</bean>
<bean id="entityManager1" class="org.springframework.orm.jpa.support.SharedEntityManagerBean" >
<property name="entityManagerFactory" ref="entityManagerFactory1" />
</bean>
<bean id="entityManager2" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
</bean>
<bean id="dataSource1"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
<bean id="dataSourceOntology"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
I have two EntityLocators which are not managed by Spring that access entities in each of the corresponding databases. They look something like that:
public class SpringEntitiyLocator1 {
private EntityManager em;
public SpringEntitiyLocator1() {
}
private EntityManager getEM() {
if (em == null) {
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestFactoryServlet.getThreadLocalServletContext());
SharedEntityManagerBean bean = context.getBean("entityManager1",SharedEntityManagerBean.class);
em = bean.getObject();
}
return em;
}
}
When I have only one SharedEntityManagerBean defined in my applicationContext the call to getBean() works fine. However once I have both SharedEntityManagerBeans defined I get the error:
Bean named 'x' must be of type [y], but was actually of type [$Proxy]
I read on SO that I should use cglib proxying by adding <aop:config proxy-target-class="true"/> to my application.xml.
Is that the best solution ?
When I add that line I get Caused by: java.lang.NoClassDefFoundError: org/aspectj/util/PartialOrder$PartialComparable errors.
Do I need aspectj for that?
EDIT:
In case I have only one SharedEntityManagerBean defined I can call getBean(SharedEntityManagerBean.class). This works fine.
I debugged the code and it seems that this call will call getBean("&entityManager1",SharedEntityManagerBean.class) (note &) .
However when I pass the name getBean("EntityManager1",SharedEntityManagerBean.class) I get a type cast exception.
Having both SharedEntityManagerBeans defined and call getBean without a name also causes an exception (can't find a bean with that name).
So my current workaround is to call: getBean("&entityManager1",SharedEntityManagerBean.class) and getBean("&entityManager2",SharedEntityManagerBean.class)
This works fine.
Ok apparently SharedEntityManagerBean is a FactoryBean and for that I have to add & before the bean name to retrieve the SharedEntityManagerBean.
Alternatively I could probably just call:
em = context.getBean("entityManager",EntityManager.class);
See here and here for reference.
Related
I have following configuration in application context
<jee:jndi-lookup id="dataSource" jndi-name="MY_DS" />
<context:load-time-weaver/>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceUnitName" value="pu_TEST" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
Now my DAO Class
#Repository
public class EmployeeDAO{
#PersistenceContext
private EntityManager em;
#Transactional
public void create(Employee entity) {
LOG.error("Enitity Manager:create" + em);
em.persist(entity);
// em.flush(); if i use flush it saves
}
}
Now when I save the entity it does not say give any error but no data is updated into db.
I do not wish to use flush as entitymanager is injected by spring and should perform flush at the end automatically which is not happening. correct my understanding.
Adding facade class may be issue is there, Does Propagation.REQUIRES_NEW has anything to do here?
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void process(){
Employee e = factory.getEmployee();
employeeDao.create(e);
}
On Debug after create method call it shows employee got primary key populated that mean db call has made but at the end it is not persisted.
Please try either of the 3 :
1.Solution 1
Please call below code
em.joinTransaction();
just before
em.persistEntity(entity);
2.Solution 2
make attribute readOnly=false in #Transactional
3.Solution 3
Try manually adding bean EmployeeDAO in spring xml file
or else you can try below:
#Transactional(propagation=Propagation.REQUIRED)
Here i tried 2 write cod 2 get list from Mysql Database using spring nd Hibernate.
But problem is here that how initialize **org.hibernate.Session se through "applicationContext.xml" file by bean class....
public void getList(**Session se**){
String liststudent="from StudentList stud";
Query q=se.createQuery(liststudent);
List<Object> list=q.list();
for(Object obj:list){
Object studarr[]=(Object[])obj;
System.out.println("Data at Zero Index"+studarr[0]);
}
}
As here property name **template** has been initialized by the ref template.
Is there any way to initialize Session se.
<bean name="mydao" class="dao.MyDao">
<property name="template" ref="template"></property>
</bean>
using your context.xml file
define sessionFactory
<bean id="sessionFactory" class="LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--define other properties...mapping files
</bean>
define hibernateTemplate
<bean id="template" class="*HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
then
<bean name="mydao" class="dao.MyDao">
<property name="template" ref="template"></property>
</bean>
NOTE: the class package has been ommitted
I have tried autowiring byName and byType for different beans and it's working fine. But I want to use byName and byType autowiring on the same bean, can it be done? I have tried several way but it doesn't work.
<beans>
<bean id="car" class="com.Car" autowire="byName">
<property name="carName" value="BMW" />
</bean>
<bean id="wheel" class="com.Wheel">
<property name="wheelType" value="with Tube" />
</bean>
<bean id="wheel1" class="com.Wheel">
<property name="wheelType" value="tubeless" />
</bean>
<bean id="Byke" class="com.Byke" autowire="byType">
<property name="bykeName" value="Honda" />
</bean>
<bean id="Wheel" class="com.Wheel">
<property name="wheelType" value="No Information" />
</bean>
</beans>
In short answer is NO. For explanation see the relevant API doc which clearly takes only one argument for type of autowiring you need viz. autowireMode For quick reference pasting signature - java.lang.Object createBean(java.lang.Class<?> beanClass, int autowireMode ,boolean dependencyCheck) throws BeansException
my dao implementaion;
\\here are imports...
#Repository
public class CompanyDaoImp extends JdbcDaoSupport implements CompanyDao {
private static final String INSERTCOMPANY = "INSERT INTO b_company"
+ "(NAME)VALUES(?)";
this is my bean;
<?xml version=".........
<!-- TODO add the component-scan and annotation-config elements -->
<context:annotation-config/>
<context:component-scan base-package="com.some.company"/>
<bean id="companyAppDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/companyapp"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
i couldn't understand why i keep taking the exception;
.......Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required.........
JdbcDaoSupport doesn't have any annotation to automatically inject the DataSource. You have to override the setDataSource method like this:
<bean name="companyDaoImp" class="...CompanyDaoImp">
<property name="dataSource" ref="companyAppDataSource" />
</bean>
Spring couldn't inject automatically the DataSource because you may have multiple data sources and in that case it would be necessary to tell Spring which one you need.
I am trying to test my DAO that uses JPA EntityManager to fetch and update entities. I have marked my unit test as Transactional and set the defaultRollback property to false. However, I don't see my transactions rolling back at the end of the test when throwing a rune time exception. The data is getting persisted in the DB. Here is my unit test code along with spring configuration. I am clearly missing something but havent been able to identify what.
Btw, the transaction is RESOURCE_LOCAL in the persistence.xml
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:spring/test-jpa.xml"})
#TestExecutionListeners(
{ DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class
})
#TransactionConfiguration(defaultRollback=false)
#Transactional
public class JpaTests {
#PersistenceContext
EntityManage em;
#Test
public void testTransactionQueueManager() {
Object entity = em.find(1);
//code to update entity omitted.
entity = em.merge(entity);
em.flush();
throw new RuntimeException
}
}
Spring Configuration
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jpa.driverclassname}" />
<property name="url" value="${jpa.url}" />
<property name="username" value="${jpa.username}" />
<property name="password" value="${jpa.password}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="${jpa.persistenceunitname}"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="databasePlatform" value="org.apache.openjpa.jdbc.sql.DBDictionary"/>
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
Your configuration seems fine.
There could be different reasons for the unexpected commit, maybe a datasource with autocommit mode or a non transaction compliant database (mysql with MyISAM ?)
Did you check this thread Why are transactions not rolling back when using SpringJUnit4ClassRunner/MySQL/Spring/Hibernate ?
#TransactionConfiguration(defaultRollback=false)
might be the culprit. Try defaultRollback=true, that should rollback the transaction.
Adding rollbackFor may help, it's a common pitfall.
#Transactional(rollbackFor=Exception.class)