From 7d68aaa0f7447c825d5d3ca2825c8a135a1965fe Mon Sep 17 00:00:00 2001 From: Zhengjiaao Date: Mon, 28 Nov 2022 13:05:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(root)=20=E6=96=B0=E5=A2=9E=20starter-jta-a?= =?UTF-8?q?tomikos=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 + starter-jta-atomikos/README.md | 276 ++++++++++++++++++ starter-jta-atomikos/pom.xml | 72 +++++ .../com/zja/jta/JtaAtomikosApplication.java | 21 ++ .../config/JtaTransactionManagerConfig.java | 37 +++ .../jta/config/PrimaryDataSourceConfig.java | 103 +++++++ .../jta/config/SecondaryDataSourceConfig.java | 97 ++++++ .../com/zja/jta/primary/PrimaryService.java | 42 +++ .../zja/jta/primary/entity/PrimaryEntity.java | 29 ++ .../primary/repository/PrimaryRepository.java | 27 ++ .../zja/jta/secondary/SecondaryService.java | 42 +++ .../jta/secondary/entity/SecondaryEntity.java | 26 ++ .../repository/SecondaryRepository.java | 27 ++ .../java/com/zja/jta/service/JtaService.java | 60 ++++ .../src/main/resources/application.yaml | 38 +++ .../zja/jta/JtaAtomikosApplicationTests.java | 34 +++ .../zja/jta/PrimaryEntityServiceTests.java | 34 +++ .../zja/jta/SecondaryEntityServiceTests.java | 34 +++ starter-validation/README.md | 12 +- .../main/resources/templates/stomp-v1.html | 2 +- .../main/resources/templates/stomp-v2.html | 2 +- .../resources/templates/stomp/stomp-v1.html | 2 +- .../static/stompwebsocket/test-stomp.html | 2 +- .../static/stompwebsocket/websocket.jsp | 2 +- .../resources/templates/stomp/stomp-v1.html | 2 +- 25 files changed, 1014 insertions(+), 12 deletions(-) create mode 100644 starter-jta-atomikos/README.md create mode 100644 starter-jta-atomikos/pom.xml create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/JtaAtomikosApplication.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/config/JtaTransactionManagerConfig.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/config/PrimaryDataSourceConfig.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/config/SecondaryDataSourceConfig.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/primary/PrimaryService.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/primary/entity/PrimaryEntity.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/primary/repository/PrimaryRepository.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/secondary/SecondaryService.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/secondary/entity/SecondaryEntity.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/secondary/repository/SecondaryRepository.java create mode 100644 starter-jta-atomikos/src/main/java/com/zja/jta/service/JtaService.java create mode 100644 starter-jta-atomikos/src/main/resources/application.yaml create mode 100644 starter-jta-atomikos/src/test/java/com/zja/jta/JtaAtomikosApplicationTests.java create mode 100644 starter-jta-atomikos/src/test/java/com/zja/jta/PrimaryEntityServiceTests.java create mode 100644 starter-jta-atomikos/src/test/java/com/zja/jta/SecondaryEntityServiceTests.java diff --git a/pom.xml b/pom.xml index 51c2d31..5a20ed2 100644 --- a/pom.xml +++ b/pom.xml @@ -17,10 +17,13 @@ starter-actuator starter-aop + starter-batch starter-cache starter-data + starter-dubbo starter-freemarker starter-jdbc + starter-jta-atomikos starter-mail starter-quartz diff --git a/starter-jta-atomikos/README.md b/starter-jta-atomikos/README.md new file mode 100644 index 0000000..57e98ff --- /dev/null +++ b/starter-jta-atomikos/README.md @@ -0,0 +1,276 @@ +# starter-jta-atomikos + +**多数据源+jta分布式事务管理** + +## 依赖引入 + +```xml + + org.springframework.boot + spring-boot-starter-jta-atomikos + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + 8.0.29 + runtime + + + org.postgresql + postgresql + 42.3.4 + +``` + +## 配置 jta-atomikos + +JtaTransactionManagerConfig.java + +```java +/** + * 统一事务管理 + */ +@Configuration +public class JtaTransactionManagerConfig { + /** + * 配置spring的JtaTransactionManager,底层委派给atomikos进行处理 + */ + @Primary + @Bean(name = "jtaTransactionManager") + public JtaTransactionManager jtaTransactionManager() { + UserTransactionManager userTransactionManager = new UserTransactionManager(); + UserTransaction userTransaction = new UserTransactionImp(); + return new JtaTransactionManager(userTransaction, userTransactionManager); + } +} +``` + +## 配置jpa多数据源 + +### jpa数据源一 + +```java +/** + * 配置JPA的数据持久层,需要配置如下内容: + * + * DataSource + * EntityManager + * EntityManagerFactoryBean + * PlatformTransactionManager + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + entityManagerFactoryRef = "primaryEntityManagerFactory", + transactionManagerRef = "primaryTransactionManager", + basePackages = PrimaryDataSourceConfig.REPOSITORY_PACKAGE) +public class PrimaryDataSourceConfig { + + static final String REPOSITORY_PACKAGE = "com.zja.jta.primary.repository"; + private static final String ENTITY_PACKAGE = "com.zja.jta.primary.entity"; + + @Primary + @Bean(name = "primaryDataSource") + @ConfigurationProperties(prefix = "spring.datasource.primary") + public DataSource dataSource() { + return DataSourceBuilder.create().build(); + } + + @Primary + @Bean(name = "primaryJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.primary") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + /** + * 实体管理工厂对象 + * + * 将数据源、连接池、以及其他配置策略进行封装返回给事务管理器 + * 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 + */ + @Primary + @Bean(name = "primaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("primaryDataSource") DataSource dataSource, + @Qualifier("primaryJpaProperties") JpaProperties jpaProperties, + EntityManagerFactoryBuilder builder) { + return builder + // 设置数据源 + .dataSource(dataSource) + // 设置jpa配置 + .properties(jpaProperties.getProperties()) + //设置实体类所在位置:类或包 entity + .packages(ENTITY_PACKAGE) + //持久化单元名称 用于@PersistenceContext注解获取EntityManager时指定数据源 + .persistenceUnit("primaryPersistenceUnit") + .build(); + } + + /** + * 实体对象管理器 + */ + @Primary + @Bean(name = "primaryEntityManager") + public EntityManager entityManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + /** + * 数据源的事务管理器 + */ + @Primary + @Bean(name = "primaryTransactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} + +``` + +### jpa数据源二 + +```java +/** + * 配置JPA的数据持久层,需要配置如下内容: + * + * DataSource + * EntityManager + * EntityManagerFactoryBean + * PlatformTransactionManager + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + entityManagerFactoryRef = "secondaryEntityManagerFactory", + transactionManagerRef = "secondaryTransactionManager", + basePackages = SecondaryDataSourceConfig.REPOSITORY_PACKAGE) +public class SecondaryDataSourceConfig { + + static final String REPOSITORY_PACKAGE = "com.zja.jta.secondary.repository"; + private static final String ENTITY_PACKAGE = "com.zja.jta.secondary.entity"; + + @Bean(name = "secondaryDataSource") + @ConfigurationProperties(prefix = "spring.datasource.secondary") + public DataSource dataSource() { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "secondaryJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.secondary") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + /** + * 实体管理工厂对象 + * + * 将数据源、连接池、以及其他配置策略进行封装返回给事务管理器 + * 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 + */ + @Bean(name = "secondaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("secondaryDataSource") DataSource dataSource, + @Qualifier("secondaryJpaProperties") JpaProperties jpaProperties, + EntityManagerFactoryBuilder builder) { + return builder + // 设置数据源 + .dataSource(dataSource) + // 设置jpa配置 + .properties(jpaProperties.getProperties()) + //设置实体类所在位置:类或包 entity + .packages(ENTITY_PACKAGE) + //持久化单元名称 用于@PersistenceContext注解获取EntityManager时指定数据源 + .persistenceUnit("secondaryPersistenceUnit") + .build(); + } + + /** + * 实体对象管理器 + */ + @Bean(name = "secondaryEntityManager") + public EntityManager entityManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + /** + * 数据源的事务管理器 + */ + @Bean(name = "secondaryTransactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} +``` + +## yml 配置参考 + +```yaml +spring: + main: + allow-bean-definition-overriding: true + datasource: + primary: + jdbc-url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC #&rewriteBatchedStatements=true + username: test + password: pass + driver-class-name: com.mysql.cj.jdbc.Driver + secondary: + jdbc-url: jdbc:postgresql://localhost:5433/test + username: test + password: pass + driver-class-name: org.postgresql.Driver + jpa: + primary: + show-sql: true + properties: + hibernate: + hbm2ddl: + auto: update + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + secondary: + show-sql: true + properties: + hibernate: + hbm2ddl: + auto: update + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + +``` + +## 测试示例 + +```java +@Service +public class JtaService { + + //无注解时 抛异常,全部存储 +// @Transactional(rollbackFor = Exception.class) //使用jta-atomikos时,抛异常,全部不会存储;不使用jta-atomikos时,抛异常,user不会存储,goods会存储; +// @Transactional(value = "primaryTransactionManager", rollbackFor = Exception.class) //抛异常,user不会存储,goods会存储 +// @Transactional(value = "secondaryTransactionManager", rollbackFor = Exception.class) //抛异常,user会存储,goods不会存储 +// @Transactional(value = "jtaTransactionManager", rollbackFor = Exception.class) //抛异常,全部存储 + public void add_rollback_example() { + + PrimaryEntity primaryEntity = new PrimaryEntity(); + primaryEntity.setName("数据源1-实体类"); + primaryEntity.setCreateTime(new Date()); + primaryRepository.save(primaryEntity); + + SecondaryEntity secondaryEntity = new SecondaryEntity(); + secondaryEntity.setName("数据源2-实体类"); + secondaryEntity.setCreateTime(new Date()); + secondaryRepository.save(secondaryEntity); + + //故意抛出异常测试 + int i = 10 / 0; + } + +} +``` diff --git a/starter-jta-atomikos/pom.xml b/starter-jta-atomikos/pom.xml new file mode 100644 index 0000000..fe47771 --- /dev/null +++ b/starter-jta-atomikos/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + com.zja + spring-boot-starter-test-root + 2.0-SNAPSHOT + + + com.zja + starter-jta-atomikos + jar + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + + + org.springframework.boot + spring-boot-starter-test + test + + + junit + junit + test + + + org.projectlombok + lombok + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + 8.0.29 + runtime + + + org.postgresql + postgresql + 42.3.4 + + + com.oracle + ojdbc6 + 11.2.0.3 + + + com.alibaba + druid + 1.2.9 + + + + org.springframework.boot + spring-boot-starter-jta-atomikos + + + + diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/JtaAtomikosApplication.java b/starter-jta-atomikos/src/main/java/com/zja/jta/JtaAtomikosApplication.java new file mode 100644 index 0000000..1e5b0c7 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/JtaAtomikosApplication.java @@ -0,0 +1,21 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-07-27 11:09 + * @Since: + */ +package com.zja.jta; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class JtaAtomikosApplication { + + public static void main(String[] args) { + SpringApplication.run(JtaAtomikosApplication.class, args); + } + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/config/JtaTransactionManagerConfig.java b/starter-jta-atomikos/src/main/java/com/zja/jta/config/JtaTransactionManagerConfig.java new file mode 100644 index 0000000..0f388f0 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/config/JtaTransactionManagerConfig.java @@ -0,0 +1,37 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-02-14 11:12 + * @Since: + */ +package com.zja.jta.config; + +import com.atomikos.icatch.jta.UserTransactionImp; +import com.atomikos.icatch.jta.UserTransactionManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.transaction.jta.JtaTransactionManager; + +import javax.transaction.UserTransaction; + +/** + * 统一事务管理 + */ +@Configuration +public class JtaTransactionManagerConfig { + + /** + * 配置spring的JtaTransactionManager,底层委派给atomikos进行处理 + */ + @Primary + @Bean(name = "jtaTransactionManager") + public JtaTransactionManager jtaTransactionManager() { + UserTransactionManager userTransactionManager = new UserTransactionManager(); + UserTransaction userTransaction = new UserTransactionImp(); + return new JtaTransactionManager(userTransaction, userTransactionManager); + } + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/config/PrimaryDataSourceConfig.java b/starter-jta-atomikos/src/main/java/com/zja/jta/config/PrimaryDataSourceConfig.java new file mode 100644 index 0000000..ea0de3c --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/config/PrimaryDataSourceConfig.java @@ -0,0 +1,103 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:05 + * @Since: + */ +package com.zja.jta.config; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +/** + * 配置JPA的数据持久层,需要配置如下内容: + * + * DataSource + * EntityManager + * EntityManagerFactoryBean + * PlatformTransactionManager + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + entityManagerFactoryRef = "primaryEntityManagerFactory", + transactionManagerRef = "primaryTransactionManager", + basePackages = PrimaryDataSourceConfig.REPOSITORY_PACKAGE) +public class PrimaryDataSourceConfig { + + static final String REPOSITORY_PACKAGE = "com.zja.jta.primary.repository"; + private static final String ENTITY_PACKAGE = "com.zja.jta.primary.entity"; + + @Primary + @Bean(name = "primaryDataSource") + @ConfigurationProperties(prefix = "spring.datasource.primary") + public DataSource dataSource() { + return DataSourceBuilder.create().build(); + } + + @Primary + @Bean(name = "primaryJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.primary") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + /** + * 实体管理工厂对象 + * + * 将数据源、连接池、以及其他配置策略进行封装返回给事务管理器 + * 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 + */ + @Primary + @Bean(name = "primaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("primaryDataSource") DataSource dataSource, + @Qualifier("primaryJpaProperties") JpaProperties jpaProperties, + EntityManagerFactoryBuilder builder) { + return builder + // 设置数据源 + .dataSource(dataSource) + // 设置jpa配置 + .properties(jpaProperties.getProperties()) + //设置实体类所在位置:类或包 entity + .packages(ENTITY_PACKAGE) + //持久化单元名称 用于@PersistenceContext注解获取EntityManager时指定数据源 + .persistenceUnit("primaryPersistenceUnit") + .build(); + } + + /** + * 实体对象管理器 + */ + @Primary + @Bean(name = "primaryEntityManager") + public EntityManager entityManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + /** + * 数据源的事务管理器 + */ + @Primary + @Bean(name = "primaryTransactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("primaryEntityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/config/SecondaryDataSourceConfig.java b/starter-jta-atomikos/src/main/java/com/zja/jta/config/SecondaryDataSourceConfig.java new file mode 100644 index 0000000..587814e --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/config/SecondaryDataSourceConfig.java @@ -0,0 +1,97 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 15:00 + * @Since: + */ +package com.zja.jta.config; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +/** + * 配置JPA的数据持久层,需要配置如下内容: + * + * DataSource + * EntityManager + * EntityManagerFactoryBean + * PlatformTransactionManager + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + entityManagerFactoryRef = "secondaryEntityManagerFactory", + transactionManagerRef = "secondaryTransactionManager", + basePackages = SecondaryDataSourceConfig.REPOSITORY_PACKAGE) +public class SecondaryDataSourceConfig { + + static final String REPOSITORY_PACKAGE = "com.zja.jta.secondary.repository"; + private static final String ENTITY_PACKAGE = "com.zja.jta.secondary.entity"; + + @Bean(name = "secondaryDataSource") + @ConfigurationProperties(prefix = "spring.datasource.secondary") + public DataSource dataSource() { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "secondaryJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.secondary") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + /** + * 实体管理工厂对象 + * + * 将数据源、连接池、以及其他配置策略进行封装返回给事务管理器 + * 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 + */ + @Bean(name = "secondaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("secondaryDataSource") DataSource dataSource, + @Qualifier("secondaryJpaProperties") JpaProperties jpaProperties, + EntityManagerFactoryBuilder builder) { + return builder + // 设置数据源 + .dataSource(dataSource) + // 设置jpa配置 + .properties(jpaProperties.getProperties()) + //设置实体类所在位置:类或包 entity + .packages(ENTITY_PACKAGE) + //持久化单元名称 用于@PersistenceContext注解获取EntityManager时指定数据源 + .persistenceUnit("secondaryPersistenceUnit") + .build(); + } + + /** + * 实体对象管理器 + */ + @Bean(name = "secondaryEntityManager") + public EntityManager entityManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + /** + * 数据源的事务管理器 + */ + @Bean(name = "secondaryTransactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/primary/PrimaryService.java b/starter-jta-atomikos/src/main/java/com/zja/jta/primary/PrimaryService.java new file mode 100644 index 0000000..529fbf2 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/primary/PrimaryService.java @@ -0,0 +1,42 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:26 + * @Since: + */ +package com.zja.jta.primary; + +import com.zja.jta.primary.entity.PrimaryEntity; +import com.zja.jta.primary.repository.PrimaryRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PrimaryService { + + @Autowired + PrimaryRepository primaryRepository; + + public void add_example() { + PrimaryEntity primaryEntity = new PrimaryEntity(); + primaryEntity.setName("数据源1-实体类"); + primaryRepository.save(primaryEntity); + } + + //无注解时 抛异常,会存储 +// @Transactional(rollbackFor = Exception.class) //抛异常,不会存储 +// @Transactional(value = "primaryTransactionManager", rollbackFor = Exception.class) //抛异常,不会存储 +// @Transactional(value = "secondaryTransactionManager", rollbackFor = Exception.class) //抛异常,会存储 +// @Transactional(value = "jtaTransactionManager", rollbackFor = Exception.class) //抛异常,会存储 + public void add_rollback_example() { + PrimaryEntity primaryEntity = new PrimaryEntity(); + primaryEntity.setName("数据源1-实体类"); + primaryRepository.save(primaryEntity); + + //故意抛出异常测试 + int i = 10 / 0; + } + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/primary/entity/PrimaryEntity.java b/starter-jta-atomikos/src/main/java/com/zja/jta/primary/entity/PrimaryEntity.java new file mode 100644 index 0000000..3c326e6 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/primary/entity/PrimaryEntity.java @@ -0,0 +1,29 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-02-14 11:03 + * @Since: + */ +package com.zja.jta.primary.entity; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Data +@Entity +@Table(name = "primary_entity") +public class PrimaryEntity { + + @Id + @GeneratedValue + private Long id; + private String name; + private Date createTime; +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/primary/repository/PrimaryRepository.java b/starter-jta-atomikos/src/main/java/com/zja/jta/primary/repository/PrimaryRepository.java new file mode 100644 index 0000000..8637048 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/primary/repository/PrimaryRepository.java @@ -0,0 +1,27 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-02-14 11:04 + * @Since: + */ +package com.zja.jta.primary.repository; + +import com.zja.jta.primary.entity.PrimaryEntity; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +/** + * 用法参考:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#preface + * + * Repository + * CrudRepository 常用的 + * PagingAndSortingRepository 分页、排序 + * JpaRepository 常用的 + * QuerydslPredicateExecutor 扩展,可选的 + */ +//@Repository +public interface PrimaryRepository extends CrudRepository, PagingAndSortingRepository { + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/SecondaryService.java b/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/SecondaryService.java new file mode 100644 index 0000000..9f455ce --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/SecondaryService.java @@ -0,0 +1,42 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:26 + * @Since: + */ +package com.zja.jta.secondary; + +import com.zja.jta.secondary.entity.SecondaryEntity; +import com.zja.jta.secondary.repository.SecondaryRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SecondaryService { + + @Autowired + SecondaryRepository secondaryRepository; + + public void add_example() { + SecondaryEntity secondaryEntity = new SecondaryEntity(); + secondaryEntity.setName("数据源2-实体类"); + secondaryRepository.save(secondaryEntity); + } + + //无注解时 抛异常,会存储 +// @Transactional(rollbackFor = Exception.class) //抛异常,不会存储 +// @Transactional(value = "primaryTransactionManager", rollbackFor = Exception.class) //抛异常,会存储 +// @Transactional(value = "secondaryTransactionManager", rollbackFor = Exception.class) //抛异常,不会存储 +// @Transactional(value = "jtaTransactionManager", rollbackFor = Exception.class) //抛异常,会存储 + public void add_rollback_example() { + SecondaryEntity secondaryEntity = new SecondaryEntity(); + secondaryEntity.setName("数据源2-实体类"); + secondaryRepository.save(secondaryEntity); + + //故意抛出异常测试 + int i = 10 / 0; + } + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/entity/SecondaryEntity.java b/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/entity/SecondaryEntity.java new file mode 100644 index 0000000..18bfe89 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/entity/SecondaryEntity.java @@ -0,0 +1,26 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 15:58 + * @Since: + */ +package com.zja.jta.secondary.entity; + +import lombok.Data; + +import javax.persistence.*; +import java.util.Date; + +@Data +@Entity +@Table(name = "secondary_entity") +public class SecondaryEntity { + + @Id + @GeneratedValue + private Long id; + private String name; + private Date createTime; +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/repository/SecondaryRepository.java b/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/repository/SecondaryRepository.java new file mode 100644 index 0000000..32e1529 --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/secondary/repository/SecondaryRepository.java @@ -0,0 +1,27 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-02-14 11:04 + * @Since: + */ +package com.zja.jta.secondary.repository; + +import com.zja.jta.secondary.entity.SecondaryEntity; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +/** + * 用法参考:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#preface + * + * Repository + * CrudRepository 常用的 + * PagingAndSortingRepository 分页、排序 + * JpaRepository 常用的 + * QuerydslPredicateExecutor 扩展,可选的 + */ +//@Repository +public interface SecondaryRepository extends CrudRepository, PagingAndSortingRepository { + +} diff --git a/starter-jta-atomikos/src/main/java/com/zja/jta/service/JtaService.java b/starter-jta-atomikos/src/main/java/com/zja/jta/service/JtaService.java new file mode 100644 index 0000000..5c8452e --- /dev/null +++ b/starter-jta-atomikos/src/main/java/com/zja/jta/service/JtaService.java @@ -0,0 +1,60 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:01 + * @Since: + */ +package com.zja.jta.service; + +import com.zja.jta.primary.entity.PrimaryEntity; +import com.zja.jta.primary.repository.PrimaryRepository; +import com.zja.jta.secondary.entity.SecondaryEntity; +import com.zja.jta.secondary.repository.SecondaryRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; + +@Service +public class JtaService { + + @Autowired + PrimaryRepository primaryRepository; + + @Autowired + SecondaryRepository secondaryRepository; + + public void add_example() { + PrimaryEntity primaryEntity = new PrimaryEntity(); + primaryEntity.setName("数据源1-实体类"); + primaryRepository.save(primaryEntity); + + SecondaryEntity secondaryEntity = new SecondaryEntity(); + secondaryEntity.setName("数据源2-实体类"); + secondaryRepository.save(secondaryEntity); + } + + //无注解时 抛异常,全部存储 +// @Transactional(rollbackFor = Exception.class) //使用jta-atomikos时,抛异常,全部不会存储;不使用jta-atomikos时,抛异常,user不会存储,goods会存储; +// @Transactional(value = "primaryTransactionManager", rollbackFor = Exception.class) //抛异常,user不会存储,goods会存储 +// @Transactional(value = "secondaryTransactionManager", rollbackFor = Exception.class) //抛异常,user会存储,goods不会存储 +// @Transactional(value = "jtaTransactionManager", rollbackFor = Exception.class) //抛异常,全部存储 + public void add_rollback_example() { + + PrimaryEntity primaryEntity = new PrimaryEntity(); + primaryEntity.setName("数据源1-实体类"); + primaryEntity.setCreateTime(new Date()); + primaryRepository.save(primaryEntity); + + SecondaryEntity secondaryEntity = new SecondaryEntity(); + secondaryEntity.setName("数据源2-实体类"); + secondaryEntity.setCreateTime(new Date()); + secondaryRepository.save(secondaryEntity); + + //故意抛出异常测试 + int i = 10 / 0; + } + +} diff --git a/starter-jta-atomikos/src/main/resources/application.yaml b/starter-jta-atomikos/src/main/resources/application.yaml new file mode 100644 index 0000000..c2ea9d2 --- /dev/null +++ b/starter-jta-atomikos/src/main/resources/application.yaml @@ -0,0 +1,38 @@ +spring: + main: + allow-bean-definition-overriding: true + datasource: + primary: + jdbc-url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC #&rewriteBatchedStatements=true + username: test + password: pass + driver-class-name: com.mysql.cj.jdbc.Driver + secondary: + jdbc-url: jdbc:postgresql://localhost:5433/test + username: test + password: pass + driver-class-name: org.postgresql.Driver + jpa: +# show-sql: true # 控制台打印sql +# hibernate: +# ddl-auto: update # update会导致启动至 org.hibernate.dialect.Dialect 时卡住 +# naming: +# # physical-strategy: 物理策略 把[属性名] 映射为 [表字段],默认 将实体类的属性名映射表中策略是:userName --> user_name +# # physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy # 默认,Spring 物理命名策略,示例: userName --> user_name,@Column(name = "LICENSENUMBER") --> licensenumber name变为小写 +# physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl # 驼峰命名策略,示例: userName --> userName,@Column(name = "LICENSENUMBER") --> LICENSENUMBER name变为大写 + primary: + show-sql: true + properties: + hibernate: + hbm2ddl: + auto: update + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + secondary: + show-sql: true + properties: + hibernate: + hbm2ddl: + auto: update + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl diff --git a/starter-jta-atomikos/src/test/java/com/zja/jta/JtaAtomikosApplicationTests.java b/starter-jta-atomikos/src/test/java/com/zja/jta/JtaAtomikosApplicationTests.java new file mode 100644 index 0000000..9228e8e --- /dev/null +++ b/starter-jta-atomikos/src/test/java/com/zja/jta/JtaAtomikosApplicationTests.java @@ -0,0 +1,34 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:32 + * @Since: + */ +package com.zja.jta; + +import com.zja.jta.service.JtaService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; + +@SpringBootTest +public class JtaAtomikosApplicationTests { + + @Resource + JtaService jtaService; + + //正常录入数据 + @Test + public void add_example_test() { + jtaService.add_example(); + } + + //异常测试回滚 + @Test + public void add_rollback_example_test() { + jtaService.add_rollback_example(); + } +} diff --git a/starter-jta-atomikos/src/test/java/com/zja/jta/PrimaryEntityServiceTests.java b/starter-jta-atomikos/src/test/java/com/zja/jta/PrimaryEntityServiceTests.java new file mode 100644 index 0000000..4a85422 --- /dev/null +++ b/starter-jta-atomikos/src/test/java/com/zja/jta/PrimaryEntityServiceTests.java @@ -0,0 +1,34 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:34 + * @Since: + */ +package com.zja.jta; + +import com.zja.jta.primary.PrimaryService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; + +@SpringBootTest +public class PrimaryEntityServiceTests { + + @Resource + PrimaryService primaryService; + + //正常录入数据 + @Test + public void add_example_test() { + primaryService.add_example(); + } + + //异常测试回滚 + @Test + public void add_rollback_example_test() { + primaryService.add_rollback_example(); + } +} diff --git a/starter-jta-atomikos/src/test/java/com/zja/jta/SecondaryEntityServiceTests.java b/starter-jta-atomikos/src/test/java/com/zja/jta/SecondaryEntityServiceTests.java new file mode 100644 index 0000000..e08c4bc --- /dev/null +++ b/starter-jta-atomikos/src/test/java/com/zja/jta/SecondaryEntityServiceTests.java @@ -0,0 +1,34 @@ +/** + * @Company: 上海数慧系统技术有限公司 + * @Department: 数据中心 + * @Author: 郑家骜[ào] + * @Email: zhengja@dist.com.cn + * @Date: 2022-11-25 16:35 + * @Since: + */ +package com.zja.jta; + +import com.zja.jta.secondary.SecondaryService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.annotation.Resource; + +@SpringBootTest +public class SecondaryEntityServiceTests { + + @Resource + SecondaryService secondaryService; + + //正常录入数据 + @Test + public void add_example_test() { + secondaryService.add_example(); + } + + //异常测试回滚 + @Test + public void add_rollback_example_test() { + secondaryService.add_rollback_example(); + } +} diff --git a/starter-validation/README.md b/starter-validation/README.md index a635d98..7776a85 100644 --- a/starter-validation/README.md +++ b/starter-validation/README.md @@ -100,7 +100,7 @@ private Product product; @PostMapping(value = "create") @ResponseBody -public R createUserForm(@Valid User user,BindingResult bindingResult){ +public R createUserForm(@Valid User primaryEntity,BindingResult bindingResult){ if(bindingResult.hasErrors()){ //获取错误信息,返回json return R.error("请求失败,请重试!"); @@ -112,15 +112,15 @@ public R createUserForm(@Valid User user,BindingResult bindingResult){
- +
- +
- +
- -
\ No newline at end of file + + diff --git a/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v1.html b/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v1.html index 9d45c70..b36e213 100644 --- a/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v1.html +++ b/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v1.html @@ -73,7 +73,7 @@ // subscribe.unsubscribe(); //订阅消息 另外再注册一下定时任务接受 - stompClient.subscribe('/user/123/msg', function (response) { + stompClient.subscribe('/primaryEntity/123/msg', function (response) { showCallback(response.body); }); diff --git a/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v2.html b/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v2.html index 9d45c70..b36e213 100644 --- a/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v2.html +++ b/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp-v2.html @@ -73,7 +73,7 @@ // subscribe.unsubscribe(); //订阅消息 另外再注册一下定时任务接受 - stompClient.subscribe('/user/123/msg', function (response) { + stompClient.subscribe('/primaryEntity/123/msg', function (response) { showCallback(response.body); }); diff --git a/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp/stomp-v1.html b/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp/stomp-v1.html index c60b287..4b0cf27 100644 --- a/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp/stomp-v1.html +++ b/starter-websocket/starter-websocket-stomp/src/main/resources/templates/stomp/stomp-v1.html @@ -44,7 +44,7 @@ showResponse(JSON.parse(response.body).responseMessage); }); // 另外再注册一下定时任务接受 - stompClient.subscribe('/user/123/msg', function (response) { + stompClient.subscribe('/primaryEntity/123/msg', function (response) { showCallback(response.body); }); }); diff --git a/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/test-stomp.html b/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/test-stomp.html index 3fa4a39..97cd96d 100644 --- a/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/test-stomp.html +++ b/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/test-stomp.html @@ -48,7 +48,7 @@ showResponse(JSON.parse(response.body).responseMessage); }); // 另外再注册一下定时任务接受 - stompClient.subscribe('/user/123/msg', function (response) { + stompClient.subscribe('/primaryEntity/123/msg', function (response) { showCallback(response.body); }); }); diff --git a/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/websocket.jsp b/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/websocket.jsp index 7269442..a9157d0 100644 --- a/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/websocket.jsp +++ b/starter-websocket/starter-websocket-tio/src/main/resources/static/stompwebsocket/websocket.jsp @@ -32,7 +32,7 @@ showGreeting(JSON.parse(greeting.body).content); }); - stompClient.subscribe('/user/' + userid + '/message',function(greeting){ + stompClient.subscribe('/primaryEntity/' + userid + '/message',function(greeting){ alert(JSON.parse(greeting.body).content); showGreeting(JSON.parse(greeting.body).content); }); diff --git a/starter-websocket/starter-websocket-tio/src/main/resources/templates/stomp/stomp-v1.html b/starter-websocket/starter-websocket-tio/src/main/resources/templates/stomp/stomp-v1.html index c60b287..4b0cf27 100644 --- a/starter-websocket/starter-websocket-tio/src/main/resources/templates/stomp/stomp-v1.html +++ b/starter-websocket/starter-websocket-tio/src/main/resources/templates/stomp/stomp-v1.html @@ -44,7 +44,7 @@ showResponse(JSON.parse(response.body).responseMessage); }); // 另外再注册一下定时任务接受 - stompClient.subscribe('/user/123/msg', function (response) { + stompClient.subscribe('/primaryEntity/123/msg', function (response) { showCallback(response.body); }); });