ShardingSphere 4.x User Manual-Sharding-JDBC-Distributed Transaction

Apache ShardingSphere
4 min readSep 7, 2020

--

Distributed transaction have been integrated into ShardingDataSource, you can use TransactionTypeHolder to modify transaction type before creating ShardingConnection.

Not Use Spring

Introduce Maven Dependency

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
<!-- introduce this module if you want to use XA transaction -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- introduce this module if you want to use BASE transaction -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>

Raw JDBC for sharding transaction

TransactionTypeHolder.set(TransactionType.XA); // Support TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
try (Connection connection = dataSource.getConnection()) { // dataSource type is ShardingDataSource
connection.setAutoCommit(false);
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO t_order (user_id, status) VALUES (?, ?)");
preparedStatement.setObject(1, i);
preparedStatement.setObject(2, "init");
preparedStatement.executeUpdate();
connection.commit();
}

Use Spring-namespace

Introduce Maven Dependency

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- introduce this module if you want to use XA transaction -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- introduce this module if you want to use BASE transaction -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>

Config Spring-namespace transaction manager

<!-- ShardingDataSource configuration -->
...
<!-- Enable auto scan @ShardingTransactionType annotation to inject the transaction type before connection created -->
<sharding:tx-type-annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="shardingDataSource" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="shardingDataSource" />
</bean>
<tx:annotation-driven />

Use sharding transaction in business code

@Transactional
@ShardingTransactionType(TransactionType.XA) // Support 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();
});
}

Use Spring-boot

Introduce Maven Dependency

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- introduce this module if you want to use XA transaction -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- introduce this module if you want to use BASE transaction -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>

Config spring-boot transaction manager

@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);
}
}

Use sharding transaction in business code

@Transactional
@ShardingTransactionType(TransactionType.XA) // Support 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();
});
}

Other configuration for Sharding Transaction Manager

XA Transaction (Optional)

Default ShardingSphere XA transaction manager is Atomikos. xa_tx.log generated in the project log is necessary for the recovery when XA crashes. Please do not delete it.

Or you can add jta.properties in classpath of the program to customize Atomikos configurations. For detailed configuration rules, please refer to the official documentation of Atomikos.

BASE Transaction (SEATA-AT)

1.Download seata server according to seata-work-shop, refer to step6 and step7 is OK.

2.Create undo_log table in each physical database.(only mysql supported before seata version 0.8.X)

