Where does the @Transactional annotation belong?

2018-12-31 08:45发布

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条回答
情到深处是孤独
2楼-- · 2018-12-31 09:01

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)

  1. 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.

  2. 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(..);
    }
}
查看更多
情到深处是孤独
3楼-- · 2018-12-31 09:02

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.

查看更多
初与友歌
4楼-- · 2018-12-31 09:04

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.

查看更多
孤独寂梦人
5楼-- · 2018-12-31 09:07

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)

See Checked vs. Unchecked Exceptions.

查看更多
怪性笑人.
6楼-- · 2018-12-31 09:08

@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.

查看更多
不再属于我。
7楼-- · 2018-12-31 09:13

I think transactions belong on the Service layer. It's the one that knows about units of work and use cases. It's the right answer if you have several DAOs injected into a Service that need to work together in a single transaction.

查看更多
登录 后发表回答