I´m new to JPA. I´m developing an application which uses JPA (Hibernate implementation) and Spring. I´ve declared a persistence unit in my persistence.xml and configuration about EntityManagerFactory in my Spring config files. Something like this:
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="my.package" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
Then I have some DAOs where I inject the entityManager with the #PersistenceContext annotation:
public MyDaoImpl implements MyDao{
private EntityManager entityManager;
#PersistenceContext
private void setEntityManager(EntityManager em){
this.entityManager = em;
}
}
And finally, I have some services where DAOs are injected (by #Autowired Spring's annotation):
public MyServiceImpl implements MyService{
#Autowired
private MyDao myDao;
public List<MyEntity> readOperation(){
//
return myDAo.searchAll();
}
}
As its a read only operation I thought it wasn´t needed the #Transactional annotation, but without it, there is an exception:
java.lang.IllegalStateException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:223)
at $Proxy121.unwrap(Unknown Source)
I´ve read some other posts like this: java.lang.IllegalStateException: No transactional EntityManager available
And all is said is that the transactional annotation is needed. It´s true that it works with it, but I´d like to know (and why) if all methods (even read only operations) must be transactional.
A JPA Transaction is needed for all your methods - essentially a transaction is what opens a Hibernate session, and you need an open session to interact with it.
You can annotate the transactions as readonly or readwrite, and you can also annotate at the class level to save you annotating each method. For example:
#Transactional(readOnly = true)
public MyDaoImpl implements MyDao{
private EntityManager entityManager;
#PersistenceContext
private void setEntityManager(EntityManager em){
this.entityManager = em;
}
#Transactional(readOnly = false)
public void saveItem(MyEntity entity) {
}
public List<MyEntity> searchAll() {
}
}
You a need a transaction for all operations that change anything in DB (the only exception is SELECT queries, without locking). Check this answer.
Related
Assuming I have the next code:
#Autowired
private IManager1 manager1;
#Autowired
private IManager2 manager2;
#Autowired
private IManager3 manager3;
#Transactional
public void run() {
manager1.doStuff();
manager2.registerStuffDone();
manager3.doStuff();
manager2.registerStuffDone();
manager1.doMoreStuff();
manager2.registerStuffDone();
}
If any exception is launched I want to rollback everything done by the "doStuff()" methods, but I don't want to rollback the data recorded by the "registerStuffDone()" method.
I've been reading the propagation options for #Transactional annotation, but I don't understand how to use them properly.
Every manager internally uses hiberante to commit the changes:
#Autowired
private IManager1Dao manager1Dao;
#Transactional
public void doStuff() {
manager1Dao.doStuff();
}
Where the dao looks like this:
#PersistenceContext
protected EntityManager entityManager;
public void doStuff() {
MyObject whatever = doThings();
entityManager.merge(whatever);
}
This is my applicationContext configuration:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourcePool" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Ideas?
You need 2 transactions, one for the stuff to be committed and one for the stuff to be rolled back.
#Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor={Exception1.class, Exception2.class})
public void registerStuffDone()() {
//code
}
Your run method will then use the first transaction and that will be rolled back, but the registerStuffDone method will start a second transaction which will be commited.
You are using declarative transaction and want to control like program sense. For this reason, you need more practice and deep understanding about Spring transaction definition such as PROPAGATION, ISOLATION etc...
Programmatic transaction management: This means that you have manage the transaction with the help of programming. That gives you extreme flexibility, but it is difficult to maintain.
VsDeclarative transaction management: This means you separate transaction management from the business code. You only use annotations or XML based configuration to manage the transactions.
Perhaps, alternative way for your questions by Programmatic transaction management.
/** DataSourceTransactionManager */
#Autowired
private PlatformTransactionManager txManager;
public void run() {
try {
// Start a manual transaction.
TransactionStatus status = getTransactionStatus();
manager1.doStuff();
manager2.registerStuffDone();
manager3.doStuff();
manager2.registerStuffDone();
manager1.doMoreStuff();
manager2.registerStuffDone();
//your condition
txManager.commit(status);
//your condition
txManager.rollback(status);
} catch (YourException e) {
}
}
/**
* getTransactionStatus
*
* #return TransactionStatus
*/
private TransactionStatus getTransactionStatus() {
DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
dtd.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
dtd.setReadOnly(false);
return txManager.getTransaction(dtd);
}
Note: It does not mean you need to always use one approach like Programmatic transaction management. I prefer mixed approach. Please use easy way like Declarative transaction for simple database services, otherwise, just control with Programmatic transaction in your services will save your logic easily.
I just have a new project to maintain, and using Hibernate+Spring. I wrote a DeliveryInfoServiceImpl which have a method to query for some entity but not have any update or save operation, but I have an error:
Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Unless I add #Transactional on the method or the class.
My questions are :
Why I have to add #Transactional though I am only executing select query?
Does adding #Transactional means enable transaction support ,which may have more unnecessary overhead when I am only using "select" query.
Below is my code snippet:
#Override
public List<UnavailableRestaurantBean> getUnavailableRestaurantBean(String custAddress, List<Long> dishesId) {
List<Dish> dishes = getDishByIds(dishesId);//exception here
....
}
private List<Dish> getDishByIds(List<Long> ids){
return deliveryInfoDao.findByIds(Dish.class,ids);
}
And I have below transaction manager config:
<tx:annotation-driven transaction-manager="myTxManager" />
<bean id="myTxManager" name="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory">
</property>
</bean>
I have an entity User, a Repository/Dao class UserDao (using Spring Data JPA) and a Service class UserService with a method addUser annotated as #Transactional:
#Service
public class UserService {
#Autowired
private UserDao userDao;
#Transactional
public void addUser() throws Exception {
User user = new User();
user.setUsername("aaa");
// Save the user, but since this method have the #Transactional
// annotation it should not be committed....
userDao.save(user);
// Forcing an error here I expected that the previous operation
// were rolled back.. Instead the user is saved in the db.
if ("".equals("")) {
throw new Exception("something fails");
}
// Other operations (never executed in this example)
user.setUsername("bbb");
userDao.save(user);
return;
} // method addUser
} // class UserService
The UserDao is simply this:
#Transactional
public interface UserDao extends CrudRepository<User, Long> { }
Reading the Spring Data JPA documentation and other questions on the same argument (1, 2) my expectations were that each operations inside a method marked with #Transactional will be rolled back if some error occurs..
What am I doing wrong?
Is there a way for rollback the save operation in the previous example if an error occurs?
Your understanding is correct however automatic rollback only occurs for runtime, unchecked exceptions.
So, assuming your transaction manager is configured correctly, to rollback on a non-runtime, checked exception add the rollbackFor attribute to your transactional annotation:
#Transactional(rollbackFor=Exception.class)
public void addUser() throws Exception {
}
You need to add things to your Xml configuration file.. you need to add trnasaction manager.
<tx:annotation-driven transaction-manager="txMgrDataSource" />
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="txMgrDataSource"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource" />
</bean>
Assuming your data source is:
<bean id="DataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="####" />
<property name="url"
value="jdbc:sqlConnection" />
<property name="username" ref="user" />
<property name="password" ref="pass" />
</bean>
I am mostly using #Autowired and #Component annotations in my project. However, I am going to use DataSource class for database actions.
So, I use this is in my dispatcher-servlet.xml :
<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/market"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
In my dao class, My setter for the dataSource is :
#Autowired
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
However this is not doing the trick. My jdbcTemplateObject is null.
If I dont use "context:component scan ..." and use classical spring beans instead, without utilizing #Autowired annotation, all works good.
I can use my database. However, I dont want to declare all the beans one by one in my xml file. As the project grows, it is not going to be practical. How can I solve this problem ? Is it possible to declare dataSource in my dispatcher-servlet.xml as component, so #Autowired works on dataSource ?
When you use #Autowired on fields Spring will look for dependencies and inject them right there there is no point if setter method here.
You do not need to worry about how spring is going to inject the dependency. It will take care of complete life cycle.
For more on Spring's Dependecy Injection visit this link.
You have annotated the field with #Autowired which tells spring to inject the dependency directly into the field. If you really want to use the setter annotate the setter with #Autowired instead of the field.
#Autowired
public void setDataSource(DataSource ds) { ... }
However I strongly suggest to not create a JdbcTemplate for each bean that needs one (it is quite heavy to create). The JdbcTemplate is a thread-safe object, once constructed. So instead of creating a new one for each bean that needs one (in the setDataSource method) just create a single JdbcTemplateand inject that.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
Then in your dao.
#Autowired
private JdbcTemplate jdbcTemplate;
Or what I like to do..
private final JdbcTemplate jdbcTemplate;
#Autowired
public YourRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
This way you cannot construct an illegal object, whereas with setter based injection you could. While maintaining the possibility to inject one for testing purposes.
Another note, the DriverManagerDataSource is nice for testing but not for production usage, for that use a real connection pool like HikariCP or Tomcat JDBC.
I need to call some method after transaction succes or rollback. I am using as
<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref local="mysessionFactory"/>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="mysessionFactory"/>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
The application use some external web services which needs to be "cleaned" when the internal transaction gets rollbacked.
Is there way how to accomplish this without using declarative transaction management.
From Hibernate, you could extends EmptyInterceptor and override
afterTransactionCompletion() method and register it in
SessionFactoryBean or HibernateTransactionManager.
From Spring you could extends TransactionSynchronizationAdapter and
override afterCompletion() and register when appropriate with
TransactionSynchronizationManager#registerSynchronization().
Edit
An Example of using Spring Aop to add a synchronization to all methods annotated with #Transactional
#Aspect
class TransactionAspect extends TransactionSynchronizationAdapter {
#Before("#annotation(org.springframework.transaction.annotation.Transactional)")
public void registerTransactionSyncrhonization() {
TransactionSynchronizationManager.registerSynchronization(this);
}
#Override
public void afterCompletion(int status) {
// code
}
}
Spring has various classes which might be of interest here:
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/support/TransactionSynchronization.html
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationAdapter.html
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationManager.html
There's some example code here:
http://azagorneanu.blogspot.co.uk/2013/06/transaction-synchronization-callbacks.html
Update 2016
The event handling infrastructure introduced in Spring 4.2 makes this much simpler.
See:
https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2#transaction-bound-events
Another popular improvement is the ability to bind the listener of an
event to a phase of the transaction. The typical example is to handle
the event when the transaction has completed successfully
#Component
public class MyComponent {
#TransactionalEventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
...
}
}
#TransactionalEventListener is a regular #EventListener and also
exposes a TransactionPhase, the default being AFTER_COMMIT. You can
also hook other phases of the transaction (BEFORE_COMMIT,
AFTER_ROLLBACK and AFTER_COMPLETION that is just an alias for
AFTER_COMMIT and AFTER_ROLLBACK).
Using Spring 4+: The easiest/cleanest way without using global aspects and configurations is based on my answer here: https://stackoverflow.com/a/43322052/986160
If you need a callback on a #Transactional method after it successfully commits just add that in the beginning of the method:
#Service
public class OneService {
#Autowired
OneDao dao;
#Transactional
public void a transactionalMethod() {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
public void afterCommit(){
//do stuff right after commit
System.out.println("commit!!!");
}
});
//do db stuff
dao.save();
}
}