Should you place the @Transactional
in the DAO
classes and/or their methods or is it better to annotate the Service classes which are calling using the DAO objects? Or does it make sense to annotate both "layers"?
19 Answers
In general I agree with the others stating that transactions are usually started on the service level (depending on the granularity that you require of course).
However, in the mean time I also started adding @Transactional(propagation = Propagation.MANDATORY)
to my DAO layer (and other layers that are not allowed to start transactions but require existing ones) because it is much easier to detect errors where you have forgotten to start a transaction in the caller (e.g. the service). If your DAO is annotated with mandatory propagation you will get an exception stating that there is no active transaction when the method is invoked.
I also have an integration test where I check all beans (bean post processor) for this annotation and fail if there is a @Transactional
annotation with propagation other than Mandatory in a bean that does not belong to the services layer. This way I make sure we do not start transactions on the wrong layer.
Transactional Annotations should be placed around all operations that are inseparable.
For example, your call is "change password". That consists of two operations
- Change the password.
- Audit the change.
- Email the client that the password has changed.
So in the above, if the audit fails, then should the password change also fail? If so, then the transaction should be around 1 and 2 (so at the service layer). If the email fails (probably should have some kind of fail safe on this so it won't fail) then should it roll back the change password and the audit?
These are the kind of questions you need to be asking when deciding where to put the @Transactional
.
The correct answer for traditional Spring architectures is to place transactional semantics on the service classes, for the reasons that others have already described.
An emerging trend in Spring is toward domain-driven design (DDD). Spring Roo exemplifies the trend nicely. The idea is to make the domain object POJOs a lot richer than they are on typical Spring architectures (usually they are anemic), and in particular to put transaction and persistence semantics on the domain objects themselves. In cases where all that's needed is simple CRUD operations, the web controllers operate directly on the domain object POJOs (they're functioning as entities in this context), and there's no service tier. In cases where there's some kind of coordination needed between domain objects, you can have a service bean handle that, with @Transaction
as per tradition. You can set the transaction propagation on the domain objects to something like REQUIRED
so that the domain objects use any existing transactions, such as transactions that were started at the service bean.
Technically this technique makes use of AspectJ and <context:spring-configured />
. Roo uses AspectJ inter-type definitions to separate the entity semantics (transactions and persistence) from the domain object stuff (basically fields and business methods).
The normal case would be to annotate on a service layer level, but this really depends on your requirements.
Annotating on a service layer will result in longer transactions than annotating on DAO level. Depending on the transaction isolation level that can youse problems, as concurrent transactions wont see each other's changes in eg. REPEATABLE READ.
Annotating on the DAOs will keep the transactions as short as possible, with the drawback that the functionality your service layer is exposing wont be done in a single (rollbackable) transaction.
It does not make sense to annotate both layers if the propagation mode is set to default.
I place the @Transactional
on the @Service
layer and set rollbackFor
any exception and readOnly
to optimize the transaction further.
By default @Transactional
will only look for RuntimeException
(Unchecked Exceptions), by setting rollback to Exception.class
(Checked Exceptions) it will rollback for any exception.
@Transactional(readOnly = false, rollbackFor = Exception.class)
Or does it make sense to annotate both "layers"? - doesn't it make sense to annotate both the service layer and the dao layer - if one wants to make sure that DAO method is always called (propagated) from a service layer with propagation "mandatory" in DAO. This would provide some restriction for DAO methods from being called from UI layer (or controllers). Also - when unit testing DAO layer in particular - having DAO annotated will also ensure it is tested for transactional functionality.
Also, Spring recommends only using the annotation on concrete classes and not interfaces.
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
For Transaction in database level
mostly I used @Transactional
in DAO's just on method level, so configuration can be specifically for a method / using default (required)
DAO's method that get data fetch (select .. ) - don't need
@Transactional
this can lead to some overhead because of transaction interceptor / and AOP proxy that need to be executed as well.DAO's methods that do insert / update will get
@Transactional
very good blog on transctional
For application level -
I am using transactional for business logic I would like to be able rolback in case of unexpected error
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}
Usually, one should put a transaction at the service layer.
But as stated before, the atomicity of an operation is what tells us where an annotation is necessary. Thus, if you use frameworks like Hibernate, where a single "save/update/delete/...modification" operation on an object has the potential to modify several rows in several tables (because of the cascade through the object graph), of course there should also be transaction management on this specific DAO method.
@Transactional
Annotations should be placed around all operations that are inseparable.
Using @Transactional
transaction propagation are handled automatically.In this case if another method is called by current method,then that method will have the option of joining the ongoing transaction.
So lets take example:
We have 2 model's i.e. Country
and City
. Relational Mapping of Country
and City
model is like one Country
can have multiple Cities so mapping is like,
@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Here Country mapped to multiple cities with fetching them Lazily
. So here comes role of @Transactinal
when we retrieve Country object from database then we will get all the data of Country object but will not get Set of cities because we are fetching cities LAZILY
.
//Without @Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
When we want to access Set of Cities from country object then we will get null values in that Set because object of Set created only this Set is not initialize with there data to get values of Set we use @Transactional
i.e.,
//with @Transactional
@Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
Object object = country.getCities().size();
}
So basically @Transactional
is Service can make multiple call in single transaction without closing connection with end point.
It is better to have it in the service layer! This is clearly explained on one of the article that I came across yesterday! Here is the link that you can check out!
First of all let's define where we have to use transaction?
I think correct answer is - when we need to make sure that sequence of actions will be finished together as one atomic operation or no changes will be made even if one of the actions fails.
It is well known practice to put business logic into services. So service methods may contain different actions which must be performed as a single logical unit of work. If so - then such method must be marked as Transactional. Of course, not every method requires such limitation, so you don't need to mark whole service as transactional.
And even more - don't forget to take into account that @Transactional obviously, may reduce method performance. In order to see whole picture you have to know transaction isolation levels. Knowing that might help you avoid using @Transactional where it's not necessarily needed.
The @Transactional
should be used on service layer as it contains the business logic. The DAO layer usually has only database CRUD operations.
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
Spring doc : https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
Service layer is best place to add @Transactional
annotations as most of the business logic present here, it contain detail level use-case behaviour.
Suppose we add it to DAO and from service we are calling 2 DAO classes , one failed and other success , in this case if @Transactional
not on service one DB will commit and other will rollback.
Hence my recommendation is use this annotation wisely and use at Service layer only.
It's better to keep @Transactional in a separate middle layer between DAO and Service Layer. Since, rollback is very important, you can place all your DB manipulation in the middle layer and write business logic in Service Layer. Middle layer will interact with your DAO layers.
This will help you in many situations like ObjectOptimisticLockingFailureException - This exception occurs only after your Transaction is over. So, you cannot catch it in middle layer but you can catch in your service layer now. This would not be possible if you have @Transactional in Service layer. Although you can catch in Controller but Controller should be as clean as possible.
If you are sending mail or sms in seperate thread after completing all the save,delete and update options, you can do this in service after Transaction is completed in your middle layer. Again, if you mention @Transactional in service layer, you mail will go even if your transaction fails.
So having a middle @Transaction layer will help to make your code better and easy to handle. Otherwise, If you use in DAO layer, you may not be able to Rollback all operations. If you use in Service layer, you may have to use AOP(Aspect Oriented Programming) in certain cases.
Ideally, Service layer(Manager) represents your business logic and hence it should be annotated with @Transactional
.Service layer may call different DAO to perform DB operations. Lets assume a situations where you have N number of DAO operations in a service method. If your 1st DAO operation failed, others may be still passed and you will end up inconsistent DB state. Annotating Service layer can save you from such situations.