I have an existing code which is written using Spring + Hibernate session factory. I have DAOs written using sessionFactory which are transactional.
#Transactional
public class WorkingDAO<T> {
private SessionFactory sessionFactory;
public void save(T t){
sessionFactory.getCurrentSession().save(t);
}
}
I have unit tests which tests for this DAO which were working fine. Now i want to use Spring JPA so to reduce the effort of writing DAO classes. So I used the following configuration
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect"/>
<property name="jpaProperties">
....
</bean>
<bean id="SessionFactory" factory-bean="entityManagerFactory"
factory-method="getSessionFactory" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven/>
However my older unit tests are failing after using the above configuration. Can i use the existing SessionFactory ? or do i have to migrate to the entityManager ?
Related
I'm trying to create a pagination system with Spring interface PagingAndSortingRepository.
I'm following some guides on the internet, but i'm stuck at the first step.
I implemented PagingAndSortingRepository this way
public interface ArtistaRepository extends PagingAndSortingRepository<Artista,Integer> {
List<Artista> findByNome(String nome);
}
If I try to run the webapplication I get this error:
No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined
I use Hibernate Session as entity manager. In all example I saw on the Internet, JPA EntityManager was used.
This is the code inside my configuration.xml file:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<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.jeansedizioni.model"/>
</bean>
Since I'm not using JPA EntityManager, how should I edit my code?
Thank you in advance
Declaring Hibernate's Session Factory won't work. The Spring-data-jpa repositories will only work with the jpa entity manager, as fellow M. Deinum wrote.
Try 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="<your database - Oracle, MySQL...>"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="persistenceUnitName" value="default"/>
<!-- spring based scanning for entity classes>-->
<property name="packagesToScan" value="com.jeansedizioni.model"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
Try this code I hope it will be useful for you.
//Repository Code
public interface ArtistaRepository extends JpaRepository<Artista,Integer> {
Page<Artista> findByNome(String nome,Pageable page);
}
//Service code
int totalElements;
int totalPages;
int numberOfElements;
Pageable pageable = new PageRequest(page,size,Sort.Direction.DESC,"id");
Page<Artista> list=artistaRepository.findByNome(nome,pageable);
totalElements=list.getTotalElements();
numberOfElements=list.getNumberOfElements();
totalPages=list.getTotalPages();
Im using JPA with Hibernate implementation and using JpaTransactionManager to mange transactions.
Below is my application context file
<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="defaultDataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory" primary="true"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="infra_services" />
</bean>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
I have defined my service class as below
#Service
#Transactional
public class ComponentService {
I execute queries in dao layer as below
Query q = entityManager.createQuery(
"SELECT cc.component FROM "
+ this.typeParameterClass.getSimpleName()
+ " cc WHERE cc.caseload.id = ? ").setParameter(1,
caseloadId);
Collection<Component> ddd =q.getResultList();
for (Component c : ddd) {
System.out.println(c.getComponentId());
System.out.println(c.getComponentRelationships2());
}
return ddd;
I started with select queries. While executing the line System.out.println(c.getComponentRelationships2()); getting could not initialize proxy - no Session] with root cause exception
Not sure why the session is not available here. Please help me on this.
If your service is not in the same context as the one where <tx:annotation-driven /> then it's not working. Because it only look for bean in the same context. Extract from spring doc:
#EnableTransactionManagement and only looks for #Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for #Transactional beans in your controllers, and not your services. See Section 21.2, “The DispatcherServlet” for more information.
I have been facing the below error while trying to save the object to database. I tried the solution mentioned here1 and here2 but no good. I was following a tutorial but the only difference is versions of Spring and Hibernate.
I am able to persist the object directly using the SessionFactory but it fails with below error if I try this with HibernateDaoSupport
spring.xml
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="system" />
<property name="password" value="xxx" />
</bean>
<context:annotation-config/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan" value="org.sri.sphiber.model"></property>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="customerDAOImpl" class="org.sri.sphiber.dao.CustomerDAOImpl">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
CustomerDAOImpl.java
public class CustomerDAOImpl extends HibernateDaoSupport {
public boolean insertCustomer(Customer cust){
try {
getHibernateTemplate().saveOrUpdate(cust);
} catch (DataAccessException e) {
e.printStackTrace();
return false;
}
return true;
}
}
Invoke it using.
public class MainClass {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("spring.xml");
CustomerDAOImpl hdi=appContext.getBean("customerDAOImpl",CustomerDAOImpl.class);
Customer customer=new Customer();
customer.setCustomerName("Sri");
boolean isUpdated = hdi.insertCustomer(customer);
}
}
Error message.
Aug 10, 2014 12:45:52 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000232: Schema update complete
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1135)
at org.springframework.orm.hibernate4.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:684)
at org.springframework.orm.hibernate4.HibernateTemplate.doExecute(HibernateTemplate.java:340)
at org.springframework.orm.hibernate4.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:308)
at org.springframework.orm.hibernate4.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:681)
at org.sri.sphiber.dao.CustomerDAOImpl.insertCustomer(CustomerDAOImpl.java:16)
at org.sri.sphiber.main.MainClass.main(MainClass.java:26)
Version Details :
Spring version : spring-framework-4.0.6.RELEASE
Hibernate Version : hibernate-release-4.3.5.Final
Database : Orcale 11g
You are missing TransactionManager definition, see http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html
[UPDATE]
Previously i was writing from my mobile so it was hard to provide details, here is what you need to do:
Spring xml config:
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Add #Transactional annotation to CustomerDaoImpl.insertCustomer method
Now your code should work.
Please note that #Transactional annotation should be used in service layer, not in DAO layer like in this example.
#Transactional annotation tells spring to create proxy which "wraps" annotated method with transaction using aspects.
In configuration file
do the change:-
#Configuration
#EnableTransactionManagement <-----Put this line
public PersistenceConfig{
//your code
}
(OR)
#Bean
#Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory session) {
HibernateTemplate hb = new HibernateTemplate();
hb.setCheckWriteOperations(false);
hb.setSessionFactory(session);
return hb;
}
I am new to Spring framework; need some clarifications on how the SessionFactory object Dependency injection is working in below code.
spring-servlet.xml
<context:annotation-config />
<context:component-scan base-package="com.employee" />
<bean id="jspViewResolver"
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" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}"
p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:employee.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
EmployeeDAOImpl.java
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
#Repository
public class EmployeeDAOImpl implements EmployeeDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void addEmployee(EmployeeForm employee) {
sessionFactory.getCurrentSession().save(employee);
}
}
How is the sessionFactory getting initialized with a SessionFactory object here?
What I understand
In the sprng-servlet.xml file, the DI of sessionFactory is happening in the below code:
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Now, if I open the source code for the class org.springframework.orm.hibernate3.HibernateTransactionManager, then I can see the below section:
private SessionFactory sessionFactory;
public HibernateTransactionManager(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
afterPropertiesSet();
}
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory(){
return this.sessionFactory;
}
which means the sessionFactory class variable of org.springframework.orm.hibernate3.HibernateTransactionManager has been initializd.
Now my Query:
In my code posted above, how is the sessionFactory of class EmployeeDAOImpl.java getting initialized? I can't find any relation between the sessionFactory of class org.springframework.orm.hibernate3.HibernateTransactionManager (where DI is happening) and the sessionFactory of class EmployeeDAOImpl.java (which I wrote). Then how is it working?
Please explain - totally confused !!!
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:employee.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
You have defined the session factory bean in you context file. During the application bootstrap, the spring context is loaded and this session factory bean is initialized by spring as a singleton instance.
<context:annotation-config />
<context:component-scan base-package="com.employee" />
#Autowired
private SessionFactory sessionFactory;
And since you have enabled the annotation-config and component-scan and declared #Autowired in your DAOImp, this is the reason Spring knows the place to inject the session factory bean properly.
This configuration is enabled the transaction manager annotation.
Example:
#Transactional
public void addEmployee(EmployeeForm employee){...}
Here is the suggestion.
Transactional annotation is better to be placed in service layer instead of DAO layer. You need to make sure the annotation is placed on the concrete class unless you use the interface-proxy in your component-scan.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
This piece of configuration is set the transaction manager bean which lets transaction manager knows which session factory it needs to manage with.
Therefore the configuration of bean
id="transactionManager" sets the transaction manager with the proper hibernate session factory.
tx:annotation-driven configuration enables the annotation-based transaction manager in code level.
Hope the explanation is helpful for you. :)
I am using JUnit 4 to test Dao Access with Spring (annotations) and JPA (hibernate). The datasource is configured through JNDI(Weblogic) with an ORacle(Backend). This persistence is configured with just the name and a RESOURCE_LOCAL transaction-type
The application context file contains notations for annotations, JPA config, transactions, and default package and configuration for annotation detection.
I am using Junit4 like so:
ApplicationContext
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="workRequest"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${database.target}"/>
<property name="showSql" value="${database.showSql}" />
<property name="generateDdl" value="${database.generateDdl}" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>workRequest</value>
</property>
<property name="jndiEnvironment">
<props>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
<prop key="java.naming.provider.url">t3://localhost:7001</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
JUnit TestCase
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class AssignmentDaoTest {
private AssignmentDao assignmentDao;
#Test
public void readAll() {
assertNotNull("assignmentDao cannot be null", assignmentDao);
List<Assignment> assignments = assignmentDao.findAll();
assertNotNull("There are no assignments yet", assignments);
}
}
regardless of what changes I make I get:
No unique bean of type [javax.persistence.EntityManager] is defined
Any hint on what this could be. I am running the tests inside eclipse.
Your Spring context has a bean definition using LocalContainerEntityManagerFactoryBean. This creates an EntityManagerFactory, not an EntityManager.
AssignmentDao needs to get itself wired with an EntityManagerFactory.
Alternatively, you can replace the LocalContainerEntityManagerFactoryBean with a LocalEntityManagerFactoryBean, which will create an EntityManager directly. However, you need to be careful with that one, it has some downsides. See that part of the Spring docs for a full explanation of the options.
It's confusing, because the naming conventions of JPA and Spring overlap each other, so naming these classes is a real bugger.