新公司使用了自動分庫分表的插件(sharding-jdbc),由於有多個數據源,所以結合了durid框架,作爲數據庫鏈接管理框架。
Sharding jdbc
Sharding-JDBC是一個開源的分佈式數據庫中間件,它無需額外部署和依賴,完全兼容JDBC和各種ORM框架。Sharding-JDBC作爲面向開發的微服務雲原生基礎類庫,完整的實現了分庫分表、讀寫分離和分佈式主鍵功能,並初步實現了柔性事務。
研究了一天具體的運行的流程,自己實現了個小demo
項目用的是springboot 2.0+ 、mybaties 、durid
一、準備工作
由於是分庫分表,所以新建三個庫user_1,user_2,user_3,在各個數據庫分別插入30個表
user_pay_order_0 ----> user_pay_order_29
建表語句如下:
CREATE TABLE IF NOT EXISTS user_pay_order (order_id INT NOT NULL, user_id INT NOT NULL, status VARCHAR(50), PRIMARY KEY (order_id))
二、項目配置
項目的基本配置(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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!-- 數據庫連接管理工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<!-- 分庫分表的sharding-jdbc插件 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- 分佈式事務-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<!-- Mysql鏈接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
三、流程
四、具體實現代碼
1.配置多數據源的參數(application.yml)
server:
port: 8090 #端口
spring:
datasource: #主數據源
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/game?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
initialSize: 5
minIdle: 1
maxActive: 50
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
filters: stat,wall
user: #分庫後每個庫的數據源
datasource:
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/user_0?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/user_1?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
ds2:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/user_2?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
2.主數據源配置(沒有分庫分表的)
注意點:
@Primary 必須配置 不然會報錯
@MapperScan 掃描的mapper都將使用當前數據源
/**
* @Author ww
* @Date 2020-04-22
*/
@Configuration
@MapperScan(basePackages = {"com.example.demo.data.mapper.main"}, sqlSessionFactoryRef = "apiMainSqlSessionFactory")
public class MainDataSourceConfig {
//@Primary 標識主數據源
@Bean(name = "dataSource")
@Primary
public DataSource apiMainDataSource() {
//druid數據庫連接配置
DruidXADataSource druidDataSource = new DruidXADataSource();
druidDataSource.setUrl(url);
druidDataSource.setUsername(userName);
druidDataSource.setPassword(password);
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
try {
druidDataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
//分佈式數據源配置
AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
sourceBean.setXaDataSource(druidDataSource);
sourceBean.setMaxPoolSize(maxActive);
sourceBean.setUniqueResourceName("main0");
return sourceBean;
}
//@Qualifier("dataSource") 特指當前上面分佈式數據源
@Bean(name = "apiMainSqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver
.getResources("classpath:mapper/*.xml"));
//SqlMonitorInterceptor 攔截sql查詢語句 替換參數
sqlSessionFactoryBean.setPlugins(new Interceptor[]{new SqlMonitorInterceptor()});
return sqlSessionFactoryBean.getObject();
}
//@Value 獲取剛剛yml配置文件中主數據源的參數
@Value("${spring.datasource.type}")
private String type;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String userName;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.initialSize}")
private Integer initialSize;
@Value("${spring.datasource.maxActive}")
private Integer maxActive;
@Value("${spring.datasource.minIdle}")
private Integer minIdle;
@Value("${spring.datasource.maxWait}")
private Long maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private Long timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private Long minEvictableIdleTimeMillis;
@Value("${spring.datasource.filters}")
private String filters;
}
SqlMonitorInterceptor 攔截器
package com.example.demo.config.plugin;//
@Intercepts({@Signature(
args = {MappedStatement.class, Object.class},
method = "update",
type = Executor.class
), @Signature(
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class},
method = "query",
type = Executor.class
), @Signature(
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class},
method = "query",
type = Executor.class
)})
public class SqlMonitorInterceptor implements Interceptor {
public SqlMonitorInterceptor() {
}
/**
* 將責任鏈的內的sql,替換參數 查詢sql
**/
public Object intercept(Invocation invocation) throws Throwable {
String classname = "";
String method = "";
String sql = "";
String sql_param = "";
long duration = -1L;
long beginTime = System.currentTimeMillis();
try {
MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
String[] strArr = mappedStatement.getId().split("\\.");
classname = strArr[strArr.length - 2];
method = strArr[strArr.length - 1];
Object parameter = null;
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
sql = boundSql.getSql();
sql_param = JSON.toJSONString(parameter);
} catch (Exception var14) {
var14.printStackTrace();
}
Object returnObj = invocation.proceed();
long endTime = System.currentTimeMillis();
duration = endTime - beginTime;
return returnObj;
}
public String showSql(Configuration configuration, BoundSql boundSql) {
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", this.getParameterValue(parameterObject));
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
Iterator var8 = parameterMappings.iterator();
while(var8.hasNext()) {
ParameterMapping parameterMapping = (ParameterMapping)var8.next();
String propertyName = parameterMapping.getProperty();
Object obj;
if (metaObject.hasGetter(propertyName)) {
obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", this.getParameterValue(obj));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", this.getParameterValue(obj));
}
}
}
}
return sql;
}
private String getParameterValue(Object obj) {
String value = null;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(2, 2, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
} else if (obj != null) {
value = obj.toString();
} else {
value = "";
}
return value;
}
public Object plugin(Object target) {
return target instanceof Executor ? Plugin.wrap(target, this) : target;
}
public void setProperties(Properties properties) {
}
}
3.分庫分表數據源配置
配置三個數據源的信息
package com.example.demo.config;
import com.alibaba.druid.pool.xa.DruidXADataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
/**
* @Author ww
* @Date 2020-04-22
*/
@Configuration
public class UserDataSourceConfig {
@Bean(name = "shardingdsDataSource")
public DataSource shardingDataSource() {
AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
DruidXADataSource druidDataSource = new DruidXADataSource();
druidDataSource.setUrl(url);
druidDataSource.setUsername(userName);
druidDataSource.setPassword(password);
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
try {
druidDataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
sourceBean.setXaDataSource(druidDataSource);
sourceBean.setUniqueResourceName("ds0");
sourceBean.setMaxPoolSize(maxActive);
return sourceBean;
}
@Bean(name = "shardingOneDataSource")
public DataSource shardingOneDataSource() {
AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
DruidXADataSource druidDataSource = new DruidXADataSource();
druidDataSource.setUrl(urlOne);
druidDataSource.setUsername(userNameOne);
druidDataSource.setPassword(passwordOne);
druidDataSource.setDriverClassName(driverClassNameOne);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
try {
druidDataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
sourceBean.setXaDataSource(druidDataSource);
sourceBean.setMaxPoolSize(maxActive);
sourceBean.setUniqueResourceName("ds1");
return sourceBean;
}
@Bean(name = "shardingTwoDataSource")
public DataSource shardingTwoDataSource() {
AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
DruidXADataSource druidDataSource = new DruidXADataSource();
druidDataSource.setUrl(urlTwo);
druidDataSource.setUsername(userNameTwo);
druidDataSource.setPassword(passwordTwo);
druidDataSource.setDriverClassName(driverClassNameTwo);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
try {
druidDataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
sourceBean.setXaDataSource(druidDataSource);
sourceBean.setMaxPoolSize(maxActive);
sourceBean.setUniqueResourceName("ds2");
return sourceBean;
}
//三個分庫的數據源配置
@Value("${spring.user.datasource.ds0.type}")
private String type;
@Value("${spring.user.datasource.ds0.driver-class-name}")
private String driverClassName;
@Value("${spring.user.datasource.ds0.url}")
private String url;
@Value("${spring.user.datasource.ds0.username}")
private String userName;
@Value("${spring.user.datasource.ds0.password}")
private String password;
@Value("${spring.user.datasource.ds1.type}")
private String typeOne;
@Value("${spring.user.datasource.ds1.driver-class-name}")
private String driverClassNameOne;
@Value("${spring.user.datasource.ds1.url}")
private String urlOne;
@Value("${spring.user.datasource.ds1.username}")
private String userNameOne;
@Value("${spring.user.datasource.ds1.password}")
private String passwordOne;
@Value("${spring.user.datasource.ds2.type}")
private String typeTwo;
@Value("${spring.user.datasource.ds2.driver-class-name}")
private String driverClassNameTwo;
@Value("${spring.user.datasource.ds2.url}")
private String urlTwo;
@Value("${spring.user.datasource.ds2.username}")
private String userNameTwo;
@Value("${spring.user.datasource.ds2.password}")
private String passwordTwo;
@Value("${spring.datasource.initialSize}")
private Integer initialSize;
@Value("${spring.datasource.maxActive}")
private Integer maxActive;
@Value("${spring.datasource.minIdle}")
private Integer minIdle;
@Value("${spring.datasource.maxWait}")
private Long maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private Long timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private Long minEvictableIdleTimeMillis;
@Value("${spring.datasource.filters}")
private String filters;
}
將三個數據源裝載在分片數據源工廠裏
/**
* @Author ww
* @Date 2020-04-22
*/
@Component
public class ShardingDataSourceConfig {
//最後返回的由 分片數據工廠ShardingDataSourceFactory 生產的DataSource
private DataSource shardingDataSource;
//前面配置的三個分庫的數據源
@Resource(name = "shardingdsDataSource")
private DataSource shardingdsDataSource;
@Resource(name = "shardingOneDataSource")
private DataSource shardingOneDataSource;
@Resource(name = "shardingTwoDataSource")
private DataSource shardingTwoDataSource;
//在當前類被依賴注入(@autowired)後執行的方法。
@PostConstruct
public void init() throws SQLException {
//將三個數據源放在map中
Map<String ,DataSource> dataSourceMap = new HashMap<>();
dataSourceMap.put("ds0",shardingdsDataSource);
dataSourceMap.put("ds1",shardingOneDataSource);
dataSourceMap.put("ds2",shardingTwoDataSource);
//
/**
* 新建分片規則配置類 參數任意選
* public final class ShardingRuleConfiguration {
* //默認數據源名稱
* private String defaultDataSourceName;
* //表規則配置
* private Collection<TableRuleConfiguration> tableRuleConfigs = new LinkedList<>();
* //相同表分片規則的組,如果表分片規則相同,則可以放在一個組裏。
* private Collection<String> bindingTableGroups = new LinkedList<>();
* //默認數據庫的分片算法配置
* private ShardingStrategyConfiguration defaultDatabaseShardingStrategyConfig;
* //默認表的分片算法配置
* private ShardingStrategyConfiguration defaultTableShardingStrategyConfig;
* //默認鍵的生成工具類
* private KeyGenerator defaultKeyGenerator;
* //主備配置信息
* private Collection<MasterSlaveRuleConfiguration> masterSlaveRuleConfigs = new LinkedList<>();
* }
*/
ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
//相同表分片規則的組,如果表分片規則相同,則可以放在一個組裏
shardingRuleConfiguration.getBindingTableGroups().addAll(Arrays.asList(
"user_pay_order"
));
//表規則配置
List<TableRuleConfiguration> tableRuleConfigurationList = new ArrayList<>();
/**
* //邏輯表名
* private String logicTable;
* //真實的數據節點名稱
* private String actualDataNodes;
* //數據庫分片算法配置
* private ShardingStrategyConfiguration databaseShardingStrategyConfig;
* //表分片算法配置
* private ShardingStrategyConfiguration tableShardingStrategyConfig;
* //自動生成鍵的名稱
* private String keyGeneratorColumnName;
* //自動生成鍵的工具類
* private KeyGenerator keyGenerator;
*
* private String logicIndex;
*/
// param1 : 邏輯表名, param2 : 真實存在的節點,由數據源 + 表明組成, ds${0..1} 代表 數據庫選擇 ds 後綴爲 0 - 2 之間,user_pay_order_ 代表數據表 user_pay_order_ 後綴 0 - 1 之間
TableRuleConfiguration tableRuleConfiguration = new TableRuleConfiguration("user_pay_order","ds${0..2}.user_pay_order_${0..29}");
//表分片算法配置
tableRuleConfiguration.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_pay_id",new ShardingAlgorithmLong()));
//數據庫分片算法配置
tableRuleConfiguration.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_pay_id",new UserPayOrderDataSourceAlgo()));
tableRuleConfigurationList.add(tableRuleConfiguration);
// 配置分片規則
shardingRuleConfiguration.getTableRuleConfigs().addAll(tableRuleConfigurationList);
shardingDataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap,shardingRuleConfiguration,new Properties());
}
public DataSource getDataSource() {
return shardingDataSource;
}
}
4.分片算法
精確分片算法
對應PreciseShardingAlgorithm,用於處理使用單一鍵作爲分片鍵的=與IN進行分片的場景。需要配合StandardShardingStrategy使用。
範圍分片算法
對應RangeShardingAlgorithm,用於處理使用單一鍵作爲分片鍵的BETWEEN AND進行分片的場景。需要配合StandardShardingStrategy使用。
複合分片算法
對應ComplexKeysShardingAlgorithm,用於處理使用多鍵作爲分片鍵進行分片的場景,包含多個分片鍵的邏輯較複雜,需要應用開發者自行處理其中的複雜度。需要配合ComplexShardingStrategy使用。
Hint分片算法
對應HintShardingAlgorithm,用於處理使用Hint行分片的場景。需要配合HintShardingStrategy使用。
分庫算法UserPayOrderDataSourceAlgo 使用的是精確分片算法
/**
* @Author ww
* @Date 2020-04-22
*/
public class UserPayOrderDataSourceAlgo implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
int postfix = (int)((shardingValue.getValue() / 30) % availableTargetNames.size());
for (String dataSource : availableTargetNames) {
if (dataSource.endsWith(String.valueOf(postfix))) {
return dataSource;
}
}
throw new IllegalArgumentException();
}
}
分表算法 ShardingAlgorithmLong
/**
* @Author ww
* @Date 2020-04-22
*/
public class ShardingAlgorithmLong implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {
String postfix = "" +(preciseShardingValue.getValue() % collection.size());
for (String tableName : collection){
if(tableName.endsWith(postfix)){
return tableName;
}
}
throw new IllegalArgumentException("沒有匹配到id:"+preciseShardingValue.getValue());
}
}
5.將前面的數據源 適配到對應的mapper分類中,使用該mapper中自動會去用到分片查詢
@Configuration
@MapperScan(basePackages = {"com.example.demo.data.mapper.user"}, sqlSessionFactoryRef = "sqlSessionFactory")
public class ShardingMybatisConfig {
@Autowired
private ShardingDataSourceConfig dataSourceConfig;
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceConfig.getDataSource());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver
.getResources("classpath:mapper/*.xml"));
sqlSessionFactoryBean.setPlugins(new Interceptor[]{new UserPayOrderSqlInterceptor()});
return sqlSessionFactoryBean.getObject();
}
}
6.sql重寫 責任鏈模式
Mybatis採用責任鏈模式,通過動態代理組織多個攔截器(插件),通過這些攔截器可以改變Mybatis的默認行爲(諸如SQL重寫之類的)
/**
* 這是個臨時的補救類,主要解決UserPayOrder根據主鍵進行查詢的問題(分片查詢) 沒有也可以
*/
@Intercepts({@Signature(
args = {MappedStatement.class, Object.class},
method = "update",
type = Executor.class
), @Signature(
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class},
method = "query",
type = Executor.class
), @Signature(
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class},
method = "query",
type = Executor.class
)})
public class UserPayOrderSqlInterceptor implements Interceptor {
//Object intercept(Invocation invocation)是實現攔截邏輯的地方,內部要通過invocation.proceed()顯式地推進責任鏈前進,也就是調用下一個攔截器攔截目標方法
public Object intercept(Invocation invocation) throws Throwable {
String classname = "";
String method = "";
String sql = "";
String sql_param = "";
long duration = -1L;
long beginTime = System.currentTimeMillis();
try {
MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
String[] strArr = mappedStatement.getId().split("\\.");
classname = strArr[strArr.length - 2];
method = strArr[strArr.length - 1];
Object parameter = null;
if (invocation.getArgs().length > 1) {
parameter = invocation.getArgs()[1];
}
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
sql = boundSql.getSql();
sql_param = JSON.toJSONString(parameter);
if(classname.equals("UserPayOrderMapper") && method.equals("selectByPrimaryKey")){
String user_pay_id=parameter.toString().split("_")[1];
sql=sql+" and user_pay_id="+user_pay_id;
System.out.println("newsql: "+sql);
modify(boundSql,"sql",sql);
}
} catch (Exception var14) {
var14.printStackTrace();
}
Object returnObj = invocation.proceed();
long endTime = System.currentTimeMillis();
duration = endTime - beginTime;
return returnObj;
}
public String showSql(Configuration configuration, BoundSql boundSql) {
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", this.getParameterValue(parameterObject));
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
Iterator var8 = parameterMappings.iterator();
while(var8.hasNext()) {
ParameterMapping parameterMapping = (ParameterMapping)var8.next();
String propertyName = parameterMapping.getProperty();
Object obj;
if (metaObject.hasGetter(propertyName)) {
obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", this.getParameterValue(obj));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", this.getParameterValue(obj));
}
}
}
}
return sql;
}
private static void modify(Object object, String fieldName, Object newFieldValue){
try {
Field field = object.getClass().getDeclaredField(fieldName);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & Modifier.FINAL);
if(!field.isAccessible()) {
field.setAccessible(true);
}
field.set(object, newFieldValue);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getParameterValue(Object obj) {
String value = null;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(2, 2, Locale.CHINA);
value = "'" + formatter.format(new Date()) + "'";
} else if (obj != null) {
value = obj.toString();
} else {
value = "";
}
return value;
}
//Object plugin(Object target) 就是用當前這個攔截器生成對目標target的代理,實際是通過Plugin.wrap(target,this) 來完成的,把目標target和攔截器this傳給了包裝函數
public Object plugin(Object target) {
return target instanceof Executor ? Plugin.wrap(target, this) : target;
}
//setProperties(Properties properties)用於設置額外的參數,參數配置在攔截器的Properties節點裏
public void setProperties(Properties properties) {
}
}
7.項目結構以及代碼
UserController.java
@RestController
public class UserController{
@Autowired
private UserPayOrderService userPayOrderService;
/**
* 根據訂單號獲取商戶id
* @param userOrderId 訂單id
* @return
*/
@PostMapping("/userOrderMerchantId")
public String userOrderMerchantId(@RequestParam("userOrderId") String userOrderId){
return userPayOrderService.userOrderMerchantId(userOrderId);
}
@PostMapping("/submit")
public String submit(@RequestBody SubmitUserPayOrderRequest userPayOrderRequest){
return userPayOrderService.submit(userPayOrderRequest);
}
}
UserPayOrderService .java
@Service
public class UserPayOrderService {
@Autowired
private UserPayOrderMapper userPayOrderDao;
/**
* 根據訂單號獲取商戶id
*
* @param userOrderId
* @return
*/
public String userOrderMerchantId(String userOrderId) {
UserPayOrder upo = userPayOrderDao.selectByEntity(new UserPayOrder()
.setId(userOrderId));
return JSON.toJSONString(upo);
}
/**
* 提交訂單
*
* @param userPayOrderRequest
* @return
* @throws Exception
*/
@Transactional(rollbackFor = Exception.class)
public String submit(SubmitUserPayOrderRequest userPayOrderRequest) {
Date createTime = new Date();
userPayOrderDao.insertSelective(new UserPayOrder()
.setId(userPayOrderRequest.getId())
.setMerchantId(userPayOrderRequest.getMerchantId())
.setUserPayId(userPayOrderRequest.getUserPayId())
.setAmountOfConsumption(userPayOrderRequest.getAmountOfConsumption())
.setPayAbleAmount(userPayOrderRequest.getPayAblAmount())
.setUserId(userPayOrderRequest.getUserId())
.setDiscountAmount(userPayOrderRequest.getDiscountAmount())
.setFreeAmount(userPayOrderRequest.getFreeAmount())
.setStatus(userPayOrderRequest.getStatus())
.setChannelId(userPayOrderRequest.getChannelId())
.setEnjoyKingAmount(userPayOrderRequest.getEnjoyKingAmount())
.setPayType(userPayOrderRequest.getPayType())
.setScanType(userPayOrderRequest.getScanType())
.setCreateTime(createTime));
return "xx";
}
}
UserPayOrderMapper.java
/**
* @Author ww
* @Date 2020-04-22
*/
@Mapper
public interface UserPayOrderMapper extends BaseDao<UserPayOrder,String> {
//自行擴展
int updateByIdAndPayUserId(UserPayOrder userPayOrder);
Integer queryStatus(@Param("id") String id,
@Param("userPayId") Long userPayId);
UserPayOrder selectByPayTime(UserPayOrder userPayOrder);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.data.mapper.user.UserPayOrderMapper">
<resultMap id="BaseResultMap" type="com.example.demo.entity.UserPayOrder">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="merchant_id" jdbcType="BIGINT" property="merchantId" />
<result column="user_pay_id" jdbcType="BIGINT" property="userPayId" />
<result column="amount_of_consumption" jdbcType="DECIMAL" property="amountOfConsumption" />
<result column="pay_able_amount" jdbcType="DECIMAL" property="payAbleAmount" />
<result column="merchant_receive_amount" jdbcType="DECIMAL" property="merchantReceiveAmount" />
<result column="pay_type" jdbcType="INTEGER" property="payType" />
<result column="pay_time" jdbcType="TIMESTAMP" property="payTime" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="discount_amount" jdbcType="DECIMAL" property="discountAmount" />
<result column="free_amount" jdbcType="DECIMAL" property="freeAmount" />
<result column="status" jdbcType="INTEGER" property="status" />
<result column="channel_id" jdbcType="INTEGER" property="channelId" />
<result column="enjoy_king_amount" jdbcType="DECIMAL" property="enjoyKingAmount" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="enjoy_issue_king_amount" jdbcType="DECIMAL" property="enjoyIssueKingAmount" />
<result column="enjoy_receive_king_amount" jdbcType="DECIMAL" property="enjoyReceiveKingAmount" />
</resultMap>
<sql id="Base_Column_List">
id, merchant_id, user_pay_id, amount_of_consumption, pay_able_amount, merchant_receive_amount, pay_type, pay_time, user_id, discount_amount, free_amount, status, channel_id, enjoy_king_amount, create_time, update_time, enjoy_issue_king_amount, enjoy_receive_king_amount
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_pay_order
where id = #{id,jdbcType=VARCHAR}
</select>
<select id="selectByEntity" parameterType="com.example.demo.entity.UserPayOrder" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_pay_order
where 1 = 1
<if test="id != null" >
and id = #{id,jdbcType=VARCHAR}
</if>
<if test="merchantId != null" >
and merchant_id = #{merchantId,jdbcType=BIGINT}
</if>
<if test="userPayId != null" >
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</if>
<if test="amountOfConsumption != null" >
and amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL}
</if>
<if test="payAbleAmount != null" >
and pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL}
</if>
<if test="merchantReceiveAmount != null" >
and merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL}
</if>
<if test="payType != null" >
and pay_type = #{payType,jdbcType=INTEGER}
</if>
<if test="payTime != null" >
and pay_time = #{payTime,jdbcType=TIMESTAMP}
</if>
<if test="userId != null" >
and user_id = #{userId,jdbcType=BIGINT}
</if>
<if test="discountAmount != null" >
and discount_amount = #{discountAmount,jdbcType=DECIMAL}
</if>
<if test="freeAmount != null" >
and free_amount = #{freeAmount,jdbcType=DECIMAL}
</if>
<if test="status != null" >
and status = #{status,jdbcType=INTEGER}
</if>
<if test="channelId != null" >
and channel_id = #{channelId,jdbcType=INTEGER}
</if>
<if test="enjoyKingAmount != null" >
and enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL}
</if>
<if test="createTime != null" >
and create_time = #{createTime,jdbcType=TIMESTAMP}
</if>
<if test="updateTime != null" >
and update_time = #{updateTime,jdbcType=TIMESTAMP}
</if>
<if test="enjoyIssueKingAmount != null" >
and enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL}
</if>
<if test="enjoyReceiveKingAmount != null" >
and enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL}
</if>
limit 1
</select>
<select id="selectByPayTime" parameterType="com.example.demo.entity.UserPayOrder" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_pay_order
where user_pay_id = #{userPayId,jdbcType=BIGINT}
and pay_type = #{payType,jdbcType=INTEGER}
and status = #{status,jdbcType=INTEGER}
order by pay_time asc
limit 1
</select>
<select id="selectByEntityList" parameterType="com.example.demo.entity.UserPayOrder" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_pay_order
where 1 = 1
<if test="id != null" >
and id = #{id,jdbcType=VARCHAR}
</if>
<if test="merchantId != null" >
and merchant_id = #{merchantId,jdbcType=BIGINT}
</if>
<if test="userPayId != null" >
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</if>
<if test="amountOfConsumption != null" >
and amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL}
</if>
<if test="payAbleAmount != null" >
and pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL}
</if>
<if test="merchantReceiveAmount != null" >
and merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL}
</if>
<if test="payType != null" >
and pay_type = #{payType,jdbcType=INTEGER}
</if>
<if test="payTime != null" >
and pay_time = #{payTime,jdbcType=TIMESTAMP}
</if>
<if test="userId != null" >
and user_id = #{userId,jdbcType=BIGINT}
</if>
<if test="discountAmount != null" >
and discount_amount = #{discountAmount,jdbcType=DECIMAL}
</if>
<if test="freeAmount != null" >
and free_amount = #{freeAmount,jdbcType=DECIMAL}
</if>
<if test="status != null" >
and status = #{status,jdbcType=INTEGER}
</if>
<if test="channelId != null" >
and channel_id = #{channelId,jdbcType=INTEGER}
</if>
<if test="enjoyKingAmount != null" >
and enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL}
</if>
<if test="createTime != null" >
and create_time = #{createTime,jdbcType=TIMESTAMP}
</if>
<if test="updateTime != null" >
and update_time = #{updateTime,jdbcType=TIMESTAMP}
</if>
<if test="enjoyIssueKingAmount != null" >
and enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL}
</if>
<if test="enjoyReceiveKingAmount != null" >
and enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL}
</if>
</select>
<select id="selectById" parameterType="com.example.demo.entity.UserPayOrder" resultType="java.lang.String">
select
id
from user_pay_order
where 1 = 1
<if test="id != null" >
and id = #{id,jdbcType=VARCHAR}
</if>
<if test="merchantId != null" >
and merchant_id = #{merchantId,jdbcType=BIGINT}
</if>
<if test="userPayId != null" >
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</if>
<if test="amountOfConsumption != null" >
and amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL}
</if>
<if test="payAbleAmount != null" >
and pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL}
</if>
<if test="merchantReceiveAmount != null" >
and merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL}
</if>
<if test="payType != null" >
and pay_type = #{payType,jdbcType=INTEGER}
</if>
<if test="payTime != null" >
and pay_time = #{payTime,jdbcType=TIMESTAMP}
</if>
<if test="userId != null" >
and user_id = #{userId,jdbcType=BIGINT}
</if>
<if test="discountAmount != null" >
and discount_amount = #{discountAmount,jdbcType=DECIMAL}
</if>
<if test="freeAmount != null" >
and free_amount = #{freeAmount,jdbcType=DECIMAL}
</if>
<if test="status != null" >
and status = #{status,jdbcType=INTEGER}
</if>
<if test="channelId != null" >
and channel_id = #{channelId,jdbcType=INTEGER}
</if>
<if test="enjoyKingAmount != null" >
and enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL}
</if>
<if test="createTime != null" >
and create_time = #{createTime,jdbcType=TIMESTAMP}
</if>
<if test="updateTime != null" >
and update_time = #{updateTime,jdbcType=TIMESTAMP}
</if>
<if test="enjoyIssueKingAmount != null" >
and enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL}
</if>
<if test="enjoyReceiveKingAmount != null" >
and enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL}
</if>
limit 1
</select>
<select id="selectByIds" parameterType="com.example.demo.entity.UserPayOrder" resultType="java.lang.String">
select
id
from user_pay_order
where 1 = 1
<if test="id != null" >
and id = #{id,jdbcType=VARCHAR}
</if>
<if test="merchantId != null" >
and merchant_id = #{merchantId,jdbcType=BIGINT}
</if>
<if test="userPayId != null" >
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</if>
<if test="amountOfConsumption != null" >
and amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL}
</if>
<if test="payAbleAmount != null" >
and pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL}
</if>
<if test="merchantReceiveAmount != null" >
and merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL}
</if>
<if test="payType != null" >
and pay_type = #{payType,jdbcType=INTEGER}
</if>
<if test="payTime != null" >
and pay_time = #{payTime,jdbcType=TIMESTAMP}
</if>
<if test="userId != null" >
and user_id = #{userId,jdbcType=BIGINT}
</if>
<if test="discountAmount != null" >
and discount_amount = #{discountAmount,jdbcType=DECIMAL}
</if>
<if test="freeAmount != null" >
and free_amount = #{freeAmount,jdbcType=DECIMAL}
</if>
<if test="status != null" >
and status = #{status,jdbcType=INTEGER}
</if>
<if test="channelId != null" >
and channel_id = #{channelId,jdbcType=INTEGER}
</if>
<if test="enjoyKingAmount != null" >
and enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL}
</if>
<if test="createTime != null" >
and create_time = #{createTime,jdbcType=TIMESTAMP}
</if>
<if test="updateTime != null" >
and update_time = #{updateTime,jdbcType=TIMESTAMP}
</if>
<if test="enjoyIssueKingAmount != null" >
and enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL}
</if>
<if test="enjoyReceiveKingAmount != null" >
and enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL}
</if>
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from user_pay_order where id = #{id,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="com.example.demo.entity.UserPayOrder" >
insert into user_pay_order (
id, merchant_id, user_pay_id, amount_of_consumption, pay_able_amount, merchant_receive_amount, pay_type, pay_time, user_id, discount_amount, free_amount, status, channel_id, enjoy_king_amount, create_time, update_time, enjoy_issue_king_amount, enjoy_receive_king_amount
)
values (
#{id,jdbcType=VARCHAR}, #{merchantId,jdbcType=BIGINT}, #{userPayId,jdbcType=BIGINT}, #{amountOfConsumption,jdbcType=DECIMAL}, #{payAbleAmount,jdbcType=DECIMAL}, #{merchantReceiveAmount,jdbcType=DECIMAL}, #{payType,jdbcType=INTEGER}, #{payTime,jdbcType=TIMESTAMP}, #{userId,jdbcType=BIGINT}, #{discountAmount,jdbcType=DECIMAL}, #{freeAmount,jdbcType=DECIMAL}, #{status,jdbcType=INTEGER}, #{channelId,jdbcType=INTEGER}, #{enjoyKingAmount,jdbcType=DECIMAL}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}, #{enjoyIssueKingAmount,jdbcType=DECIMAL}, #{enjoyReceiveKingAmount,jdbcType=DECIMAL}
)
</insert>
<insert id="insertSelective" parameterType="com.example.demo.entity.UserPayOrder" >
insert into user_pay_order
<trim prefix="(" suffix=")" suffixOverrides=",">
id,
<if test="merchantId != null">
merchant_id,
</if>
<if test="userPayId != null">
user_pay_id,
</if>
<if test="amountOfConsumption != null">
amount_of_consumption,
</if>
<if test="payAbleAmount != null">
pay_able_amount,
</if>
<if test="merchantReceiveAmount != null">
merchant_receive_amount,
</if>
<if test="payType != null">
pay_type,
</if>
<if test="payTime != null">
pay_time,
</if>
<if test="userId != null">
user_id,
</if>
<if test="discountAmount != null">
discount_amount,
</if>
<if test="freeAmount != null">
free_amount,
</if>
<if test="status != null">
status,
</if>
<if test="channelId != null">
channel_id,
</if>
<if test="enjoyKingAmount != null">
enjoy_king_amount,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="enjoyIssueKingAmount != null">
enjoy_issue_king_amount,
</if>
<if test="enjoyReceiveKingAmount != null">
enjoy_receive_king_amount,
</if>
<if test="scanType != null">
scan_type,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
#{id,jdbcType=VARCHAR},
<if test="merchantId != null">
#{merchantId,jdbcType=BIGINT},
</if>
<if test="userPayId != null">
#{userPayId,jdbcType=BIGINT},
</if>
<if test="amountOfConsumption != null">
#{amountOfConsumption,jdbcType=DECIMAL},
</if>
<if test="payAbleAmount != null">
#{payAbleAmount,jdbcType=DECIMAL},
</if>
<if test="merchantReceiveAmount != null">
#{merchantReceiveAmount,jdbcType=DECIMAL},
</if>
<if test="payType != null">
#{payType,jdbcType=INTEGER},
</if>
<if test="payTime != null">
#{payTime,jdbcType=TIMESTAMP},
</if>
<if test="userId != null">
#{userId,jdbcType=BIGINT},
</if>
<if test="discountAmount != null">
#{discountAmount,jdbcType=DECIMAL},
</if>
<if test="freeAmount != null">
#{freeAmount,jdbcType=DECIMAL},
</if>
<if test="status != null">
#{status,jdbcType=INTEGER},
</if>
<if test="channelId != null">
#{channelId,jdbcType=INTEGER},
</if>
<if test="enjoyKingAmount != null">
#{enjoyKingAmount,jdbcType=DECIMAL},
</if>
<if test="createTime != null">
#{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="enjoyIssueKingAmount != null">
#{enjoyIssueKingAmount,jdbcType=DECIMAL},
</if>
<if test="enjoyReceiveKingAmount != null">
#{enjoyReceiveKingAmount,jdbcType=DECIMAL},
</if>
<if test="scanType != null">
#{scanType,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKey" parameterType="com.example.demo.entity.UserPayOrder">
update user_pay_order
<set>
<if test="merchantId != null">
merchant_id = #{merchantId,jdbcType=BIGINT},
</if>
<if test="userPayId != null">
user_pay_id = #{userPayId,jdbcType=BIGINT},
</if>
<if test="amountOfConsumption != null">
amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL},
</if>
<if test="payAbleAmount != null">
pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL},
</if>
<if test="merchantReceiveAmount != null">
merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL},
</if>
<if test="payType != null">
pay_type = #{payType,jdbcType=INTEGER},
</if>
<if test="payTime != null">
pay_time = #{payTime,jdbcType=TIMESTAMP},
</if>
<if test="userId != null">
user_id = #{userId,jdbcType=BIGINT},
</if>
<if test="discountAmount != null">
discount_amount = #{discountAmount,jdbcType=DECIMAL},
</if>
<if test="freeAmount != null">
free_amount = #{freeAmount,jdbcType=DECIMAL},
</if>
<if test="status != null">
status = #{status,jdbcType=INTEGER},
</if>
<if test="channelId != null">
channel_id = #{channelId,jdbcType=INTEGER},
</if>
<if test="enjoyKingAmount != null">
enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="enjoyIssueKingAmount != null">
enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL},
</if>
<if test="enjoyReceiveKingAmount != null">
enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="insertBatch" parameterType="java.util.List" >
insert into user_pay_order (
id, merchant_id, user_pay_id, amount_of_consumption, pay_able_amount, merchant_receive_amount, pay_type, pay_time, user_id, discount_amount, free_amount, status, channel_id, enjoy_king_amount, create_time, update_time, enjoy_issue_king_amount, enjoy_receive_king_amount
)
values
<foreach collection="list" index="index" item="item" separator=",">
(
#{item.id,jdbcType=VARCHAR},
#{item.merchantId,jdbcType=BIGINT},
#{item.userPayId,jdbcType=BIGINT},
#{item.amountOfConsumption,jdbcType=DECIMAL},
#{item.payAbleAmount,jdbcType=DECIMAL},
#{item.merchantReceiveAmount,jdbcType=DECIMAL},
#{item.payType,jdbcType=INTEGER},
#{item.payTime,jdbcType=TIMESTAMP},
#{item.userId,jdbcType=BIGINT},
#{item.discountAmount,jdbcType=DECIMAL},
#{item.freeAmount,jdbcType=DECIMAL},
#{item.status,jdbcType=INTEGER},
#{item.channelId,jdbcType=INTEGER},
#{item.enjoyKingAmount,jdbcType=DECIMAL},
#{item.createTime,jdbcType=TIMESTAMP},
#{item.updateTime,jdbcType=TIMESTAMP},
#{item.enjoyIssueKingAmount,jdbcType=DECIMAL},
#{item.enjoyReceiveKingAmount,jdbcType=DECIMAL}
)
</foreach>
</insert>
<update id="updateBatch" parameterType="java.util.List">
<foreach close=")" collection="list" index="index" item="item" open="(" separator=",">
update user_pay_order
set
merchant_id = #{item.merchantId,jdbcType=BIGINT},
user_pay_id = #{item.userPayId,jdbcType=BIGINT},
amount_of_consumption = #{item.amountOfConsumption,jdbcType=DECIMAL},
pay_able_amount = #{item.payAbleAmount,jdbcType=DECIMAL},
merchant_receive_amount = #{item.merchantReceiveAmount,jdbcType=DECIMAL},
pay_type = #{item.payType,jdbcType=INTEGER},
pay_time = #{item.payTime,jdbcType=TIMESTAMP},
user_id = #{item.userId,jdbcType=BIGINT},
discount_amount = #{item.discountAmount,jdbcType=DECIMAL},
free_amount = #{item.freeAmount,jdbcType=DECIMAL},
status = #{item.status,jdbcType=INTEGER},
channel_id = #{item.channelId,jdbcType=INTEGER},
enjoy_king_amount = #{item.enjoyKingAmount,jdbcType=DECIMAL},
create_time = #{item.createTime,jdbcType=TIMESTAMP},
update_time = #{item.updateTime,jdbcType=TIMESTAMP},
enjoy_issue_king_amount = #{item.enjoyIssueKingAmount,jdbcType=DECIMAL},
enjoy_receive_king_amount = #{item.enjoyReceiveKingAmount,jdbcType=DECIMAL}
where id = #{id,jdbcType=VARCHAR}
</foreach>
</update>
<delete id="deleteBatch" parameterType="java.util.List">
delete from user_pay_order where id in
<foreach close=")" collection="list" index="index" item="item" open="(" separator=",">
#{item}
</foreach>
</delete>
<delete id="deleteByEntity" parameterType="com.example.demo.entity.UserPayOrder">
delete from user_pay_order where 1 = 1
<if test="id != null" >
and id = #{id,jdbcType=VARCHAR}
</if>
<if test="merchantId != null" >
and merchant_id = #{merchantId,jdbcType=BIGINT}
</if>
<if test="userPayId != null" >
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</if>
<if test="amountOfConsumption != null" >
and amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL}
</if>
<if test="payAbleAmount != null" >
and pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL}
</if>
<if test="merchantReceiveAmount != null" >
and merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL}
</if>
<if test="payType != null" >
and pay_type = #{payType,jdbcType=INTEGER}
</if>
<if test="payTime != null" >
and pay_time = #{payTime,jdbcType=TIMESTAMP}
</if>
<if test="userId != null" >
and user_id = #{userId,jdbcType=BIGINT}
</if>
<if test="discountAmount != null" >
and discount_amount = #{discountAmount,jdbcType=DECIMAL}
</if>
<if test="freeAmount != null" >
and free_amount = #{freeAmount,jdbcType=DECIMAL}
</if>
<if test="status != null" >
and status = #{status,jdbcType=INTEGER}
</if>
<if test="channelId != null" >
and channel_id = #{channelId,jdbcType=INTEGER}
</if>
<if test="enjoyKingAmount != null" >
and enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL}
</if>
<if test="createTime != null" >
and create_time = #{createTime,jdbcType=TIMESTAMP}
</if>
<if test="updateTime != null" >
and update_time = #{updateTime,jdbcType=TIMESTAMP}
</if>
<if test="enjoyIssueKingAmount != null" >
and enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL}
</if>
<if test="enjoyReceiveKingAmount != null" >
and enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL}
</if>
</delete>
<select id="selectEntityListByPrimaryKeys" parameterType="java.util.List" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List" />
FROM user_pay_order WHERE id in
<foreach close=")" collection="list" index="index" item="item" open="(" separator=",">
#{item}
</foreach>
</select>
<update id="updateByIdAndPayUserId" parameterType="com.example.demo.entity.UserPayOrder">
update user_pay_order
<set>
<if test="merchantId != null">
merchant_id = #{merchantId,jdbcType=BIGINT},
</if>
<if test="amountOfConsumption != null">
amount_of_consumption = #{amountOfConsumption,jdbcType=DECIMAL},
</if>
<if test="payAbleAmount != null">
pay_able_amount = #{payAbleAmount,jdbcType=DECIMAL},
</if>
<if test="merchantReceiveAmount != null">
merchant_receive_amount = #{merchantReceiveAmount,jdbcType=DECIMAL},
</if>
<if test="payType != null">
pay_type = #{payType,jdbcType=INTEGER},
</if>
<if test="payTime != null">
pay_time = #{payTime,jdbcType=TIMESTAMP},
</if>
<if test="userId != null">
user_id = #{userId,jdbcType=BIGINT},
</if>
<if test="discountAmount != null">
discount_amount = #{discountAmount,jdbcType=DECIMAL},
</if>
<if test="freeAmount != null">
free_amount = #{freeAmount,jdbcType=DECIMAL},
</if>
<if test="status != null">
status = #{status,jdbcType=INTEGER},
</if>
<if test="channelId != null">
channel_id = #{channelId,jdbcType=INTEGER},
</if>
<if test="enjoyKingAmount != null">
enjoy_king_amount = #{enjoyKingAmount,jdbcType=DECIMAL},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="enjoyIssueKingAmount != null">
enjoy_issue_king_amount = #{enjoyIssueKingAmount,jdbcType=DECIMAL},
</if>
<if test="enjoyReceiveKingAmount != null">
enjoy_receive_king_amount = #{enjoyReceiveKingAmount,jdbcType=DECIMAL},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</update>
<select id="queryStatus" resultType="java.lang.Integer">
select status
from user_pay_order
where id = #{id,jdbcType=VARCHAR}
and user_pay_id = #{userPayId,jdbcType=BIGINT}
</select>
</mapper>
注意點
- 多數據源情況下,要有主數據源@Primary
- mapper文件地址要和ShardingMybatisConfig配置文件中@MapperScan路徑一致,最好分庫的數據源的mapper都在一個路徑下,該路徑下的mapper都是用ShardingDataSource的數據庫鏈接,查詢時候自帶分片查詢
- 插入和查詢的時候會根據自定義算法