Java分布式事务是指跨越多个独立的系统或进程的事务,它们共同参与一个全局的事务。在分布式系统中,每个系统都可能有自己的数据库和事务管理器,因此需要一种机制来确保所有系统在执行分布式事务时保持一致性。
Java分布式事务可以使用两种基本的模式:基于两阶段提交(Two-Phase Commit,2PC)协议和基于补偿事务(Compensating Transaction)机制。2PC是最常用的分布式事务协议,它通过协调器协调参与者的操作来实现全局事务的提交或回滚。
下面是一个基于2PC协议的Java分布式事务示例代码:
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
<version>2.6.2</version>
</dependency>
配置数据源和事务管理器
@Configuration
public class DataSourceConfig {
@Bean(name = "dataSource1")
@ConfigurationProperties(prefix = "spring.datasource.ds1")
public DataSource dataSource1() {
return new AtomikosDataSourceBean();
}
@Bean(name = "dataSource2")
@ConfigurationProperties(prefix = "spring.datasource.ds2")
public DataSource dataSource2() {
return new AtomikosDataSourceBean();
}
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(10000);
return userTransactionImp;
}
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
return userTransactionManager;
}
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() throws Throwable {
return new JtaTransactionManager(userTransaction(), atomikosTransactionManager());
}
}
在这个配置类中,我们使用了Atomikos实现了分布式事务管理器。我们配置了两个数据源dataSource1和dataSource2,它们使用不同的数据库。我们还配置了userTransaction和atomikosTransactionManager两个Bean,用于管理分布式事务。
编写业务逻辑代码
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
@Transactional(rollbackFor = Exception.class)
public void transfer(String fromUser, String toUser, int amount) throws Exception {
User user1 = userRepository.findByUsername(fromUser);
User user2 = userRepository.findByUsername(toUser);
if (user1.getBalance() < amount) {
throw new RuntimeException("Insufficient balance.");
}
user1.setBalance(user1.getBalance() - amount);
user2.setBalance(user2.getBalance() + amount);
userRepository.save(user1);
userRepository.save(user2);
}
}