分片查詢(sharding-jdbc)以及常見問題解決

新公司使用了自動分庫分表的插件(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>

注意點

  1. 多數據源情況下,要有主數據源@Primary
  2. mapper文件地址要和ShardingMybatisConfig配置文件中@MapperScan路徑一致,最好分庫的數據源的mapper都在一個路徑下,該路徑下的mapper都是用ShardingDataSource的數據庫鏈接,查詢時候自帶分片查詢
  3. 插入和查詢的時候會根據自定義算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章