Declaring Transaction Attributes on Spring's TransactionProxyFactoryBean

Posted on January 23, 2006 by Scott Leberknight

One of the (many) benefits of using Spring for web application development is that you can declaratively define transaction boundaries on POJOs, e.g. business service layer classes that delegate to one or more DAOs underneath. One of the simplest ways to do this is to use Spring's TransactionProxyFactoryBean to specify how to apply transactions to methods on a proxied object. Without going into all the gory details of how Spring AOP works, using dynamic proxies and such, there is something to watch out for when using this useful class. Typically when using TransactionProxyFactoryBean you'll create a parent bean definition in your Spring ApplicationContext which defines the transaction manager and the transaction attributes. You then create child beans which inherit the transaction manager and transaction attributes. For example:

<bean id="abstractTransactionProxy"
    abstract="true"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="hibernateTransactionManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
            <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
            <prop key="is*">PROPAGATION_SUPPORTS,readOnly</prop>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

You would then create child beans which inherit from abstractTransactionProxy and which are your actual service POJOs. For example:

<bean id="customerService" parent="abstractTransactionProxy">
    <property name="target" ref="customerTarget"/>
</bean>

<bean id="productService" parent="abstractTransactionProxy">
    <property name="target" ref="productTarget"/>
</bean>

Easy enough, right? The child beans will now inherit the transaction manager and all the transaction attributes. The definition of transaction attributes in abstractTransactionProxy specifies several things. First, any method whose name begins with "get", "find", or "is" will support execution within a transaction, and the "readOnly" marker indicates that they can be executed in a read-only mode. So, if one of these methods is called when there is no existing transaction, then no transaction will be created and the method executes without the overhead of a database transaction. If one of the methods is called when there is an existing transaction, it simply inherits the transactional context and executes within the transaction. So far so good. Now, the last part of the transaction attributes definition specifies a "*" as the method name, meaning any other method whose name doesn't start with "get", "find", or "is." In addition, any other method is required to execute within a transaction. If an existing transaction exists the method will inherit the transactional context; if not then a new transaction will be automatically created. The "*" acts as a catch-all against a developer who adds a new method that must execute transactionally but who forgets to add the method to the transaction attributes definition. Take the following example:

<bean id="abstractTransactionProxy"
    abstract="true"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="hibernateTransactionManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="create*">PROPAGATION_REQUIRED</prop>
            <prop key="update*">PROPAGATION_REQUIRED</prop>
            <prop key="delete*">PROPAGATION_REQUIRED</prop>
            <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
        </props>
    </property>
</bean>

What's the difference here? In this case, if a developer doesn't follow the naming conventions for "bang" methods - methods that insert, update, or delete database records - then no transactions are applied and their changes will not be committed to the database. For example, suppose a developer creates a method named "saveProduct" in a class which has the above transaction attributes applied to it. What happens? It supports an existing transaction but if called without an existing transaction it will execute non-transactionally and in a read-only fashion, since the "*" transaction attribute is the rule that applies. Thus the database changes would never take effect! In fact, if the method is sometimes called when there is an existing transaction and sometimes not, a subtle bug would arise since sometimes the database changes would be committed and sometimes not! To allow developers to add methods whose name begins with "save," you would have to add another transaction attribute definition. Even worse, what happens if no rule matches a given method? Take the following:

<bean id="abstractTransactionProxy"
    abstract="true"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="hibernateTransactionManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="create*">PROPAGATION_REQUIRED</prop>
            <prop key="update*">PROPAGATION_REQUIRED</prop>
            <prop key="delete*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

For this example, if a method named "saveProduct" is executed, none of the above transaction attributes apply, and the method is assumed to be non-transactional. So what is the point of all this? There are several. First, define your transaction attributes explicitly for read-only methods like "get*" and "find*". Second, have the read-only method definitions support an existing transaction using PROPAGATION_SUPPORTS and add the readOnly marker. This ensures that when there is no existing transaction, the method executes non-transactionally and may be optimized by the JDBC driver and database to be read-only. Third, add a "*" rule to the transaction attributes definition which specifies the default transaction rule. Fourth, make this default catch-all rule be as conservative as possible. Usually you will want to use PROPAGATION_REQUIRED, as this will require the method to execute within an existing transaction or create a new one. It is much better to have a read-only method execute transactionally than have a bang method which changes database state execute non-transactionally, even though it will have additional overhead. Finally, perform code reviews or write a script or find some way to automate checking that your naming conventions are being followed so that methods execute with the correct transactional context.

