DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Building a CRUD Application With Spring and SimpleJdbcMapper
  • How to Marry MDC With Spring Integration
  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux

Trending

  • AI Agents in Java: Architecting Intelligent Health Data Systems
  • Dear Micromanager: Your Distrust Has a Job; It’s Just Not the One You’re Doing
  • You Learned AI. So Why Are You Still Not Getting Hired?
  • Context Is the New Schema
  1. DZone
  2. Coding
  3. Frameworks
  4. A Word on Spring @Transactional and Exceptions

A Word on Spring @Transactional and Exceptions

Spring's @Transactional is very popular among developers. Yet, many of them are unaware of its weird exception handling convention, which can lead to inconsistent data.

By 
Shaamik Mitraa user avatar
Shaamik Mitraa
·
Feb. 03, 17 · Tutorial
Likes (80)
Comment
Save
Tweet
Share
154.7K Views

Join the DZone community and get the full member experience.

Join For Free

A unit of work transaction either succeeds or fails and rolls back. So suppose we are dealing with transferring money from one account to another. Now, say money from one account is already debited but when it gets credited to another account, there was an exception. Obviously, the ideal scenario would be for the debited action to roll back. Otherwise, we're dealing with an inconsistent state (and some very angry account owners).

So if we use transactions in our business logic, we can ensure the logic under the transaction works as a unit and that it will roll back if anything is found to be wrong.

Either the unit of work completely succeeds or completely fails. There is no intermediate state. Now the question comes, "How we can handle a transaction?"

There are two ways to handle it:

  • BMT: Bean Managed Transaction

  • CMT: Container Managed Transaction

BMT

If we need a finer control over business logic or want to introduce savepoints, this type of technique should be adopted, where a bean provider has a responsibility to start, commit, and roll back the transaction.

CMT

If we want to delegate the responsibility to a container, we use this instead. Sometimes we call it a declarative transaction. We all know in Spring that, using the @Transactional annotation, we can adopt a declarative transaction technique.

A Weird Case

We're not going to go into configuration in this article. Instead, I'm going to warn you about some precautions you want to take while using @Transactional. Study the pseudo code below:

@Transactional
public void transferMoney(Account to, Account from, int amount) throws Exception {
    debiFromAccount(from, amount)
    creditToAccount(to, amount);
}

public debitFromAccount(Account from, int amount) {
    //do staff and debited money from data base
}

public creditToAccount(Account to, int amount) throws Exception {
    //do straff
    throw new Exception("Error during credit");
}

Now do a dry run:

  1. If Account from's initial balance is 1000

  2. Account to is 500

  3. Transfer amount is 100

  4. Afterward, an error occurred in creditToAccount(Account to,int amount)

What will be the output you expect?

To: 500

From: 1000

After all, I use @Transactional. If there's an exception, it should be rolled back, right?

But unfortunately, it left an inconsistent state.

Our output is:

To: 500

From: 900

What's going on here?

Let me clear this up for you. @Transactional only rolls back transactions for unchecked exceptions. For checked exceptions and their subclasses, it commits data. So although an exception is raised here, because it's a checked exception, Spring ignores it and commits the data to the database, making the system inconsistent.

The Spring documentation says:

While the EJB default behavior is for the EJB container to automatically roll back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on an application exception (that is, a checked exception other than java.rmi.RemoteException). While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it is often useful to customize this.

Pay attention to the last line: “it is often useful to customize this.” So how can we customize it?

It's very simple, just use the following with @Transactional:

@Transactional(rollbackFor = Exception.class)

So if you throw an Exception or a subclass of it, always use the above with the @Transactional annotation to tell Spring to roll back transactions if a checked exception occurs.

Spring Framework

Published at DZone with permission of Shaamik Mitraa. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building a CRUD Application With Spring and SimpleJdbcMapper
  • How to Marry MDC With Spring Integration
  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook