autocommit and @Transactional and Cascading with spring, jpa and hibernate
15,579
- you can't have queries without an active transaction in hibernate
-
@Transactional
has apropagation
attribute, which identifies the transaction behaviour when new methods are called. The default isREQUIRED
, which is what you want. Here you can find a graphical presentation of the concept. -
you can omit using
@Transactional
if you set-up your transactional methods with aop, like this:<aop:config> <aop:pointcut id="serviceMethods" expression="execution(* com.company.product.service..*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" /> </tx:attributes> </tx:advice>
That makes all public methods in the
service
package transactional.
Also, feel free to read the entire chapter on spring transactions.
Author by
subes
Updated on June 04, 2022Comments
-
subes almost 2 years
what I would like to accomplish is the following:
- have autocommit enabled so per default all queries get commited
- if there is a @Transactional on a method, it overrides the autocommit and encloses all queries into a single transaction, thus overriding the autocommit
- if there is a @Transactional method that calls other @Transactional annotated methods, the outer most annotation should override the inner annotaions and create a larger transaction, thus annotations also override eachother
I am currently still learning about spring-orm and couldn't find documentation about this and don't have a test project for this yet.
So my questions are:
- What is the default behaviour of transactions in spring?
- If the default differs from my requirement, is there a way to configure my desired behaviour?
- Or is there a totally different best practice for transactions?
--EDIT--
I have the following test-setup:
@javax.persistence.Entity public class Entity { @Id @GeneratedValue private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } @Repository public class Dao { @PersistenceContext private EntityManager em; public void insert(Entity ent) { em.persist(ent); } @SuppressWarnings("unchecked") public List<Entity> selectAll() { List<Entity> ents = em.createQuery("select e from " + Entity.class.getName() + " e").getResultList(); return ents; } }
If I have it like this, even with autocommit enabled in hibernate, the insert method does nothing. I have to add @Transactional to the insert or the method calling insert for it to work...
Is there a way to make @Transactional completely optional?
-
subes over 14 yearshmm, ok that would work, seems like the idea I had about using autocommit was a bad idea anyway. I think it would be better practice for me to just annotate the services propertly. autocommit on any db operation would too easily lead to a broken state. instead of doing a blacklist approach I should go with a whitelist (metaphorical). I will try to create an advice that adds @Transactional to all beans annotated with @Service. Though first read about spring-aop. :) thanks
-
subes over 14 yearsthe advice for transactional was a bad idea afterall: -- ibm.com/developerworks/java/library/… -- stackoverflow.com/questions/1882959/… -- my solution is to only annotate methods that do write operations and leave the rest not annotated. Adding propagation=SUPPORTS and readonly=true would maybe increase performance with hibernate, but that is currently too much effort for me to put into an aspectj CTW aspect.
-
polve about 12 yearsI have just had problems like this, and found your reference to readOnly=true and propagation=SUPPORTS. Just a word of warning: ibm.com/developerworks/java/library/j-ts1/index.html#N101B1 it doesn't work that way.