Reputation: 77
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
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