开发者

Using and controlling Spring transactions within Struts 2 actions

I have been working for a while on a project with the following components:

  • Struts2.1.8.1,
  • Spring 3.0.3
  • JPA 2.0,
  • Hibernate 3

I am using Spring's EntityManager magic... But I'm having problems dealing with transactions inside my actions. For instance, I am setting values on my persisted object in several methods within my class, and I want to be able to rollback if the validate method finds a validation error, or commit these changes otherwise. I have already spent quite a long time reading half of the internet for a comprehensive explanation. Unfortunately, no complete examples exist (at least similar to my stack).

I have stumbled with this thread on a mailing list: @Transactional Spring Annotation in a Struts2 Action does not work. The message I'm linking at seems to have a pretty simple and straightforward solution, using a TransactionInterceptor will do the trick it seems... The problem is that I'm not finding useful information regarding this interceptor.

Anyone here has experience with this technology and can spare a tip and a link 开发者_开发技巧or two on how to use Spring transactions inside Struts2 actions?

Thanks!

- Edit 1 -

I have set up a test project if you are interested, just download the file and try it out (or inspect it). Thanks!


Generally, controllers/actions/backing beans/etc don't handle transactions. Actions are the web-part of your back-end code - they should only be concerned with gathering request data, and sending response data. The logic itself (including database access) should be done in another layer. E.g. a service layer. So you create another bean, inject it in the action, and make it do the work - userService.register(user). Then configuring transactions on a service layer should be trivial since it is both in the spring documentation and in countless examples:

<tx:annotation-driven /> and @Transactional (btw, make sure you have the <tx:..> now, it might be causing the issue. Even if it works, this does not invalidate my suggestion about the service layer)


I don't like answering my own question, but since I solved this ages ago... I thought I should share the knowledge (or lack of... in this case).

The book I was using to learn about Struts 2 and Spring-JPA-Hibernate, adds the @Transactional annotation right before the declaration of the service class. This is terribly wrong, for all methods (including those that only retrieve stuff from the database) are inside a committable transaction. Long story short everything got committed event if exceptions occurred.

The solution, as Bozho so wisely pointed out, was to look at examples. That is, set your transtactional methods carefully, in my case I set up transactions for the methods that had to write back to the database and everything started to work just fine.

Thanks to Steven and Quaternion too for taking the time to answer my question.


Based on your question, here's what I understand about your problem.

You want to wrap your action invocation in a transaction. If the validate method records validation errors, you want to roll the transaction back. Presumably, you also want to rollback in case of an error.

Solution

Create an interceptor that will:

  • Start a transaction
  • Invoke the action inside of a try/catch block
  • Rollback the transaction if there is an exception or if there are any validation errors on the action (this can be detected using action.hasErrors)
  • Commit the transaction

You will probably want this interceptor defined pretty early in the stack. I don't know of any pre-built interceptors for this (although there may be some), but it should be fairly easy to assemble.

Update

I don't use Spring, so I can't say how the JPA transaction support works there, but you can handle transactions for your EntityManager like:

try {
    entityManager.getTransaction().begin();
    // do your thing
    entityManager.getTransaction().commit();
} catch (Exception e) {
    entityManager.getTransaction().rollback();
    throw new PersistenceException(e);
}

This is just a crude example, but it should illustrate the point.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