CREATE TABLE IF NOT EXISTS `undo_log`
(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'increment id',
`branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME NOT NULL COMMENT 'modify datetime',
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

3.Config seata.conf file in classpath.

client {
application.id = example ## application unique id.
transaction.service.group = my_test_tx_group ## transaction group
}

4.Modify file.conf and registry.conf if you need.

Distributed Transaction Example

Data Masking

This chapter mainly introduces how to use the feather of Data Masking. On one hand User can use Data Masking and Sharding together, which will create ShardingDataSource, On another hand, when user only adopt the feather of Data Masking, ShardingSphere will create EncryptDataSource.

Not Use Spring

Introduce Maven Dependency

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>

Rule Configuration Based on Java

// Configure actual data source
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/encrypt");
dataSource.setUsername("root");
dataSource.setPassword("");

// Configure the encrypt rule
Properties props = new Properties();
props.setProperty("aes.key.value", "123456");
EncryptorRuleConfiguration encryptorConfig = new EncryptorRuleConfiguration("AES", props);
EncryptColumnRuleConfiguration columnConfig = new EncryptColumnRuleConfiguration("plain_pwd", "cipher_pwd", "", "aes");
EncryptTableRuleConfiguration tableConfig = new EncryptTableRuleConfiguration(Collections.singletonMap("pwd", columnConfig));
EncryptRuleConfiguration encryptRuleConfig = new EncryptRuleConfiguration();
encryptRuleConfig.getEncryptors().put("aes", encryptorConfig);
encryptRuleConfig.getTables().put("t_encrypt", tableConfig);

// Get data source
DataSource dataSource = EncryptDataSourceFactory.createDataSource(dataSource, encryptRuleConfig, new Properties());

Rule Configuration Based on Yaml

dataSource:  !!org.apache.commons.dbcp2.BasicDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/encrypt?serverTimezone=UTC&useSSL=false
username: root
password:
encryptRule:
tables:
t_order:
columns:
user_id:
cipherColumn: user_cipher
encryptor: order_encryptor
encryptors:
order_encryptor:
type: aes
props:
aes.key.value: 123456
props:
query.with.cipher.column: true
DataSource dataSource = YamlEncryptDataSourceFactory.createDataSource(yamlFile);

Use Native JDBC

Introduce Maven Dependency

<!-- for spring boot -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
<!-- for spring namespace -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>

Rule Configuration Based on Spring Boot

spring.shardingsphere.datasource.name=dsspring.shardingsphere.datasource.ds.type=org.apache.commons.dbcp2.BasicDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/encrypt?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=
spring.shardingsphere.datasource.ds.max-total=100
spring.shardingsphere.encrypt.encryptors.encryptor_aes.type=aes
spring.shardingsphere.encrypt.encryptors.encryptor_aes.props.aes.key.value=123456
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.plainColumn=user_decrypt
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.cipherColumn=user_encrypt
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.assistedQueryColumn=user_assisted
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.encryptor=encryptor_aes
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.props.query.with.cipher.column=true

Rule Configuration Based on Spring Boot + JNDI

If you plan to use Sharding-JDBC in Application Server(such as Tomcat) with Spring boot + JNDI, spring.shardingsphere.datasource.${datasourceName}.jndiName can be used as an alternative to series of configuration of datasource. For example:

spring.shardingsphere.datasource.name=dsspring.shardingsphere.datasource.ds.jndi-name=java:comp/env/jdbc/dsspring.shardingsphere.encrypt.encryptors.encryptor_aes.type=aes
spring.shardingsphere.encrypt.encryptors.encryptor_aes.props.aes.key.value=123456
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.plainColumn=user_decrypt
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.cipherColumn=user_encrypt
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.assistedQueryColumn=user_assisted
spring.shardingsphere.encrypt.tables.t_order.columns.user_id.encryptor=encryptor_aes
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.props.query.with.cipher.column=true

Rule Configuration Based on Spring Name Space

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:encrypt="http://shardingsphere.apache.org/schema/shardingsphere/encrypt"
xmlns:bean="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://shardingsphere.apache.org/schema/shardingsphere/encrypt
http://shardingsphere.apache.org/schema/shardingsphere/encrypt/encrypt.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<import resource="datasource/dataSource.xml" />

<bean id="db" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/encrypt?serverTimezone=UTC&useSSL=false" />
<property name="username" value="root" />
<property name="password" value="" />
<property name="maxTotal" value="100" />
</bean>

<bean:properties id="props">
<prop key="aes.key.value">123456</prop>
</bean:properties>

<encrypt:data-source id="encryptDataSource" data-source-name="db" >
<encrypt:encrypt-rule>
<encrypt:tables>
<encrypt:table name="t_order">
<encrypt:column logic-column="user_id" plain-column="user_decrypt" cipher-column="user_encrypt" assisted-query-column="user_assisted" encryptor-ref="encryptor_aes" />
<encrypt:column logic-column="order_id" plain-column="order_decrypt" cipher-column="order_encrypt" assisted-query-column="order_assisted" encryptor-ref="encryptor_md5"/>
</encrypt:table>
</encrypt:tables>
<encrypt:encryptors>
<encrypt:encryptor id="encryptor_aes" type="AES" props-ref="props"/>
<encrypt:encryptor id="encryptor_md5" type="MD5" />
</encrypt:encryptors>
</encrypt:encrypt-rule>
<encrypt:props>
<prop key="sql.show">true</prop>
<prop key="query.with.cipher.column">true</prop>
</encrypt:props>
</encrypt:data-source>
</beans>

Use DataSource in Spring

@Resource
private DataSource dataSource;

--

--

Apache ShardingSphere
Apache ShardingSphere

Written by Apache ShardingSphere

Distributed SQL transaction & query engine for data sharding, scaling, encryption, and more - on any database. https://linktr.ee/ApacheShardingSphere

No responses yet