Skip to content

Commit 0a710ab

Browse files
authored
Update statement route (#12316)
* Add update case example. * Refactor shadow determiner. * Refactor abstract shadow route engine. * Add shadow update statement routing engine. * Fix shadow rule configuration yaml swapper. * Fix shadow ut.
1 parent ae047c2 commit 0a710ab

File tree

35 files changed

+805
-683
lines changed

35 files changed

+805
-683
lines changed

examples/shardingsphere-jdbc-example/other-feature-example/future-shadow-example/future-shadow-spring-namespace-mybatis-example/src/main/java/org/apache/shardingsphere/example/shadow/spring/namespace/mybatis/ShadowSpringNamespaceMybatisExample.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.shardingsphere.example.shadow.spring.namespace.mybatis;
1919

20+
import org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.service.OrderService;
2021
import org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.service.ShadowService;
2122
import org.springframework.context.ConfigurableApplicationContext;
2223
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -29,8 +30,18 @@ public final class ShadowSpringNamespaceMybatisExample {
2930

3031
public static void main(final String[] args) throws SQLException {
3132
try (ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(CONFIG_FILE)) {
32-
ShadowService shadowService = applicationContext.getBean("shadowService", ShadowService.class);
33-
shadowService.executeInsertCase();
33+
executeShadowService(applicationContext);
34+
executeOrderService(applicationContext);
3435
}
3536
}
37+
38+
private static void executeOrderService(final ConfigurableApplicationContext applicationContext) {
39+
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
40+
orderService.executeUpdateCase();
41+
}
42+
43+
private static void executeShadowService(final ConfigurableApplicationContext applicationContext) {
44+
ShadowService shadowService = applicationContext.getBean("shadowService", ShadowService.class);
45+
shadowService.executeUpdateCase();
46+
}
3647
}
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,22 @@
1515
* limitations under the License.
1616
*/
1717

18-
package org.apache.shardingsphere.shadow.route.future.engine.validator;
18+
package org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.repository;
1919

20-
import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
21-
import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
20+
import org.apache.ibatis.annotations.Mapper;
21+
import org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.domain.OrderInfo;
2222

23-
/**
24-
* Shadow statement validator.
25-
*
26-
* @param <T> type of SQL statement
27-
*/
28-
public interface ShadowStatementValidator<T extends SQLStatement> {
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
@Mapper
27+
public interface OrderMapper {
28+
29+
void saveOne(OrderInfo orderInfo);
30+
31+
void saveBatch(List<OrderInfo> orderList);
32+
33+
void updateOne(OrderInfo orderInfo);
2934

30-
/**
31-
* Validate whether shadow operation is supported before route.
32-
*
33-
* @param sqlStatementContext SQL statement context
34-
* @return is shadow or not
35-
*/
36-
boolean preValidate(SQLStatementContext<T> sqlStatementContext);
35+
void updateByUserIds(Map<String, Object> updateMap);
3736
}
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,11 @@
1515
* limitations under the License.
1616
*/
1717

18-
package org.apache.shardingsphere.shadow.route.future.engine.determiner;
18+
package org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.service;
1919

20-
import org.apache.shardingsphere.infra.binder.statement.dml.InsertStatementContext;
21-
import org.apache.shardingsphere.shadow.rule.ShadowRule;
22-
23-
/**
24-
* Shadow table determiner.
25-
*/
26-
public interface ShadowTableDeterminer {
20+
public interface OrderService {
21+
22+
void executeInsertCase();
2723

28-
/**
29-
* Is shadow in shadow table.
30-
*
31-
* @param insertStatementContext insert statement context
32-
* @param shadowRule related shadow tables
33-
* @param tableName table name
34-
* @return is shadow or not
35-
*/
36-
boolean isShadow(InsertStatementContext insertStatementContext, ShadowRule shadowRule, String tableName);
24+
void executeUpdateCase();
3725
}

examples/shardingsphere-jdbc-example/other-feature-example/future-shadow-example/future-shadow-spring-namespace-mybatis-example/src/main/java/org/apache/shardingsphere/example/shadow/spring/namespace/mybatis/service/ShadowService.java

+2
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@
2020
public interface ShadowService {
2121

2222
void executeInsertCase();
23+
24+
void executeUpdateCase();
2325
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.service.impl;
19+
20+
import org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.domain.OrderInfo;
21+
import org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.repository.OrderMapper;
22+
import org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.service.OrderService;
23+
import org.springframework.stereotype.Service;
24+
25+
import javax.annotation.Resource;
26+
import java.util.ArrayList;
27+
import java.util.LinkedHashMap;
28+
import java.util.LinkedList;
29+
import java.util.List;
30+
import java.util.Map;
31+
32+
@Service(value = "orderService")
33+
public final class OrderServiceImpl implements OrderService {
34+
35+
@Resource
36+
private OrderMapper orderMapper;
37+
38+
@Override
39+
public void executeInsertCase() {
40+
executeOneInsertCase();
41+
executeBatchInsertCase();
42+
}
43+
44+
@Override
45+
public void executeUpdateCase() {
46+
executeOneUpdateCase();
47+
executeInUpdateCase();
48+
}
49+
50+
private void executeInUpdateCase() {
51+
Map<String, Object> updateMap = new LinkedHashMap<>();
52+
List<Integer> userIds = new LinkedList<>();
53+
userIds.add(1);
54+
userIds.add(2);
55+
updateMap.put("userIds",userIds);
56+
updateMap.put("content","update_case_2");
57+
orderMapper.updateByUserIds(updateMap);
58+
59+
}
60+
61+
private void executeOneUpdateCase() {
62+
OrderInfo orderInfo = new OrderInfo();
63+
orderInfo.setUserId(1);
64+
orderInfo.setContent("update_case_1");
65+
orderMapper.updateOne(orderInfo);
66+
}
67+
68+
69+
private void executeOneInsertCase() {
70+
OrderInfo orderInfo = new OrderInfo();
71+
orderInfo.setUserId(1);
72+
orderInfo.setContent("insert_case_1");
73+
orderMapper.saveOne(orderInfo);
74+
}
75+
76+
private void executeBatchInsertCase() {
77+
List<OrderInfo> orders = new ArrayList<>();
78+
OrderInfo orderInfo1 = new OrderInfo();
79+
orderInfo1.setUserId(1);
80+
orderInfo1.setContent("insert_case_2");
81+
orders.add(orderInfo1);
82+
OrderInfo orderInfo2 = new OrderInfo();
83+
orderInfo2.setUserId(2);
84+
orderInfo2.setContent("insert_case_2");
85+
orders.add(orderInfo2);
86+
OrderInfo orderInfo3 = new OrderInfo();
87+
orderInfo3.setUserId(1);
88+
orderInfo3.setContent("insert_case_2");
89+
orders.add(orderInfo3);
90+
orderMapper.saveBatch(orders);
91+
}
92+
}

examples/shardingsphere-jdbc-example/other-feature-example/future-shadow-example/future-shadow-spring-namespace-mybatis-example/src/main/java/org/apache/shardingsphere/example/shadow/spring/namespace/mybatis/service/impl/ShadowServiceImpl.java

+28-1
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,39 @@ private Collection<String> initInsertCase() {
4747
Collection<String> result = new LinkedList<>();
4848
String insert_case_1 = "INSERT INTO t_order (user_id, content) VALUES (1, 'insert_case_1')";
4949
result.add(insert_case_1);
50-
String insert_case_2 = "INSERT INTO t_order (user_id, content) VALUES (1, 'insert_case_2'), (1, 'insert_case_2')";
50+
String insert_case_2 = "INSERT INTO t_order (user_id, content) VALUES (1, 'insert_case_2'), (1, 'insert_case_2'), (1, 'insert_case_2'), (1, 'insert_case_2')";
5151
result.add(insert_case_2);
5252
String insert_case_3 = "INSERT INTO t_order (user_id, content) VALUES (1, 'insert_case_3'), (2, 'insert_case_3')";
5353
result.add(insert_case_3);
5454
String insert_case_4 = "INSERT INTO t_order (user_id, content) SELECT user_id, content from t_order_data where user_id = 1";
5555
result.add(insert_case_4);
5656
return result;
5757
}
58+
59+
@Override
60+
public void executeUpdateCase() {
61+
Collection<String> updateSQLs = initUpdateCase();
62+
for (String each : updateSQLs) {
63+
execute(each);
64+
}
65+
}
66+
67+
private Collection<String> initUpdateCase() {
68+
Collection<String> result = new LinkedList<>();
69+
String update_case_1 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id = 1 and content = 'update_case_1'";
70+
result.add(update_case_1);
71+
String update_case_2 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id = 2 and content = 'update_case_1'";
72+
result.add(update_case_2);
73+
String update_case_3 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id = 1 or content = 'aa'";
74+
result.add(update_case_3);
75+
String update_case_4 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id = 2 or content = 'aa'";
76+
result.add(update_case_4);
77+
String update_case_5 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id in (1, 2, 3) or content BETWEEN 'aaa' AND 'bbb'";
78+
result.add(update_case_5);
79+
String update_case_6 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id = 2 or content = 'aa'";
80+
result.add(update_case_6);
81+
String update_case_7 = "UPDATE t_order SET user_id = 2, content = 'update_case_1' WHERE user_id BETWEEN 0 AND 2 or content = 'aa'";
82+
result.add(update_case_7);
83+
return result;
84+
}
5885
}

examples/shardingsphere-jdbc-example/other-feature-example/future-shadow-example/future-shadow-spring-namespace-mybatis-example/src/main/resources/META-INF/application-shadow-databases.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
<shadow:shadow-algorithm id="user-id-match-algorithm" type="COLUMN_REGEX_MATCH">
5151
<props>
52-
<prop key="operation">insert</prop>
52+
<prop key="operation">update</prop>
5353
<prop key="column">user_id</prop>
5454
<prop key="regex">[1]</prop>
5555
</props>
@@ -65,7 +65,6 @@
6565
<shadow:data-source id="shadow-data-source" source-data-source-name="ds" shadow-data-source-name="ds_shadow"/>
6666
<shadow:shadow-table name="t_order">
6767
<shadow:algorithm shadow-algorithm-ref= "user-id-match-algorithm" />
68-
<shadow:algorithm shadow-algorithm-ref= "simple-note-algorithm" />
6968
</shadow:shadow-table>
7069
<shadow:shadow-table name="t_user">
7170
<shadow:algorithm shadow-algorithm-ref= "simple-note-algorithm" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to You under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
19+
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
20+
<mapper namespace="org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.repository.OrderMapper">
21+
<resultMap id="ShadowInfoMap" type="org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.domain.OrderInfo">
22+
<result column="id" property="id" jdbcType="INTEGER"/>
23+
<result column="user_id" property="userId" jdbcType="INTEGER"/>
24+
<result column="content" property="content" jdbcType="VARCHAR"/>
25+
</resultMap>
26+
27+
<insert id="saveOne" parameterType="org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.domain.OrderInfo">
28+
insert into t_order(user_id, content) values (#{userId}, #{content})
29+
</insert>
30+
31+
<insert id="saveBatch" parameterType="java.util.List">
32+
insert into t_order(user_id, content) values
33+
<foreach collection="list" item="order" separator=",">
34+
(#{order.userId}, #{order.content})
35+
</foreach>
36+
</insert>
37+
38+
<update id="updateOne" parameterType="org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.domain.OrderInfo">
39+
update t_order
40+
<set>
41+
<if test="content != null">content=#{content}</if>
42+
</set>
43+
where user_id = #{userId}
44+
</update>
45+
46+
<update id="updateByUserIds" parameterType="java.util.Map">
47+
update t_order
48+
<set>
49+
<if test="content != null">content=#{content}</if>
50+
</set>
51+
where user_id in
52+
<foreach collection="userIds" item="userId" separator="," open="(" close=")">
53+
#{userId}
54+
</foreach>
55+
</update>
56+
</mapper>

examples/shardingsphere-jdbc-example/other-feature-example/future-shadow-example/future-shadow-spring-namespace-mybatis-example/src/main/resources/META-INF/mappers/ShadowMapper.xml

-6
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@
1818

1919
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
2020
<mapper namespace="org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.repository.ShadowMapper">
21-
<resultMap id="ShadowInfoMap" type="org.apache.shardingsphere.example.shadow.spring.namespace.mybatis.domain.OrderInfo">
22-
<result column="id" property="id" jdbcType="INTEGER"/>
23-
<result column="user_id" property="userId" jdbcType="INTEGER"/>
24-
<result column="content" property="content" jdbcType="VARCHAR"/>
25-
</resultMap>
26-
2721
<insert id="execute" parameterType="java.lang.String">
2822
${sql}
2923
</insert>

shardingsphere-features/shardingsphere-shadow/shardingsphere-shadow-core/src/main/java/org/apache/shardingsphere/shadow/route/ShadowSQLRouter.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
import org.apache.shardingsphere.infra.route.context.RouteUnit;
2828
import org.apache.shardingsphere.shadow.constant.ShadowOrder;
2929
import org.apache.shardingsphere.shadow.route.future.engine.ShadowRouteEngineFactory;
30-
import org.apache.shardingsphere.shadow.route.future.engine.validator.ShadowStatementValidator;
31-
import org.apache.shardingsphere.shadow.route.future.engine.validator.ShadowStatementValidatorFactory;
3230
import org.apache.shardingsphere.shadow.route.judge.ShadowDataSourceJudgeEngine;
3331
import org.apache.shardingsphere.shadow.route.judge.impl.PreparedShadowDataSourceJudgeEngine;
3432
import org.apache.shardingsphere.shadow.route.judge.impl.SimpleShadowDataSourceJudgeEngine;
@@ -40,7 +38,6 @@
4038
import java.util.LinkedList;
4139
import java.util.List;
4240
import java.util.Map;
43-
import java.util.Optional;
4441

4542
/**
4643
* Shadow SQL router.
@@ -88,7 +85,7 @@ private RouteUnit createRouteUnit(final String logicName, final String actualNam
8885
public void decorateRouteContext(final RouteContext routeContext,
8986
final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ShadowRule rule, final ConfigurationProperties props) {
9087
if (rule.isEnable()) {
91-
doShadowDecorateFuture(routeContext, logicSQL, metaData, rule, props);
88+
doShadowDecorateFuture(routeContext, logicSQL, rule);
9289
} else {
9390
doShadowDecorate(routeContext, logicSQL, rule);
9491
}
@@ -116,14 +113,8 @@ private void doShadowDecorate(final RouteContext routeContext, final LogicSQL lo
116113
routeContext.getRouteUnits().addAll(toBeAdded);
117114
}
118115

119-
@SuppressWarnings({"rawtypes", "unchecked"})
120-
private void doShadowDecorateFuture(final RouteContext routeContext, final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ShadowRule rule, final ConfigurationProperties props) {
121-
SQLStatementContext<?> sqlStatementContext = logicSQL.getSqlStatementContext();
122-
Optional<ShadowStatementValidator> shadowStatementValidator = ShadowStatementValidatorFactory.newInstance(sqlStatementContext.getSqlStatement());
123-
if (shadowStatementValidator.isPresent() && !shadowStatementValidator.get().preValidate(sqlStatementContext)) {
124-
return;
125-
}
126-
ShadowRouteEngineFactory.newInstance(logicSQL).route(routeContext, logicSQL, metaData, rule, props);
116+
private void doShadowDecorateFuture(final RouteContext routeContext, final LogicSQL logicSQL, final ShadowRule rule) {
117+
ShadowRouteEngineFactory.newInstance(logicSQL).route(routeContext, rule);
127118
}
128119

129120
@Override

0 commit comments

Comments
 (0)