1. 引入jar包
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.0</version>
</dependency>
2. 编写application.properties
#模式设置
spring.shardingsphere.mode.type=Standalone
#日志打印
spring.shardingsphere.props.sql-show=true
# 配置真实数据源
spring.shardingsphere.datasource.names=write,read1,read2
# 配置第 1 个数据源
spring.shardingsphere.datasource.write.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.write.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.write.jdbc-url=jdbc:mysql://xx.xx.xxx.xx:3306/testdb?useUnicode=true&characterEncoding=utf8
spring.shardingsphere.datasource.write.username=root
spring.shardingsphere.datasource.write.password=xxxxxx
# 配置第 2 个数据源
spring.shardingsphere.datasource.read1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.read1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.read1.jdbc-url=jdbc:mysql://xx.xx.xxx.xx:3307/testdb?useUnicode=true&characterEncoding=utf8
spring.shardingsphere.datasource.read1.username=root
spring.shardingsphere.datasource.read1.password=xxxxxx
# 配置第 3 个数据源
spring.shardingsphere.datasource.read2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.read2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.read2.jdbc-url=jdbc:mysql://xx.xx.xxx.xx:3308/testdb?useUnicode=true&characterEncoding=utf8
spring.shardingsphere.datasource.read2.username=root
spring.shardingsphere.datasource.read2.password=xxxxxx
#读写分离配置
#写库数据源
spring.shardingsphere.rules.readwrite-splitting.data-sources.readwrite_ds.static-strategy.write-data-source-name=write
#读库数据源(多个从数据源用逗号分隔)
spring.shardingsphere.rules.readwrite-splitting.data-sources.readwrite_ds.static-strategy.read-data-source-names=read1,read2
#负载均衡配置
spring.shardingsphere.rules.readwrite-splitting.data-sources.readwrite_ds.load-balancer-name=round_robin
#负载均衡算法
spring.shardingsphere.rules.readwrite-splitting.load-balancers.round_robin.type=ROUND_ROBIN
3. 事务测试
3.1 测试代码
@RequestMapping("/insertData")
public Object test2() throws InterruptedException {
int random = (int) (Math.random() * 1000 + 1);
String randomUsername = "王二" + random;
User user = new User();
user.setUname(randomUsername);
int insert = userMapper.insert(user);
if (insert > 0) {
log.info("数据插入成功:{}", JSONObject.toJSONString(user));
}
List<User> queryUsername1 = userMapper.selectList(new QueryWrapper<User>().eq("uname", randomUsername));
log.info("数据查询1:{}", JSONObject.toJSONString(queryUsername1));
List<User> queryUsername2 = userMapper.selectList(new QueryWrapper<User>().eq("uname", randomUsername));
log.info("数据查询2:{}", JSONObject.toJSONString(queryUsername2));
return queryUsername1;
}
日志查看
2022-10-31 14:48:33.999 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : Logic SQL: INSERT INTO t_user ( uname ) VALUES ( ? )
2022-10-31 14:48:33.999 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : SQLStatement: MySQLInsertStatement(super=InsertStatement(super=AbstractSQLStatement(parameterCount=1, parameterMarkerSegments=[ParameterMarkerExpressionSegment(startIndex=41, stopIndex=41, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)], commentSegments=[]), table=SimpleTableSegment(tableName=TableNameSegment(startIndex=12, stopIndex=17, identifier=IdentifierValue(value=t_user, quoteCharacter=NONE)), owner=Optional.empty, alias=Optional.empty), insertColumns=Optional[InsertColumnsSegment(startIndex=20, stopIndex=28, columns=[ColumnSegment(startIndex=22, stopIndex=26, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty)])], insertSelect=Optional.empty, values=[InsertValuesSegment(startIndex=39, stopIndex=43, values=[ParameterMarkerExpressionSegment(startIndex=41, stopIndex=41, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)])]), setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
2022-10-31 14:48:34.000 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : Actual SQL: write ::: INSERT INTO t_user ( uname ) VALUES ( ? ) ::: [王二563]
2022-10-31 14:48:34.127 INFO 23376 --- [nio-8080-exec-1] c.q.p.controller.ShardingController : 数据插入成功:{"id":23,"uname":"王二563"}
2022-10-31 14:48:34.216 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : Logic SQL: SELECT id,uname FROM t_user
WHERE (uname = ?)
2022-10-31 14:48:34.216 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : SQLStatement: MySQLSelectStatement(super=SelectStatement(super=AbstractSQLStatement(parameterCount=1, parameterMarkerSegments=[ParameterMarkerExpressionSegment(startIndex=49, stopIndex=49, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)], commentSegments=[]), projections=ProjectionsSegment(startIndex=8, stopIndex=15, projections=[ColumnProjectionSegment(column=ColumnSegment(startIndex=8, stopIndex=9, identifier=IdentifierValue(value=id, quoteCharacter=NONE), owner=Optional.empty), alias=Optional.empty), ColumnProjectionSegment(column=ColumnSegment(startIndex=11, stopIndex=15, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty), alias=Optional.empty)], distinctRow=false), from=SimpleTableSegment(tableName=TableNameSegment(startIndex=23, stopIndex=28, identifier=IdentifierValue(value=t_user, quoteCharacter=NONE)), owner=Optional.empty, alias=Optional.empty), where=Optional[WhereSegment(startIndex=34, stopIndex=50, expr=BinaryOperationExpression(startIndex=41, stopIndex=49, left=ColumnSegment(startIndex=41, stopIndex=45, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty), right=ParameterMarkerExpressionSegment(startIndex=49, stopIndex=49, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty), operator==, text=uname = ?))], groupBy=Optional.empty, having=Optional.empty, orderBy=Optional.empty, combines=[]), table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-10-31 14:48:34.216 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : Actual SQL: read1 ::: SELECT id,uname FROM t_user
WHERE (uname = ?) ::: [王二563]
2022-10-31 14:48:34.751 INFO 23376 --- [nio-8080-exec-1] c.q.p.controller.ShardingController : 数据查询1:[{"id":23,"uname":"王二563"}]
2022-10-31 14:48:34.756 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : Logic SQL: SELECT id,uname FROM t_user
WHERE (uname = ?)
2022-10-31 14:48:34.756 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : SQLStatement: MySQLSelectStatement(super=SelectStatement(super=AbstractSQLStatement(parameterCount=1, parameterMarkerSegments=[ParameterMarkerExpressionSegment(startIndex=49, stopIndex=49, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)], commentSegments=[]), projections=ProjectionsSegment(startIndex=8, stopIndex=15, projections=[ColumnProjectionSegment(column=ColumnSegment(startIndex=8, stopIndex=9, identifier=IdentifierValue(value=id, quoteCharacter=NONE), owner=Optional.empty), alias=Optional.empty), ColumnProjectionSegment(column=ColumnSegment(startIndex=11, stopIndex=15, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty), alias=Optional.empty)], distinctRow=false), from=SimpleTableSegment(tableName=TableNameSegment(startIndex=23, stopIndex=28, identifier=IdentifierValue(value=t_user, quoteCharacter=NONE)), owner=Optional.empty, alias=Optional.empty), where=Optional[WhereSegment(startIndex=34, stopIndex=50, expr=BinaryOperationExpression(startIndex=41, stopIndex=49, left=ColumnSegment(startIndex=41, stopIndex=45, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty), right=ParameterMarkerExpressionSegment(startIndex=49, stopIndex=49, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty), operator==, text=uname = ?))], groupBy=Optional.empty, having=Optional.empty, orderBy=Optional.empty, combines=[]), table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-10-31 14:48:34.756 INFO 23376 --- [nio-8080-exec-1] ShardingSphere-SQL : Actual SQL: read2 ::: SELECT id,uname FROM t_user
WHERE (uname = ?) ::: [王二563]
2022-10-31 14:48:35.300 INFO 23376 --- [nio-8080-exec-1] c.q.p.controller.ShardingController : 数据查询2:[{"id":23,"uname":"王二563"}]
注意: 从上述日志中可以看到,在一次请求中,执行数据插入与数据查询时,数据插入操作的是write 数据源,而数据读取操作的是另外两个read 数据源,因为数据同步的问题,这样后续可能会存在重大隐患!
当我们给上述代码加上@Transactional 注解后,再次执行观察日志
2022-10-31 14:53:27.866 INFO 18800 --- [nio-8080-exec-1] ShardingSphere-SQL : Logic SQL: INSERT INTO t_user ( uname ) VALUES ( ? )
2022-10-31 14:53:27.866 INFO 18800 --- [nio-8080-exec-1] ShardingSphere-SQL : SQLStatement: MySQLInsertStatement(super=InsertStatement(super=AbstractSQLStatement(parameterCount=1, parameterMarkerSegments=[ParameterMarkerExpressionSegment(startIndex=41, stopIndex=41, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)], commentSegments=[]), table=SimpleTableSegment(tableName=TableNameSegment(startIndex=12, stopIndex=17, identifier=IdentifierValue(value=t_user, quoteCharacter=NONE)), owner=Optional.empty, alias=Optional.empty), insertColumns=Optional[InsertColumnsSegment(startIndex=20, stopIndex=28, columns=[ColumnSegment(startIndex=22, stopIndex=26, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty)])], insertSelect=Optional.empty, values=[InsertValuesSegment(startIndex=39, stopIndex=43, values=[ParameterMarkerExpressionSegment(startIndex=41, stopIndex=41, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)])]), setAssignment=Optional.empty, onDuplicateKeyColumns=Optional.empty)
2022-10-31 14:53:27.866 INFO 18800 --- [nio-8080-exec-1] ShardingSphere-SQL : Actual SQL: write ::: INSERT INTO t_user ( uname ) VALUES ( ? ) ::: [王二737]
2022-10-31 14:53:28.892 INFO 18800 --- [nio-8080-exec-1] c.q.p.controller.ShardingController : 数据插入成功:{"id":24,"uname":"王二737"}
2022-10-31 14:53:29.001 INFO 18800 --- [nio-8080-exec-1] ShardingSphere-SQL : Logic SQL: SELECT id,uname FROM t_user
WHERE (uname = ?)
2022-10-31 14:53:29.001 INFO 18800 --- [nio-8080-exec-1] ShardingSphere-SQL : SQLStatement: MySQLSelectStatement(super=SelectStatement(super=AbstractSQLStatement(parameterCount=1, parameterMarkerSegments=[ParameterMarkerExpressionSegment(startIndex=49, stopIndex=49, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty)], commentSegments=[]), projections=ProjectionsSegment(startIndex=8, stopIndex=15, projections=[ColumnProjectionSegment(column=ColumnSegment(startIndex=8, stopIndex=9, identifier=IdentifierValue(value=id, quoteCharacter=NONE), owner=Optional.empty), alias=Optional.empty), ColumnProjectionSegment(column=ColumnSegment(startIndex=11, stopIndex=15, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty), alias=Optional.empty)], distinctRow=false), from=SimpleTableSegment(tableName=TableNameSegment(startIndex=23, stopIndex=28, identifier=IdentifierValue(value=t_user, quoteCharacter=NONE)), owner=Optional.empty, alias=Optional.empty), where=Optional[WhereSegment(startIndex=34, stopIndex=50, expr=BinaryOperationExpression(startIndex=41, stopIndex=49, left=ColumnSegment(startIndex=41, stopIndex=45, identifier=IdentifierValue(value=uname, quoteCharacter=NONE), owner=Optional.empty), right=ParameterMarkerExpressionSegment(startIndex=49, stopIndex=49, parameterMarkerIndex=0, parameterMarkerType=QUESTION, alias=Optional.empty), operator==, text=uname = ?))], groupBy=Optional.empty, having=Optional.empty, orderBy=Optional.empty, combines=[]), table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2022-10-31 14:53:29.002 INFO 18800 --- [nio-8080-exec-1] ShardingSphere-SQL : Actual SQL: write ::: SELECT id,uname FROM t_user
WHERE (uname = ?) ::: [王二737]
2022-10-31 14:53:29.172 INFO 18800 --- [nio-8080-exec-1] c.q.p.controller.ShardingController : 数据查询1:[{"id":24,"uname":"王二737"}]
2022-10-31 14:53:29.173 INFO 18800 --- [nio-8080-exec-1] c.q.p.controller.ShardingController : 数据查询2:[{"id":24,"uname":"王二737"}]
此时可以看到,在一次请求中,执行写入和查询时,操作的都是write 数据源,从而规避掉上述提到的数据同步的风险
附录
注意参考官方文档的时候,YAML 配置 部分并不是 说springboot中的yml配置文件的配置方式,一定要注意!!
参考文档:https://shardingsphere.apache.org/document/5.2.0/cn/user-manual/shardingsphere-jdbc/spring-boot-starter/
|