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;
}
Related
I have Spring + JPA (Hibernate) project, at which i connect to MsSQL database, now i need to open a new connection but this time it will be for MySQL. i am using XML configuration
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${spring.datasource.driverClassName}" />
....
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:packagesToScan="com.wsg.admin.api.model"
p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter">
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
....
</props>
</property>
<property name="persistenceUnitName" value="dataSourcePU" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Configure the MySQL connection -->
<bean id="enduserDataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${enduser.db.driver}" />
....
</bean>
<bean id="enduserEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="enduserDataSource" p:packagesToScan="com.wsg.admin.api.model"
p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter">
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
....
</props>
</property>
<property name="persistenceUnitName" value="enduserDataSourcePU" />
</bean>
<tx:annotation-driven transaction-manager="enduserTransactionManager" />
<bean id="enduserTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="enduserEntityManagerFactory" />
</bean>
then i try to inject the entityManager using the fragment
#PersistenceContext(unitName="dataSourcePU")
EntityManager entityManager;
#PersistenceContext(unitName="enduserDataSourcePU")
EntityManager endUserEntityManager;
it works only for the first Database, but when try to persist on the second it returns error
javax.persistence.TransactionRequiredException: no transaction is in progress
i tried to annotated the method (which contains persist() call) with #Transactional("transactionManager") one time, and #Transactional(value = "enduserTransactionManager") the other time, the second entityManager always throw the same exception
i tried to separate the persist() call into different methods, and annotated each of the two method #Transactional("transactionManager") and #Transactional(value = "enduserTransactionManager") but still get the same error
#Transactional(value = "enduserTransactionManager")
private void createNewBrandMySQL(Brand newBrand) {
and
#Transactional("transactionManager")
public Integer createNewBrand(Brand newBrand) throws EntityDoesntExistException {
//this method calls createNewBrandMySQL
Fixed, by injecting one em directly an the other using entityManagerFactory
#PersistenceContext(unitName = "dataSourcePU")
EntityManager entityManager;
#Autowired
#Qualifier("enduserEntityManagerFactory")
EntityManagerFactory endUserEntityManagerFactory;
EntityManager endUserEntityManager;
#PostConstruct
public void init() {
endUserEntityManager = endUserEntityManagerFactory.createEntityManager();
}
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 ?
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. :)
My service makes use of a generic DAO (which explicitly uses Hibernate session factory). I have spent some time before I discovered this error
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I annotated my service and all works perfectly. Now I want to use context path scanning, and remove this line from my configuration:
<bean id="societaService" class="it.trew.prove.services.SocietaService" />
So.... here's my final version:
#Service
#Transactional(readOnly = true)
public class SocietaService {
private Dao societaDao;
#Autowired
public void setSocietaDao(Dao societaDao) {
this.societaDao = societaDao;
}
public void salvaSocieta(Societa s) {
societaDao.save(s);
}
public List<Societa> listAll() {
return societaDao.getAll(Societa.class);
}
public void deleteById(Long id) {
societaDao.delete(getSocieta(id));
}
public Societa getSocieta(String id) {
return getSocieta(Long.parseLong(id));
}
public Societa getSocieta(Long id) {
return societaDao.get(Societa.class, id);
}
}
Adding #Service annotation makes my app give the awful hibernate error above. Why?
Removing #Service and configuring the service bean via xml = it works. WHY??
In addition:
does transactional annotating my service class makes all its methods to be executing in a transaction?
EDIT
Here's my context xml:
<context:annotation-config />
<context:component-scan base-package="it.trew.prove" />
<!-- Hibernate -->
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.google.appengine.api.rdbms.AppEngineDriver" />
<property name="url" value="jdbc:google:rdbms://xxx:xxx/xxx" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>it.trew.prove.model.beans.Scadenza</value>
<value>it.trew.prove.model.beans.Fornitore</value>
<value>it.trew.prove.model.beans.Societa</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<!-- <prop key="hibernate.hbm2ddl.import_files">/setup.sql</prop> -->
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
Did you enabled annotations ?
<context:annotation-config />
and
<context:component-scan base-package="org.example"/>
this will enable annotations like #Service, #Component and #Repository
First of all, you need to tell spring to enable Transactional annotation with something like that:
<tx:annotation-driven transaction-manager="transactionManager" />
Second, if you use #Transactional at class level, any call to a method of your Service will be transactional. Whether it starts a transaction or not depends on the "propagation" attribute. The default is start one if none started in this session (Propagation.REQUIRED). If you use #Transactional only at class level, all of your methods will inherit its attributes, i.e., if you set "readOnly = true", all of yours methods will be read only, thus, updates/saves/delete won't work. I would recommend you to read more the Spring Transaction Management Doc
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.