赞
踩
1.本地事务:普通事务。只能保证在一个数据库上的操作ACID。
JDBC事务就是本地事务,通过connection对象管理。
2.分布式事务:两个及以上数据库源的事务(由每台数据库的本地事务组成的), 使事务可以跨越多个数据库。比如,A库的a1表和B库的b1表,在一个事务中,如果B库的b1表回滚了,A库的a1表也要回滚。
JTA事务支持分布式事务。JTA指Java事务API(Java Transaction API),它本身只是为事务管理提供了接口,Atomikos是其中一种实现。
1.资源层的分布式事务:代表JTA,钢性事务,强一致性,跟交易、结算、钱有关的,对数据一致性要求高的可以考虑用这个。
2.服务层分布式事务:代表TCC,柔性事务,弱一致性。
1.原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做。
2.一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。
3.隔离性(Isolation):并发事务执行之间互不影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性。
4.持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。
关于事务的隔离机制,详细解释请看
【十六】Spring Boot之事务(事务传播机制、嵌套事务、事务隔离机制详解)
CAP理论:在一个分布式系统中,最多只能满足C、A、P中的2个。
CAP含义:
C:Consistency 一致性:同一数据的多个副本是否实时相同。
A:Availability 可用性:一定时间内,系统能返回一个明确的结果 则称为该系统可用。
P:Partition tolerance 分区容错性:将同一服务分布在多个系统中,从而保证某一个系统宕机,仍然有其他系统提供相同的服务。
而通常情况下,我们都必须要满足AP,所以只能牺牲C。
牺牲一致性换取可用性和分区容错性。
牺牲一致性的意思是,把强一致换成弱一致。只要数据最终能一致就好了,并不要实时一致。
主要就是分布式系统中最CAP怎么取舍怎么平衡的一个理论
BA:Basic Available 基本可用 一定时间内能够返回一个明确的结果。
基本可用BA和高可用HA的区别是:
1.响应时间可以更长。
2.给部分用户返回一个降级页面。返回降级页面仍然是返回明确结果。
S:Soft State:柔性状态。同一数据的不同副本的状态,不用实时一致。
E:Eventual Consisstency:最终一致性。 同一数据的不同副本的状态,不用实时一致,但一定要保证经过一定时间后最终是一致的。
分布式事务的规范。
XA规范主要定义了:事务管理器(Transaction Manager)和资源管理器(Resource Manager)之间的接口。
XA接口是双向的系统接口。在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁。
在分布式系统中,从理论上讲,两台机器无法达到一致的状态,需要引入一个单点进行协调。
XA中大致分为两个部分:
1.事务管理器(Transaction Manager),全局事务管理器。
事务管理器控制着全局事务,管理事务生命周期,并协调资源。负责各个本地资源的提交和回滚。
2.资源管理器(Resource Manager),可以理解成是一个局部的事务管理器,一个本地事务管理器或者消息队列。
场景:现有两个不同的数据库,一个叫sid,一个叫lee。操作sid库中是账户余额表,lee库中是支出金额表。
一个比支出操作,要同时更新sid的账户余额表和lee的支出金额表。失败,两个一起回滚。
项目目录
pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>com.sid</groupId>
- <artifactId>jta-atomikos</artifactId>
- <version>1.0-SNAPSHOT</version>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.8.RELEASE</version>
- <relativePath/>
- </parent>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <!-- spring-boot的web启动的jar包 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!-- mybatis -->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.3.2</version>
- </dependency>
-
- <!-- mysql数据库连接包-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.38</version>
- </dependency>
-
- <!-- alibaba的druid数据库连接池 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.9</version>
- </dependency>
-
- <!-- jta-atomikos 分布式事务管理 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jta-atomikos</artifactId>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.16.14</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
-
- <!-- mybatis generator 自动生成代码插件 -->
- <plugin>
- <groupId>org.mybatis.generator</groupId>
- <artifactId>mybatis-generator-maven-plugin</artifactId>
- <version>1.3.2</version>
- <configuration>
- <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
- <overwrite>true</overwrite>
- <verbose>true</verbose>
- </configuration>
- </plugin>
-
- </plugins>
- </build>
-
- </project>
application.yml
- server:
- port: 8080
- context-path: /sid
-
- spring:
- datasource:
- druid:
- one: #数据源1
- driver-class-name: com.mysql.jdbc.Driver
- url: jdbc:mysql://localhost:3306/sid
- username: root
- password: root
- #初始化时建立物理连接的个数
- initialSize: 1
- #池中最大连接数
- maxActive: 20
- #最小空闲连接
- minIdle: 1
- #获取连接时最大等待时间,单位毫秒
- maxWait: 60000
- #有两个含义:
- #1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。
- #2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
- timeBetweenEvictionRunsMillis: 60000
- #连接保持空闲而不被驱逐的最小时间,单位是毫秒
- minEvictableIdleTimeMillis: 300000
- #使用该SQL语句检查链接是否可用。如果validationQuery=null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
- validationQuery: SELECT 1 FROM DUAL
- #建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
- testWhileIdle: true
- #申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
- testOnBorrow: false
- #归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
- testOnReturn: false
- # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
- filters: stat,wall,slf4j
- # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
- #connectionProperties.druid.stat.mergeSql: true
- #connectionProperties.druid.stat.slowSqlMillis: 5000
- # 合并多个DruidDataSource的监控数据
- #useGlobalDataSourceStat: true
- #default-auto-commit: true 默认
- #default-auto-commit: false
- two: #数据源2
- driver-class-name: com.mysql.jdbc.Driver
- url: jdbc:mysql://localhost:3306/lee
- username: root
- password: root
- #初始化时建立物理连接的个数
- initialSize: 1
- #池中最大连接数
- maxActive: 20
- #最小空闲连接
- minIdle: 1
- #获取连接时最大等待时间,单位毫秒
- maxWait: 60000
- #有两个含义:
- #1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。
- #2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
- timeBetweenEvictionRunsMillis: 60000
- #连接保持空闲而不被驱逐的最小时间,单位是毫秒
- minEvictableIdleTimeMillis: 300000
- #使用该SQL语句检查链接是否可用。如果validationQuery=null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
- validationQuery: SELECT 1 FROM DUAL
- #建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
- testWhileIdle: true
- #申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
- testOnBorrow: false
- #归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
- testOnReturn: false
- # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
- filters: stat,wall,slf4j
- # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
- #connectionProperties.druid.stat.mergeSql: true
- #connectionProperties.druid.stat.slowSqlMillis: 5000
- # 合并多个DruidDataSource的监控数据
- #useGlobalDataSourceStat: true
- #default-auto-commit: true 默认
- #default-auto-commit: false
-
- ## 该配置节点为独立的节点,不是在在spring的节点下
- mybatis:
- mapper-locations: classpath:mapping/*/*.xml #注意:一定要对应mapper映射xml文件的所在路径
- type-aliases-package: com.sid.model # 注意:对应实体类的路径
- configuration:
- log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #控制台打印sql
启动类
- @SpringBootApplication
- @MapperScan("com.sid.mapper.*.*")
- public class App {
- public static void main(String[] args) {
- SpringApplication.run(App.class, args);
- }
- }
第一个数据源配置Properties
- @Data
- @Component
- @ConfigurationProperties(prefix = "spring.datasource.druid.one")
- public class OneDataSourceProperties {
- private String driverClassName;
-
- private String url;
-
- private String username;
-
- private String password;
-
- private Integer initialSize;
-
- private Integer maxActive;
-
- private Integer minIdle;
- private Integer maxWait;
- private Integer timeBetweenEvictionRunsMillis;
-
- private Integer minEvictableIdleTimeMillis;
-
- private String validationQuery;
- private Boolean testWhileIdle;
- private Boolean testOnBorrow;
- private Boolean testOnReturn;
-
- private String filters;
-
- }
第二个数据源配置Properties
- @Data
- @Component
- @ConfigurationProperties(prefix = "spring.datasource.druid.two")
- public class TwoDataSourceProperties {
- private String driverClassName;
-
- private String url;
-
- private String username;
-
- private String password;
-
- private Integer initialSize;
-
- private Integer maxActive;
-
- private Integer minIdle;
- private Integer maxWait;
- private Integer timeBetweenEvictionRunsMillis;
-
- private Integer minEvictableIdleTimeMillis;
-
- private String validationQuery;
- private Boolean testWhileIdle;
- private Boolean testOnBorrow;
- private Boolean testOnReturn;
-
- private String filters;
- }
第一个数据源配置
- @Configuration
- //这里要指明这个数据适用于哪些mapper,和这个数据源的sqlsessionFactory
- @MapperScan(basePackages = "com.sid.mapper.sid", sqlSessionFactoryRef = "oneSqlSessionFactory")
- public class OneDataSourceConfiguration {
- @Autowired
- public OneDataSourceProperties oneDataSourceProperties;
-
- //配置第一个数据源
- @Primary
- @Bean(name = "oneDataSource")
- public DataSource oneDataSource() {
- // 这里datasource要使用阿里的支持XA的DruidXADataSource
- DruidXADataSource datasource = new DruidXADataSource();
- BeanUtils.copyProperties(oneDataSourceProperties,datasource);
- AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
- xaDataSource.setXaDataSource(datasource);
- xaDataSource.setUniqueResourceName("oneDataSource");
- return xaDataSource;
- }
-
- //配置第一个sqlsessionFactory
- @Primary
- @Bean(name = "oneSqlSessionFactory")
- public SqlSessionFactory oneSqlSessionFactory(@Qualifier("oneDataSource") DataSource oneDataSource)
- throws Exception {
- SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
- bean.setDataSource(oneDataSource);
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- bean.setMapperLocations(resolver.getResources("classpath:mapping/sid/*.xml"));
- return bean.getObject();
- }
- }
第二个数据源配置
- @Configuration
- @MapperScan(basePackages = "com.sid.mapper.lee", sqlSessionFactoryRef = "twoSqlSessionFactory")
- public class TwoDataSourceConfiguration {
- @Autowired
- public TwoDataSourceProperties twoDataSourceProperties;
-
- @Bean(name = "twoDataSource")
- public DataSource twoDataSource() {
- DruidXADataSource datasource = new DruidXADataSource();
- BeanUtils.copyProperties(twoDataSourceProperties,datasource);
- AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
- xaDataSource.setXaDataSource(datasource);
- xaDataSource.setUniqueResourceName("twoDataSource");
- return xaDataSource;
- }
-
- @Bean(name = "twoSqlSessionFactory")
- public SqlSessionFactory twoSqlSessionFactory(@Qualifier("twoDataSource") DataSource twoDataSource)
- throws Exception {
- SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
- bean.setDataSource(twoDataSource);
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- bean.setMapperLocations(resolver.getResources("classpath:mapping/lee/*.xml"));
- return bean.getObject();
- }
- }
第一个数据源mapper
- @Mapper
- public interface AccountMapper {
- int deleteByPrimaryKey(Integer id);
-
- int insert(Account record);
-
- int insertSelective(Account record);
-
- Account selectByPrimaryKey(Integer id);
-
- int updateByPrimaryKeySelective(Account record);
-
- int updateByPrimaryKey(Account record);
- }
mapping.xml就不贴了,就是Mybatis的插件生生了
第二个数据源mapper
- @Mapper
- public interface ExpenditureMapper {
- int deleteByPrimaryKey(Integer id);
-
- int insert(Expenditure record);
-
- int insertSelective(Expenditure record);
-
- Expenditure selectByPrimaryKey(Integer id);
-
- int updateByPrimaryKeySelective(Expenditure record);
-
- int updateByPrimaryKey(Expenditure record);
- }
model类
- public class Account {
- private Integer id;
-
- private BigDecimal accountBalance;
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public BigDecimal getAccountBalance() {
- return accountBalance;
- }
-
- public void setAccountBalance(BigDecimal accountBalance) {
- this.accountBalance = accountBalance;
- }
- }
- public class Expenditure {
- private Integer id;
-
- private BigDecimal money;
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public BigDecimal getMoney() {
- return money;
- }
-
- public void setMoney(BigDecimal money) {
- this.money = money;
- }
- }
service层使用事务回滚演示
- @Service
- public class TestServiceImpl implements TestService {
-
- @Resource
- private AccountMapper accountMapper;
-
- @Resource
- private ExpenditureMapper expenditureMapper;
-
- @Override
- @Transactional
- public String testJtaAtomikos(){
- Account account = new Account();
- account.setAccountBalance(new BigDecimal(560.56));
- accountMapper.insertSelective(account);
-
- Expenditure expenditure = new Expenditure();
- expenditure.setMoney(new BigDecimal(3.3));
- expenditureMapper.insertSelective(expenditure);
- int i = 1 / 0;
- return "done";
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。