开发者

Hibernate Session flush behaviour [ and Spring @Transactional ]

开发者 https://www.devze.com 2022-12-30 20:47 出处:网络
I use Spring and Hibernate in a web-app, SessionFactory is injected into a DAO bean, and then this DAO is used in a Servlet through webservicecontext.

I use Spring and Hibernate in a web-app,

SessionFactory is injected into a DAO bean, and then this DAO is used in a Servlet through webservicecontext.

DAO methods are transactional, inside one of the methods I use ... getCurrentSession().save(myObject);

One servlet calls this method with an object passed.

The update seems to not be flushed at once, it takes about 5 seconds to see the changes in the database. The servlet's method in which that DAO's update method is called, takes a fraction of second to complete.

After the @Trans开发者_如何学Cactional method of DAO is completed, flushing may NOT happen ? It does not seem to be a rule [ I already see it ].

Then the question is this: what to do to force the session to flush after every DAO method? It may not be a good thing to do, but talking about a Service layer, some methods must end with immediate flush, and Hibernate Session behavior is not predictable.

So what to do to guarantee that my @Transactional method persists all the changes after the last line of that method code?

 getCurrentSession().flush() is the only solution?

p.s. I read somewhere that @Transactional IS ASSOCIATED with a DB Transaction. Method returns, transaction must be committed. I do not see this happens.


Once the "top level" @Transactional method has completed (ie the method called from your servlet), then the transaction should be committed, and the default Hibernate behaviour is to flush on the commit.

It sounds like something odd is happening and you should do a bit of investigating.

Investigate your logs, in particular I would set the logging level to DEBUG on your Transaction Manager to see exactly what the transaction manager is doing.

Also, set the logging on for hibernate (set show_sql to true): this will output to System.out when flushing is happening and this might give you some clues.

Do report back if you find anything interesting.


Amaze I think this one be exact answer which can solve such exact situation, you can use FlushMode.ALWAYS for particular DAO whenever you require to flush session restrict fully after every transaction.

@Autowired
private SessionFactory sessionFactory;

@Before
public void myInitMethod(){
  sessionFactory.getCurrentSession().setFlushMode(FlushMode.ALWAYS);
}

ALWAYS flushmode is not preferable because it is costly, but as you are require you can multiple session factory with different flushmode for different requirement.


I had this problem too! I'm using Spring annotation transaction (@Transactional) and I'm getting some method actually doing the session.flush(), and other not!

From my debug log I have:

transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!

The session.close() has to be called from Spring TransationManager, but I'm not sure what's going on: I double-checked my Spring configuration and I cannot argue why this is happening. I further investigate and I'll repost any hint but if someone has some useful advice I'ld be very grateful :o)

Update: The problem seems related to hibernate session flush mode = MANUAL: it didn't flush objects at the end of Spring's transaction.

You can verify your current flush mode with something like:

SessionFactoryUtils.getSession(mySessionFactory(), false).getCurrentSession().getFlushMode()


UPDATE [SOLVED FOR ME]:

I dug a lot into my problem and found the origin of the problem and a workaround.

I had, as you if I understand well, an intermittent problem where some transactions were closed correctly (i.e. hibernate sessions were flushed) and some others not.

I discovered that:

  1. the problem was due to flushMode set to FlushMode.MANUAL when I entered the transaction (that not trigger the flush operation when transaction commits);

  2. this in turn was due to something nasty going on between Spring and ZK (the bad transactions were all from ZK's composers - if you don't know ZK, they are called from servlets, roughly equivalent to Struts' actions);

  3. the precise problem lies in the Spring's OpenSessionInViewFilter not correctly communicating with ZK's filters: the Hibernate session provided by OpenSessionInViewFilter is not getting its flush mode correctly set. The single ZK composer works well (I've tested it from some JUnit tests), as well as the OpenSessionInViewFilter alone (I've tested it from a plain Servlet using WebApplicationContextUtils).

Conclusion: I call session.flush() at the end of every @Transactional method in my composers, and I'll migrate to Vaadin (much much simpler to integrate, it seems).


For your particular need (flushing at every DAO method call), you can set the session flush mode to FlushMode.ALWAYS. From the hibernate documentation:

The Session is flushed before every query.


setting the "hibernate.transaction.flush_before_completion" property to true might help.

<prop key="hibernate.transaction.flush_before_completion">true</prop>

https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/
"If enabled, the session will be automatically flushed during the before completion phase of the transaction. Built-in and automatic session context management is preferred, see Section 2.5, “Contextual sessions”".


I wouldn't recommend using hibernate.transaction.flush_before_completion globally for performance reasons.

Alternatively, you can manage transactions yourself:

@PersistenceContext
private EntityManager em;
....
public void save(){
    try
    {         
        em.getTransaction().begin();                

        <update database>

        em.getTransaction().commit();                        
    }
    catch(Throwable th) {
        em.getTransaction().rollback();
        //log, rethrow
    }        
}
0

精彩评论

暂无评论...
验证码 换一张
取 消