Sharding-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供额外服务。它使用客户端直连数据库,以 jar 包的形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动。
适用于任何基于 JDBC 的 ORM 框架。支持任何第三方的数据库连接池。支持任意实现 JDBC 规范的数据库。目前支持 MySQL、Oracle、SQL Server、PostgreSQL 以及遵循 SQL92 标准的数据库。
表是透明化数据分片的关键概念。Apache ShardingSphere 通过提供多样化的表类型,适配不同场景下的数据分片需求。
逻辑表
相同结构的水平拆分数据库(表)的逻辑名称,是 SQL 中表的逻辑标识。例:订单数据根据主键尾数拆分为 10 张表,分别是 t_order_0
到 t_order_9
,它们的逻辑表名为 t_order
。
真实表
在水平拆分的数据库中真实存在的物理表。即上个示例中的 t_order_0
到 t_order_9
。
绑定表
指分片规则一致的一组分片表。使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或者跨库关联,从而影响查询效率。例如:t_order
表和 t_order_item
表,均按照 order_id
分片,并且使用 order_id
进行关联,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。举例说明,如果 SQL 为:
select i.* from t_order o join t_order_item i on o.order_id = i.order_id where o.order_id in (10, 11);
在不配置绑定表关系时,假设分片键 order_id
将数值 10 路由至第 0 片,将数值 11 路由至第 1 片,那么路由后的 SQL 应该为 4 条,它们呈现为笛卡尔积:
t_order表 | t_order_item表 |
---|---|
t_order_0 | t_order_item_0 |
t_order_0 | t_order_item_1 |
t_order_1 | t_order_item_0 |
t_order_1 | t_order_item_1 |
在配置绑定表关系后,并且使用 order_id
进行关联后,路由的SQL应该为 2 条:
t_order表 | t_order_item表 |
---|---|
t_order_0 | t_order_item_0 |
t_order_1 | t_order_item_1 |
其中 t_order
表由于指定了分片条件,ShardingSphere 将会以它作为整个绑定表的主表。所有的分片计算将会只使用主表的策略,那么 t_order_item
表的分片计算将会使用 t_order
表的分片条件。
spring:
shardingsphere:
sharding:
tables:
t_order:
actualDataNodes: ds${0..2}.t_order
logicTable: t_order
databaseStrategy:
inline:
sharding-column: order_id
algorithm-expression: ds$->{order_id % 3}
keyGenerator:
type: SNOWFLAKE
column: order_id
t_order_item:
actual-data-nodes: ds${0..2}.t_order_item
logicTable: t_order_item
database-strategy:
inline:
sharding-column: order_id
algorithm-expression: ds${order_id % 3}
keyGenerator:
type: SNOWFLAKE
column: item_id
binding-tables:
- t_order, t_order_item
广播表
指所有的分片数据源中都存在的表,表结构以及表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
spring:
shardingsphere:
sharding:
tables:
t_config:
actual-data-nodes: ds${0..2}.t_config
broadcast-tables:
- t_config
单表
指所有的分片数据源中仅唯一存在的表。适用于数据量不大且无需分片的表。
数据分片的最小单元,由数据源名称和真实表组成。例:ds_0.t_order_0
。逻辑表与真实表的映射关系,可以分为均匀分布和自定义分布两种形式。
均匀分布
指真实表在每个数据源内呈现均匀分布的态势,例如:
db0
├── t_order0
└── t_order1
db1
├── t_order0
└── t_order1
数据节点的配置如下:
db0.t_order0, db0.t_order1, db1.t_order0, db1.t_order1
自定义分布
指真实表呈现特定规则的分布,例如:
db0
├── t_order0
└── t_order1
db1
├── t_order2
├── t_order3
└── t_order4
数据节点的配置如下:
db0.t_order0, db0.t_order1, db1.t_order2, db1.t_order3, db1.t_order4
分片键
用于将数据库(表)水平拆分的数据库字段。例如:按照订单表中的订单 id 取模分片,则订单 id 就是分片键。SQL 中如果没有用于分片的字段,将执行全路由,性能较差。Apache ShardingSphere 支持根据单字段、多字段进行分片。
分片算法
用于将数据分片的算法。分片算法可以使用 Apache ShardingSphere 内置的分片算法语法糖,也可以由开发者自定义分片算法。
分片策略
包括分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键+分片算法,也就是分片策略。
强制分片路由
对于分片字段并非是 SQL 字段而是其它外置条件决定的场景,可以使用 SQL Hint 注入分片值。比如,按照员工主键分库,但是数据库中并没有该字段。SQL Hint 支持通过 Java API 和 SQL 注释两种方式。
在繁琐的数据分片规则配置中,随着数据节点的增多,大量的重复配置使得配置本身不易被维护。通过行表达式可以有效地简化数据节点配置工作量。
对于常见的分片算法,使用 Java 代码实现并不有助于配置的统一管理。通过行表达式书写分片算法,可以有效地将规则配置一同存放,更加易于浏览与存储。
只需要在配置中使用 ${expression}
或者 $->{expression}
标识行表达式即可。目前支持数据节点和分片算法这两个部分的配置。行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。例如:${begin..end}
:表示范围区间;${[unit1, unit2, unit3]}
:表示枚举值;如果连续出现多个行表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合
e.g. ${['online', 'offline']}_table${1..2}
,则最终解析为 online_table1,online_table2,offline_table1,offline_table2
Apache ShardingSphere 不仅提供了内置的分布式主键生成器,例如 UUID、SNOWFLAKE,还抽离出分布式主键生成器的接口,方便用户自行实现自定义的自增主键生成器。
使用 UUID.randomUUID() 的方式。
使用 Twitter 的雪花算法(snowflake)生成 64 bit 的长整型数据,包括 1 bit 符号位、41bit 时间戳位、10 bit 工作进程位、12 bit 序列号位。
符号位:预留,恒为零。
时间戳位:约等于 69.73 年。ShardingSphere 的雪花算法的时间纪元从 2016 年11月1日零点开始,可以使用到 2086 年。
工作进程位:对应每个工作进程 id。
序列号位:在一毫秒内生成的 id。如果一毫秒内生成的数量超过了 4096,则生成器会等待到下个毫秒继续生成。
时钟回拨
服务器时钟回拨会导致产生重复序列,因此默认分布式主键生成器提供了一个最大容忍的时钟回拨毫秒数。 如果时钟回拨的时间超过最大容忍的毫秒数阈值,则程序报错;如果在可容忍的范围内,默认分布式主键生成器会等待时钟同步到最后一次主键生成的时间后再继续工作。 最大容忍的时钟回拨毫秒数的默认值为 0,可通过属性设置。
每个表最多可以指定一个分片策略。
对应 InlineShardingStrategy。使用 Groovy 的表达式,提供对 SQL 语句中的 = 和 in 的分片操作的支持,只支持单分片键。
${begin..end}
:表示范围区间
${[unit1, unit2, unit3]}
:表示枚举值
行表达式如果连续出现多个行表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合。比如 ${['online', 'offline']}_table${1..2}
,则最终解析为 online_table1,online_table2,offline_table1,offline_table2。
java api 方式 - 数据分片
/**
* 数据分片
*/
public class ShardingJdbcDemo {
public static void main(String[] args) {
Map<String, DataSource> dataSourceMap = new HashMap<>();
// 配置数据源0
DruidDataSource dataSource0 = new DruidDataSource();
dataSource0.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource0.setUrl("jdbc:mysql://10.211.55.6:3306/ds0");
dataSource0.setUsername("root");
dataSource0.setPassword("root");
dataSourceMap.put("ds0", dataSource0);
// 配置数据源1
DruidDataSource dataSource1 = new DruidDataSource();
dataSource1.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource1.setUrl("jdbc:mysql://10.211.55.14:3306/ds1");
dataSource1.setUsername("root");
dataSource1.setPassword("root");
dataSourceMap.put("ds1", dataSource1);
// 配置数据源2
DruidDataSource dataSource2 = new DruidDataSource();
dataSource2.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource2.setUrl("jdbc:mysql://10.211.55.15:3306/ds2");
dataSource2.setUsername("root");
dataSource2.setPassword("root");
dataSourceMap.put("ds2", dataSource2);
// 配置表规则
TableRuleConfiguration orderRuleConfiguration = new TableRuleConfiguration("t_order", "ds${0..2}.t_order");
// 配置分库策略
InlineShardingStrategyConfiguration databaseShardingStrategyConfiguration = new InlineShardingStrategyConfiguration("order_id", "ds${order_id % 3}");
orderRuleConfiguration.setDatabaseShardingStrategyConfig(databaseShardingStrategyConfiguration);
// 配置分表策略
InlineShardingStrategyConfiguration tableShardingStrategyConfiguration = new InlineShardingStrategyConfiguration("order_id", "t_order");
orderRuleConfiguration.setTableShardingStrategyConfig(tableShardingStrategyConfiguration);
// 配置分片规则
ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
// 添加表规则
shardingRuleConfiguration.getTableRuleConfigs().add(orderRuleConfiguration);
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration, new Properties());
final String sql = "select * from t_order where order_id = ?";
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setLong(1, 1);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println("order_id >>> " + resultSet.getLong(1));
System.out.println("user_id >>> " + resultSet.getLong(2));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Spring Boot yml 方式 - 数据分片
spring:
application:
name: shardingsphere-demo
shardingsphere:
datasource:
names: ds0,ds1,ds2
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.211.55.6:3306/ds0
username: root
password: root
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.211.55.14:3306/ds1
username: root
password: root
ds2:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.211.55.15:3306/ds2
username: root
password: root
sharding:
tables:
t_order:
actualDataNodes: ds${0..2}.t_order
logicTable: t_order
databaseStrategy:
inline:
sharding-column: order_id
algorithm-expression: ds${order_id % 3}
对应 StandardShardingStrategy。提供对 SQL 语句中的 =、>、 <、 >=、<=、in、between and 的分片操作支持。只支持单分片键。标准分片策略提供了 PreciseShardingAlgorithm、RangeShardingAlgorithm 两种分片算法。PreciseShardingAlgorithm 是必选的,RangeShardingAlgorithm 是可选的。
spring:
shardingsphere:
sharding:
tables:
t_order:
actualDataNodes: ds$->{0..2}.t_order
logicTable: t_order
databaseStrategy:
standard:
shardingColumn: order_id
preciseAlgorithmClassName: com.shardingsphere.demo.algorithm.MyPreciseShardingAlgorithm
rangeAlgorithmClassName: com.shardingsphere.demo.algorithm.MyRangeShardingAlgorithm
对应 PreciseShardingAlgorithm。用于处理单分片键进行 = 、in 操作分片的场景。
public class MyPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyPreciseShardingAlgorithm.class);
private static final String PREFIX = "ds";
/**
* Sharding.
*
* @param availableTargetNames available data sources or tables's names
* @param shardingValue sharding value
* @return sharding result for data source or table's name
*/
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
LOGGER.info("available target names >>> {}", availableTargetNames);
String targetDatabase = PREFIX + shardingValue.getValue() % availableTargetNames.size();
Optional<String> optional = availableTargetNames.stream().filter(targetDatabase::equals).findFirst();
if (optional.isPresent()) {
return targetDatabase;
}
throw new IllegalStateException(targetDatabase +" target name is not available.");
}
}
对应 RangeShardingAlgorithm。用于处理单分片键进行 between and、>、<、>=、<= 操作分片的场景。如果不配置 RangeShardingAlgorithm,SQL 中的 between and 将按照全库路由处理。
public class MyRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyRangeShardingAlgorithm.class);
private static final String PREFIX = "ds";
private static final Long STEP = 100L;
private static final Long INITIAL_END_POINT = 1L;
/**
* Sharding.
*
* @param availableTargetNames available data sources or tables's names
* @param shardingValue sharding value
* @return sharding results for data sources or tables's names
*/
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
LOGGER.info("available target names >>> {}", availableTargetNames);
Collection<String> dataSources = new LinkedList<>();
Range<Long> valueRange = shardingValue.getValueRange();
boolean hasLowerBound = valueRange.hasLowerBound();
boolean hasUpperBound = valueRange.hasUpperBound();
LOGGER.info("has upper bound - {}, has lower bound - {} ", hasUpperBound, hasLowerBound);
Long lowerEndPoint = INITIAL_END_POINT;
Long upperEndPoint = INITIAL_END_POINT;
if (hasLowerBound && !hasUpperBound) {
lowerEndPoint = valueRange.lowerEndpoint();
upperEndPoint = Math.min(lowerEndPoint + STEP, Long.MAX_VALUE);
}
if (!hasLowerBound && hasUpperBound) {
upperEndPoint = valueRange.upperEndpoint();
lowerEndPoint = Math.max(upperEndPoint - STEP, INITIAL_END_POINT);
}
if (hasLowerBound && hasUpperBound) {
lowerEndPoint = valueRange.lowerEndpoint();
upperEndPoint = valueRange.upperEndpoint();
}
for (Long i = lowerEndPoint; i <= upperEndPoint; i++) {
String dataSource = PREFIX + (i % availableTargetNames.size());
dataSources.add(dataSource);
}
return dataSources;
}
}
对应 ComplexShardingStrategy。提供对 SQL语句中的 =、>、<、>=、<=、in、between and 的分片操作支持。支持多分片键。
spring:
shardingsphere:
sharding:
tables:
t_order:
actualDataNodes: ds$->{0..2}.t_order
logicTable: t_order
databaseStrategy:
complex:
shardingColumns: order_id, user_id
algorithmClassName: com.shardingsphere.demo.algorithm.MyComplexKeysShardingAlgorithm
对应 ComplexKeysShardingAlgorithm。用于处理使用多键作为分片键进行分片的场景。
public class MyComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
private static final String SHARDING_KEY = "order_id";
private static final String SHARDING_KEY2 = "user_id";
private static final String PREFIX = "ds";
/**
* Sharding.
*
* @param availableTargetNames available data sources or tables's names
* @param shardingValue sharding value
* @return sharding results for data sources or tables's names
*/
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
Collection<String> targetDataSources = new LinkedList<>();
Map<String, Collection<Long>> columnNameAndShardingValuesMap = shardingValue.getColumnNameAndShardingValuesMap();
if (columnNameAndShardingValuesMap.containsKey(SHARDING_KEY)) {
List<Long> orderIdShardingValues = new LinkedList<>(columnNameAndShardingValuesMap.get(SHARDING_KEY));
if (columnNameAndShardingValuesMap.containsKey(SHARDING_KEY2)) {
List<Long> userIdShardingValues = new LinkedList<>(columnNameAndShardingValuesMap.get(SHARDING_KEY2));
for (Long orderIdShardingValue : orderIdShardingValues) {
if (orderIdShardingValue % 2 == 1) {
targetDataSources.add(PREFIX + 2);
continue;
}
for (Long userIdShardingValue : userIdShardingValues) {
targetDataSources.add(PREFIX + (userIdShardingValue / 2 % 2));
}
}
}
return availableTargetNames;
}
return targetDataSources;
}
}
对应 HintShardingStrategy。通过 Hint 指定分片值而非从 SQL 中提取分片值的方式进行分片的策略。
spring:
shardingsphere:
sharding:
tables:
t_order:
actualDataNodes: ds$->{0..2}.t_order
logicTable: t_order
databaseStrategy:
hint:
algorithmClassName: com.mzs.shardingsphere.demo.algorithm.MyHintShardingAlgorithm
对应 HintShardingAlgorithm。用于处理使用 Hint 行分片的场景。
在一些场景中,分片条件不存在于 SQL 中,而是存在于外部业务逻辑。ShardingSphere 提供了一种通过外部指定分片结果的方式,叫做 Hint。
实现机制:ShardingSphere 使用 ThreadLocal 管理分片键值。可以通过编程的方式向 HintManager 中添加分片条件,该分片条件仅仅在当前线程中生效。
在数据库的 crud 操作的前面加上如下几行代码:
HintManager.clear();
try (HintManager hintManager = HintManager.getInstance()) {
hintManager.setDatabaseShardingValue(0L); // 指定分片值
// hintManager.addDatabaseShardingValue("t_order", 0L); // 指定逻辑表名与分片值
// hintManager.addTableShardingValue("t_order", 0L); // 指定逻辑表名与分片值
// hintManager.setMasterRouteOnly(); // 强制从MySQL的主节点读取数据
// 执行数据库的 crud 操作
}
public class MyHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
private static final String PREFIX = "ds";
/**
* Sharding.
*
* sharding value injected by hint, not in SQL.
*
* @param availableTargetNames available data sources or tables's names
* @param shardingValue sharding value
* @return sharding result for data sources or tables's names
*/
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Long> shardingValue) {
Collection<String> dataSourceNames = new ArrayList<>();
// 遍历上述的 HintManager 指定的分片值
for (Long value : shardingValue.getValues()) {
dataSourceNames.add(PREFIX + (value % 3));
}
return dataSourceNames;
}
}
对应NoneShardingStrategy。不分片的策略。
spring:
shardingsphere:
sharding:
tables:
t_order:
actualDataNodes: ds0.t_order
logicTable: t_order
databaseStrategy:
none:
java api 方式- 读写分离
/**
* 读写分离
*/
public class ShardingJdbcDemo2 {
public static void main(String[] args) {
Map<String, DataSource> dataSourceMap = new HashMap<>();
// 配置数据源1
DruidDataSource dataSource1 = new DruidDataSource();
dataSource1.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource1.setUrl("jdbc:mysql://10.211.55.7:3306/ds3");
dataSource1.setUsername("root");
dataSource1.setPassword("root");
dataSourceMap.put("master0", dataSource1);
// 配置数据源2
DruidDataSource dataSource2 = new DruidDataSource();
dataSource2.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource2.setUrl("jdbc:mysql://10.211.55.8:3306/ds3");
dataSource2.setUsername("root");
dataSource2.setPassword("root");
dataSourceMap.put("slave0", dataSource2);
MasterSlaveRuleConfiguration masterSlaveRuleConfiguration = new MasterSlaveRuleConfiguration(
"master_slave_shard", "master0", Collections.singletonList("slave0"));
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
DataSource dataSource = MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, masterSlaveRuleConfiguration, new Properties());
String sql = "select * from user_info where user_id = ?";
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setLong(1, 1);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println("user_id >>> " + resultSet.getLong(1));
System.out.println("user_name >>> " + resultSet.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Spring Boot yml 方式 - 读写分离
spring:
shardingsphere:
datasource:
names: master0,slave0
master0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.211.55.7:3306/ds3
username: root
password: root
slave0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.211.55.8:3306/ds3
username: root
password: root
sharding:
tables:
user_info:
actualDataNodes: master0.user_info
databaseStrategy:
inline:
sharding-column: user_id
algorithm-expression: master0
keyGenerator:
type: SNOWFLAKE
column: user_id
master-slave-rules:
master0:
master-data-source-name: master0
slave-data-source-names: slave0
完全支持 MySQL、PostgreSQL 和 Oracle 的分页查询,SQLServer 由于分页查询较为复杂,仅部分支持。
详情查看 ShardingSphere4.x版本分页
详情查看 ShardingSphere4.x版本SQL规范
首先需要导入如下依赖:
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-jdbc-spring-boot-starterartifactId>
<version>${shardingsphere.version}version>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-transaction-xa-coreartifactId>
<version>${shardingsphere.version}version>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-transaction-base-seata-atartifactId>
<version>${sharding-sphere.version}version>
dependency>
然后配置 Spring Boot 的事务管理器。
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
@Bean
public PlatformTransactionManager txManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
最后在业务代码中使用分布式事务。
@Transactional
@ShardingTransactionType(TransactionType.XA) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
public void insert() {
jdbcTemplate.execute("INSERT INTO t_order (user_id, status) VALUES (?, ?)", (PreparedStatementCallback<Object>) preparedStatement -> {
preparedStatement.setObject(1, i);
preparedStatement.setObject(2, "init");
preparedStatement.executeUpdate();
});
}
本地事务
对应 TransactionType.LOCAL。
完全支持非跨库事务,例如:仅分表,或者分库但是路由的结果在单库中。
完全支持因逻辑夜场导致的跨库事务。例如:同一事务中,跨两个库更新。更新完毕后,抛出空指针,则两个库的内容都能回滚。
不支持因网络、硬件异常导致的跨库事务。例如:同一事务中,跨两个库更新,更新完毕后、未提交之前,第一个库宕机,则只有第二个库的数据提交。
两阶段事务-XA
对应 TransactionType.XA。
ShardingSpere 默认的 XA 事务管理器是 Atomikos,在项目的 logs 目录中会生成 xa_tx.log 文件,用于崩溃恢复的。
也可以在项目的 classpath 中添加 jta.properties 来定制化 Atomikos 配置项。具体可以参考Atomikos 官方文档。
柔性事务
对应 TransactionType.BASE。
完全支持跨库分布式事务
支持RC隔离级别
通过undo快照进行事务回滚
支持服务宕机后的,自动恢复提交中的事务
需要额外部署Seata-server服务进行分支事务的协调