多数据源事务不生效_SpringBoot+Atomikos多数据源分布式事务

环境:JDK8+2.2.11.RELEASE+Atomikos+JPA

  • pom.xml
1.8org.springframework.bootspring-boot-starter-webmysqlmysql-connector-javacom.alibabafastjson1.2.12com.github.pagehelperpagehelper5.2.0org.springframework.bootspring-boot-starter-data-jpaorg.springframework.bootspring-boot-starter-jta-atomikosorg.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-engineorg.springframework.bootspring-boot-configuration-processortrue
  • application.yml
server:  port: 9101---spring:  application:    name: atomikos---spring:  jta:    enabled: true  datasource:    account:      resourceName: accountResource      dsClassName: com.mysql.cj.jdbc.MysqlXADataSource      url: jdbc:mysql://localhost:3306/account?serverTimezone=GMT%2B8&useSSL=false      username: root      password: 123123    storage:      resourceName: storageResource      dsClassName: com.mysql.cj.jdbc.MysqlXADataSource      url: jdbc:mysql://localhost:3306/storage?serverTimezone=GMT%2B8&useSSL=false      username: root      password: 123123---spring:  jpa:    generateDdl: false    hibernate:      ddlAuto: update    openInView: true    show-sql: true    properties:      hibernate:        physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy        dialect: org.hibernate.dialect.MySQL5Dialect        transaction:          jta:            platform: com.pack.jpa.config.AtomikosJtaPlatform  #处理事务的类  hibernate不提供 需要自己写 需要继承 AbstractJtaPlatform[这里要注意 这里写的是这个类的全路径]      javax:        persistence:          transactionType: JTA  #指明事务处理类型---debug: false

这里如果不配置physical_naming_strategy

这里配置了两个数据源,account库和storage库

  • 数据源配置

数据源属性文件:

@Datapublic class BaseDataSourceProperties {private String resourceName ;private String dsClassName ;private String driver ;private String url ;private String username ;private String password ;}

Account库属性文件:

@Component@ConfigurationProperties(prefix = "spring.datasource.account")public class AccountDataSourceProperties extends BaseDataSourceProperties {}

Storage库属性文件:

@Component@ConfigurationProperties(prefix = "spring.datasource.storage")public class StorageDataSourceProperties extends BaseDataSourceProperties {}

数据源配置:

@Configurationpublic class DataSourceConfig {@Bean(name = "accountDataSource", initMethod = "init", destroyMethod = "close")@Primarypublic DataSource accountDataSource(AccountDataSourceProperties props) {AtomikosDataSourceBean ds = new AtomikosDataSourceBean() ;ds.setUniqueResourceName(props.getResourceName()) ;ds.setXaDataSourceClassName(props.getDsClassName()) ;Properties xaProperties = new Properties() ;xaProperties.setProperty("url", props.getUrl()) ;xaProperties.setProperty("user", props.getUsername()) ;xaProperties.setProperty("password", props.getPassword()) ;ds.setXaProperties(xaProperties) ;ds.setMinPoolSize(10) ;ds.setMaxPoolSize(10) ;ds.setBorrowConnectionTimeout(30) ;ds.setMaxLifetime(60) ;ds.setMaintenanceInterval(60) ;return ds ;}@Bean(name = "storageDataSource", initMethod = "init", destroyMethod = "close")public DataSource storageDataSource(StorageDataSourceProperties props) {AtomikosDataSourceBean ds = new AtomikosDataSourceBean() ;ds.setUniqueResourceName(props.getResourceName()) ;ds.setXaDataSourceClassName(props.getDsClassName()) ;Properties xaProperties = new Properties() ;xaProperties.setProperty("url", props.getUrl()) ;xaProperties.setProperty("user", props.getUsername()) ;xaProperties.setProperty("password", props.getPassword()) ;ds.setXaProperties(xaProperties) ;ds.setMinPoolSize(10) ;ds.setMaxPoolSize(10) ;ds.setBorrowConnectionTimeout(30) ;ds.setMaxLifetime(60) ;ds.setMaintenanceInterval(60) ;return ds ;}}
  • JPA配置
