views:

139

answers:

2

Not sure if 'scope' is the correct term here.

I am using Spring for JPA transaction management (with a Hibernate underneath). My method to preform database transaction is private, but since you can only set @Transactional on a class or on a public method

Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

I have set the public entry point of the class as @Transactional.

@Transactional
public void run(parameters) {
    //First non-database method, takes a decent amount of time
    Data data = getData();
    //Call to database
    storeData(data);
}

private storeData(data) {
    em.persist(data);
}

Is this bad practice? Is Spring keep an open transaction for longer then needed here? I was thinking of move the storeData() method to a DAO class and making it public, but as academic point, I wanted to know if refactoring to public would have any performance benefit.

+1  A: 

If there's heavy contention on the DB, keeping transactions as small as possible is definitely crucial -- much more important than public vs private distinctions, which, per se, don't affect performance and scalability. So, be practical...!

Alex Martelli
I think you might have misunderstood my question. @Transactional can only exist on a public method, but what I am asking is should we try the limit the @Transactional to methods that are solely doing database work.
James McMahon
I did understand: we should indeed limit transaction scopes as tightly as possible, and if that means making some things public that you'd rather keep private, that's not the end of the world.
Alex Martelli
+1  A: 

The transaction scope is has no effect until your code does something which interacts with the transaction context, in this case the storeData() method. The fact that getData() is non-transactional should not affect the performance on concurrency of your code, since any database locking will only happen when storeData() is reached.

skaffman
Depends on the transaction isolation level. With SERIALIZABLE isolation, the database needs to keep track of the state at the beginning of the transaction so that commits from other transactions don't affect your reads.
andri
@andri, when does the transaction begin then? I thought skaffman was saying it doesn't start until the call to em.persist?
James McMahon
As far as the database is concerned, the transaction only begins when a connection to the database is obtained. If this isn't done until the storeData() method is called, then as far as the database is concerned, that's when the transaction starts. Before the connection is contained, the database isn't involved, and isn't informed.
skaffman
I didn't realize when I initially wrote this question, but you can set @Transactional on the class level. So Spring must being doing some to limit the transaction length.
James McMahon