1

I am doing some tests to understand the behaviour of @Transactional in Spring 3. Though, it is not working as I would expect. If have one method with Propagation.REQUIRED calling another with Propagation.REQUIRES_NEW, will the second method be able to retrieve from the DB the data inserted by the first method?

EDITED: I AM seeing uncommitted changed in a @Transaction, here is my (nasty looking) code.

@Service
public class FeedManager {
   @Autowired
   JdbcTemplate jdbcTemplate;

   @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
   public boolean createFeed(Feed feed, boolean anonymizeIt) {
      String query = "INSERT INTO feed (name, url, is_active) values (?, ?, ?)";
      int rowsAffected = jdbcTemplate.update(query, feed.getName(), feed.getUrl(), feed.isActive()); 
      boolean success = (rowsAffected == 1); 
      if (anonymizeIt) {
         success = success && this.anonymizeFeedName(feed);
      }
      return success;
   }

   @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
   public boolean anonymizeFeedName(Feed feed) {
      String query = "UPDATE feed set name = ? where name = ?";
      int rowsAffected = jdbcTemplate.update(query, feed.getName() + (new Date()).toString(), feed.getName());
      boolean success = (rowsAffected == 1);
      return success;
   }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:mrpomario/springcore/jdbc/jdbc-testenv-config.xml")
public class TransactionalTest {
   @Autowired
   FeedManager feedManager;

   Feed feed;

   @Before
   public void setup() {
      feed = new Feed("RSS", "http://www.feedlink.com", true);
   }

   @Test
   public void test_Create()  {
      assertTrue(feedManager.createFeed(feed, false));
   }

   @Test
   public void test_Anonymize() {
      assertTrue(feedManager.anonymizeFeedName(feed));
   }

   @Test
   public void test_Create_And_Anonymize() {
      Feed feedo = new Feed("AnotherRSS", "http://www.anotherfeedlink.com", true);
      assertTrue(feedManager.createFeed(feedo, true));
   }
}

1 Answers1

4

It should not be able to see any changes made by the first method (as long as your isolation level is READ COMMITTED or above).

If you get different results, make sure that @Transactional actually takes effect. In particular, make sure that you don't call another @Transactional method of the same class - due to limitations of Spring proxy-based AOP model transactional aspect is applied only to calls that come from the outside of the class.

See also:

axtavt
  • 239,438
  • 41
  • 511
  • 482
  • I agree. That's the behaviour I expected to see given that READ_COMMITED is the default for @Transaction. Though, why am I seeing the uncommited data in the second method? –  Sep 11 '12 at 13:47
  • The only case when you can see uncomitted changes is when you are inside a transaction that made them. That's why I suspect that the second `@Transactional` doesn't take effect. – axtavt Sep 11 '12 at 13:50
  • I agree with you, that's what the documentation says but not what I am seeing. I just added my code in which I noticed the unexpected behaviour. –  Sep 11 '12 at 14:07
  • 2
    Have you read the second part of my answer? That's exactly the case I tell you about - `@Transactional` doesn't take effect when you call different method of the same class. See http://stackoverflow.com/questions/7482666/get-aop-proxy-from-the-object-itself for workarounds. – axtavt Sep 11 '12 at 14:13