public class EntityManagerFactoryConfig {@Configuration@EnableJpaRepositories(basePackages = {"com.pack.account.repository"}, entityManagerFactoryRef = "accountEntityManagerFactory",transactionManagerRef = "transactionManager")@DependsOn("transactionManager")static class AccountEntityManagerFactory {@Resource(name = "accountDataSource")private DataSource accountDataSource;@Resourceprivate JpaProperties props ;private String accountDomainPkg = "com.pack.account.domain";@Bean@Primarypublic LocalContainerEntityManagerFactoryBean accountEntityManagerFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(accountDataSource).packages(accountDomainPkg).persistenceUnit("account").properties(props.getProperties()).build();}}@Configuration@EnableJpaRepositories(basePackages = {"com.pack.storage.repository"}, entityManagerFactoryRef = "storageEntityManagerFactory",transactionManagerRef = "transactionManager")@DependsOn("transactionManager")static class StorageEntityManagerFactory {@Resource(name = "storageDataSource")private DataSource storageDataSource ;@Resourceprivate JpaProperties props ;private String storageDomainPkg = "com.pack.storage.domain" ;@Beanpublic LocalContainerEntityManagerFactoryBean storageEntityManagerFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(storageDataSource).packages(storageDomainPkg).persistenceUnit("storage").properties(props.getProperties()).build();}}}

事务配置:

public class AtomikosJtaPlatform extends AbstractJtaPlatform {private static final long serialVersionUID = 1L;public static TransactionManager transactionManager;public static UserTransaction transaction;@Overrideprotected TransactionManager locateTransactionManager() {return transactionManager;}@Overrideprotected UserTransaction locateUserTransaction() {return transaction;}}
@Configurationpublic class TxConfig {@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")@DependsOn({ "userTransaction", "atomikosTransactionManager" })public PlatformTransactionManager transactionManager() throws Throwable {UserTransaction userTransaction = userTransaction();TransactionManager atomikosTransactionManager = atomikosTransactionManager();return new JtaTransactionManager(userTransaction, atomikosTransactionManager);}}

注意AtomikosJtaPlatform类就是我们的事务处理类,对应如下的配置:

3037513b69f456580314649bbfc17734.png
  • 实体类
@Entity@Table(name = "t_account")public class Account {    @Id    private Long id;    private String userId;    private BigDecimal money;}
@Entity@Table(name = "t_storage")public class Storage {    @Id    private Long id;    private String commodityCode;    private Integer count;}
  • DAO及Service
public interface AccountRepository extends JpaRepository, JpaSpecificationExecutor {}
public interface StorageRepository extends JpaRepository, JpaSpecificationExecutor {}
@Servicepublic class AccountService {@Resourceprivate AccountRepository accountRepository ; @Transactionalpublic void saveAccount(Account account) {accountRepository.save(account) ;}}
@Servicepublic class StorageService {@Resourceprivate StorageRepository storageRepository ;@Transactionalpublic void saveStorage(Storage storage) {storageRepository.save(storage) ;}}
@Servicepublic class OperatorService {@Resourceprivate AccountService accountService ;@Resourceprivate StorageService storageService ;@Transactionalpublic void save(Account account, Storage storage) {accountService.saveAccount(account) ;if (storage.getCount() == 0) {throw new RuntimeException("库存数量错误0") ;}storageService.saveStorage(storage) ;if (storage.getCount() == -1) {throw new RuntimeException("库存数量错误-1") ;}}}

OperatorService分别调用两个服务类。这里的@Transactional 必须有,如果没有即便是该方法抛出了异常也能数据保存成功。

测试:

@RestController@RequestMapping("/oc")public class OperatorController {@Resourceprivate OperatorService os ;@PostMapping("/save")public Object save(@RequestBody OperatorDTO dto) {os.save(dto.getAccount(), dto.getStorage()) ;return "1" ;}}

成功示例:

3c496d8c64a7c446108ef859ae6a167b.png
21d3c280684c929bd0942aefdda03596.png

失败示例:

将count设置为0,或者-1

66b63f81bc7af220a98594f59534a4df.png
2975300d0cf9baccecb4d122eeaa693a.png

数据都没有成功地插入到数据库。

完毕!!!

Java分布式事务介绍及实现Atomikos

分布式事务框架Seata之AT模式

9dd379f422cc34f8c5ac319be6389f91.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值