Dummy Me
Dummy Me

Reputation: 77

Spring @Transactional behaviour with only one transactional data source

I have an app that accesses two databases. Obviously, if I need to have a transaction span both DBs, I need to use something like two phase commit. But I don't need this king of guarantee right now, I don't need everything to be transactional. Things can crash or succeed independently, the app can handle it and not end-up in an inconsistent state.

Right now I have a setup like this one (removed interfaces, code, etc to make it as simple as possible to explain):

Two data sources:

<bean id="firstDS" class="org.springframework.jndi.JndiObjectFactoryBean">
    <qualifier value="firstDS" />
    <property name="jndiName" value="java:comp/env/jdbc/firstDS" />
</bean>

<bean id="secondDS" class="org.springframework.jndi.JndiObjectFactoryBean">
    <qualifier value="secondDS" />
    <property name="jndiName" value="java:comp/env/jdbc/secondDS" />
</bean>

One transaction manager for only one of the data sources:

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="firstDS" />
</bean>

A service:

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class Service {

    @Autowired
    private FirstDao firstDao;

    @Autowired
    private SecondDao secondDao;

    public void updateStuff() {
        firstDao.updateStuff();
        secondDao.updateStuff();
    }
}

and two DAOs:

@Transactional(propagation = Propagation.MANDATORY)
public class FirstDao {

    @Autowired
    @Qualifier("firstDS")
    private DataSource dataSource;

    public void updateStuff() {
        // updates stuff in the first database using dataSource
    }
}

@Transactional(propagation = Propagation.MANDATORY)
public class SecondDao {

    @Autowired
    @Qualifier("secondDS")
    private DataSource dataSource;

    public void updateStuff() {
        // updates stuff in the second database using dataSource
    }
}

Now, this runs without problems (or at least none that I could observe) but my questions are:

I've read the reference and various posts online but I still am not sure about the behavior.

Upvotes: 2

Views: 894

Answers (1)

ben75
ben75

Reputation: 28746

Is it safe ?

No. SecondDao.updateStuff will be executed without logical transaction. It means that every single query executed during SecondDao.updateStuff will be executed in a separate physical transaction in auto-commit mode. In other words : SecondDao.updateStuff is not transactional (and may even use one separate connection for every query... which can lead to performance problems).

What can you do ?

First declare a transactionManager for your secondDS :

<tx:annotation-driven/>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="firstDS" />
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="secondDS" />
</bean>

Then specify that SecondDAO use transactionManger2 :

@Transactional(value="transactionManager2",propagation = Propagation.REQUIRED)
public class SecondDao {

    @Autowired
    @Qualifier("secondDS")
    private DataSource dataSource;

    public void updateStuff() {
        // updates stuff in the second database using dataSource
    }
}

Upvotes: 1

Related Questions