The annotation @Transactional
demarcates transactions (you can start nested transactions, propagate transactions to other layers, etc.). The transaction is an isolated work unit that takes the database from one consistent state to another consistent state. Think in terms of business transactions yourself.
The recommendation for not demarcating the DAO layer but the business layer is due to the very nature and granularity of operations of each layer. Operations of the DAO layer usually have fine granularity (insert something, update something, consult something, etc). The business layer is thicker granularity, and can group various operations of the DAO layer (as well as other layers; e.g., JMS queues).
Bean de Negócio
@Autowired BeanDAO1
@Autowired BeanDAO2
@Transactional
meu método de negócio() {
consulta algo do DAO1
faz um processamento
insere algo no DAO2
faz um update no DAO1
}
See what business methods are good candidates for transactional "work units". The idea is that the work unit that takes the bank from one consistent state to another consistent state perform various operations. You want one of two things to happen:
- the business method is successfully executed and a commit of everything be done
- Any exception occurs, in this case a rollback shall be done for the previous state (as if none of the operations had taken place).
Now imagine that you wrote down the insertion method of DAO2 with @Transactional(propagation=Propagation.REQUIRES_NEW)
(something that made sense in a certain piece of your application). If you do this your business method will no longer do rollback than was inserted into DAO2 (since the Insert happens in your own transaction). Imagine now that the update in the DAO1 failed and fired an exception; with this will be made a rollback that update, however the value inserted by DAO2 in the previous step will be maintained, potentially leaving your database in an inconsistent state. In this way it is good practice to make the DAO layer a mere "consumer" of transactions, and not an active agent of demarcations.
Open Session in view replaces transactional demarcation?
Not. Ok, I was a bit categorical here; but the truth is that if all transactions in your application have the same scope of the request (transaction-per-request) this is a strong indication that there is something wrong.
The purpose of the pattern Open Session in View (Osiv) is to facilitate the life of the programmer, allowing entities to be loaded in a lazy manner (Lazy) at render time of view (avoiding LazyInitializationException
and similar).
<!-- Poderia disparar uma exceção se a sessão estivesse fechada -->
#{minhaEntidade.listaDeOutrasEntidadesLazy}
I’ve had several discussions about the pattern Osiv, I personally consider it an anti-standard, or at least a bad practice. While there are several advocates of the standard, I am not alone on the list of dissidents. Osiv is certainly useful and saves the programmer time avoiding that he has to worry about checking if the expected objects were correctly loaded. On the other hand, abusing this type of technique also stimulates the proliferation of various problems. Neglect of transactional demarcation is one of them, as well as problems of the type N + 1
consultations.
Let’s say for example that your JPA provider has to make a query to retrieve each of the entities from a list Lazy, this will generate several selects unnecessary; something that could have easily been solved with a JOIN FETCH
will potentially undetected for production due to the use of Osiv. At best Osiv acts as a safety net and hides the problem, in the worst case it creates an even bigger problem.
From the architectural point of view, long transverse sections end up tying the layers: exceptions of the data layer potentially affect the view, can happen at render time. From the point of view of performance Long-term sessions end up consuming more resources. From the point of view of reliability the standard ends up making room for unexpected failures, etc, etc, etc.
Anyway, as the subject is controversial, I make it clear that this is just my opinion.
Now about transactional control there is not much to discuss; your business methods must have well demarcated transactions according to the rules of your application. If eventually you want to use Osiv to carry something on view OK, but at this stage all business transactions must already have been committed. That is, one thing is business transactions with potentially destructive writing operations and another completely different is the session that is open on view for late loading of objects of a particular query.
Thank you first for answering me. For me to understand: the method demarcation is used to define the nature of each method under a transaction, such as whether a method should be executed in the current transaction or whether a transaction will be created for the execution of the current transaction, or should not execute during a transaction, etc.. Right? About Osiv, the most serious that I saw in the link you mentioned was the breaking of architecture in layers, because there is the concern to open transactions in the presentation layer which conceptually is bad.
– klaytonbrito
Completing the previous answer, the problem N + 1 can be solved with the
JOIN FETCH
,BATCH FETCHING
(pagination of the collection of objects -I just don’t know if I can use JOIN in this). About a problem cited in the text of the link: "...if an Exception occurs while fetching the Session...", I find it hard to happen this kind of exception, I can only imagine it happening because of poor configuration/programming. Do you think it’s best to open transactions in the business rule classes? Or even use AOP in those classes?– klaytonbrito
Hello Klayton, I’m happy to help. About the demarcation of transactions, that’s right. In other words, it sets the boundaries of the work units. You can propagate the current transaction to the methods being called, create a separate transaction for a particular method, etc (the idea is that the transaction "involves the method").
– Anthony Accioly
About Osiv, I didn’t mean that it is the cause of N+1 problems (the cause of N+1 problems is bad programming as you well detected). My point here is that Osiv "favors sloppiness", if the programmer does not stay tuned to the logs may end up leaving an easy-to-solve problem escape for production. A colleague once told me that Osiv is the "security network of inexperienced programmers", I already think differently, I prefer that programmers spend a little time treating
LazyInitializationException
and similar than letting slip this kind of problem.– Anthony Accioly
About problems during variable startup Lazy during rendering, they do happen. Imagine a timeout or a value that has been removed from the bank externally (outside the persistence context). The problem pointed out is that by this time of the championship the code is no longer under your control, that is, you cannot simply give a
catch
at the level of controller and send the user to an error screen (because the controller has already done its part and is out of the picture). The problem is not so exotic (I’ve seen it happen).– Anthony Accioly
Finally, Spring Ejbs, Proxys or AOP etc do not get rid of transactional demarcation. Annotations are what make everything work. Between declarative transactional control (Spring or EJB annotations) vs explicit control, I personally prefer transactional demarcation because of its simplicity.
– Anthony Accioly
I want to make it clear though that I’m not telling you to abandon the Osiv (the article even mentions Gavin King, I’m not disdaining what he said :)); I just don’t have it Osiv as one of my favorite practices... I spent a lot of time maintaining systems that made bad use of JPA / JTA / Spring, with nonexistent transactional demarcation, horrendous queries and all kinds of gambiarra. For example: screens that trigger hundreds of queries to the bank due to problems of N + 1. Today, when I can, I use the good old
JdbcTemplate
(simple is better ;)).– Anthony Accioly
Hmmm understood about the danger of Osiv, it "hides" from the programmer certain problems that still exist even using the Osiv and the chance for programmers to fall for this is great. On the control of transactions, I was thinking of an alternative to Osiv (calm, I won’t abandon it), and I was thinking of using AOP to start and commit transactions because as I understand it here, it’s not just because I have the methods spelled out that the transaction by magic would start and commit alone, I have to explicitly define when to start and commit right? Or did I travel?
– klaytonbrito
Let’s go continue this discussão in chat.
– Anthony Accioly