No One "Caught" It?

Posted on January 14, 2006 by Scott Leberknight

Apparently none of the <sarcasm>tons of people who read my blog</sarcasm> caught the fact that in my test failings part ii entry the test code is wrong. (I only caught it because I read that entry as I was writing abour validation in Rails.) If the line of code dao.findVisit(-9999L) executes without throwing any exception, then the test still passes! Just because the test method throws Exception and the try/catch only deals with HibernateObjectRetrievalFailureException does not mean the test fails when the findVisit method throws no exception at all. You still need to remember to call fail() if no exception is thrown, as the following shows.

public void testFindNonExistentVisit() throws Exception {
    try {
        dao.findVisit(-9999L);
        fail("findVisit should have thrown an exception!");  // you do need this line!
    }
    catch (HibernateObjectRetrievalFailureException ex) {}
}

So even though all the ExceptionAssertionTemplate code is more verbose (hey, it's what you expect from Java developers, right?) it still ensures that you don't forget to add the call to fail() in your test methods. I don't think it's that much more verbose, and since I apparently cannot even get my code correct in a blog entry, it's probably a good idea to use it, or else I'll keep forgetting to call fail() and have my tests passing when they should fail.

Supressing Validation in Rails On Fields That Are Not Required

Posted on January 14, 2006 by Scott Leberknight

I've been really busy since my last post, which was was back in October of last year. Time goes by too damn fast! Anyway, I've been mucking around with Ruby on Rails lately and was adding some validation to a model object. I had a bunch of fields that are not required, but if a value is entered they should be validated against a specific format. In my case email addresses and phone numbers. Normally to validate the format of a field in Rails you can simply write the following. (Note that EMAIL_FORMAT is a Regexp object created as a constant in the class in case you wonder where it came from.)

validates_format_of :email,
                    :with => EMAIL_FORMAT,
                    :message => 'must be a valid email address, e.g. a@b.com'

That is all well and good except for the minor problem that this will cause Rails to run validation on the email field regardless of whether it is empty or not. So even though the field isn't required, Rails will validate it and report an error back to the user. Not exactly what I had in mind.

So after some extensive Googling, I found some documentation and examples that use the :if option along with a Proc object, which I have heard of but don't really understand. I'll learn that later, as for now I simply want to make the validation work properly. So the following code will validate the email address, but only if the user actually entered a value.

validates_format_of :email,
                    :allow_nil => true,
                    :with => EMAIL_FORMAT,
                    :if => Proc.new {|c| not c.email.blank?},
                    :message => 'must be a valid email address, e.g. a@b.com'

So that's how you do it. You create a new Proc object with a block that checks whether the field you are validating is blank. Rails will only run validation on the email field if it's not blank. Note that I also used the allow_nil option to tell Rails that a nil value is OK. If the value is nil then validation is suppressed. But won't that take care of blank values sent in from a web form? Unfortunately Rails (at least by default) will not convert empty strings received from the HTTP request parameters to nil automatically. If it did, then the :if option would not be required in the validation. So if, for example, you sent a GET request with the query string "first_name=Scott&last_name=Leberknight&email=&cell_phone=&home_phone=", Rails would assign empty strings to email, cell_phone, and home_phone request parameters. Or perhaps I should say it simply takes the request parameters as they are sent by the browser and assigns the values sent by the browser. This behavior is the same for POST requests when you don't fill out a value for things like text fields and text areas, select lists, etc. in forms. The crappy thing about empty strings is that they'll be stored in your database as empty strings rather than as null values. That's something to research later, as I want null values instead of empty strings in my database.