springboot+mybatisplus,再加入shardingjdbc分表玩法
Posted EchoXian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot+mybatisplus,再加入shardingjdbc分表玩法相关的知识,希望对你有一定的参考价值。
mybatis plus是mybatis的升级版,省去了繁琐的写xml环节,十分好用,具体文档可见http://mp.baomidou.com
先创建一个springboot项目,导入关键jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.1</version> </dependency>
创建实体类Order
package com.example.demo.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @TableName("order") public class Order { @TableId private Integer orderId; @TableField(value = "user_id") private Integer userId; public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } }
创建OrderMapper,直接可以继承mybatisplus的basemapper,里面已经封装好了通用的增删改查
package com.example.demo.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.demo.entity.Order; public interface OrderMapper extends BaseMapper<Order> { void add(Order order); }
创建了OrderMapper自然不能忘了创建相应映射文件
<?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接口 接口方法名对应下面执行语句的id 以此确定执行哪一个sql方法--> <mapper namespace="com.example.demo.dao.OrderMapper" > <!--数据库字段映射对象配置--> <resultMap id="BaseResultMap" type="com.example.demo.entity.Order" > <id column="order_id" property="orderId" jdbcType="BIGINT" /> <result column="user_id" property="userId" jdbcType="VARCHAR" /> </resultMap> <insert id="add" parameterType="com.example.demo.entity.Order" > insert into t_order (order_id,user_id) value (#{orderId},#{userId}) </insert> </mapper>
在启动项Application加入mapper扫描
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication
@MapperScan("com.example.demo.dao")//扫描相应mapper包
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
配置数据源以及mybatisplus的配置
spring: jdbc: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/ds_0?useUnicode=true&characterEncoding=UTF-8 username: root password: root connectionProperties: config.decrypt=true;druid.stat.slowSqlMillis=3000;druid.stat.logSlowSql=true;druid.stat.mergeSql=true filters: stat maxActive: 100 initialSize: 1 maxWait: 15000 minIdle: 1 timeBetweenEvictionRunsMillis: 30000 minEvictableIdleTimeMillis: 180000 validationQuery: SELECT ‘x‘ testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: false maxPoolPreparedStatementPerConnectionSize: 20 removeAbandoned: true removeAbandonedTimeout: 600 logAbandoned: false connectionInitSqls: mybatis-plus: config-location: classpath:mybatis-config.xml mapper-locations: classpath*:mapper/*.xml type-aliases-package: com.example.demo.entity global-config: id-type: 3 #1:数据库ID自增 2:用户输入id 3:全局唯一id(IdWorker) 4:全局唯一ID(uuid) db-column-underline: false refresh-mapper: true configuration: map-underscore-to-camel-case: true cache-enabled: true #配置的缓存的全局开关 lazyLoadingEnabled: true #延时加载的开关 multipleResultSetsEnabled: true #开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句,调试用
如果这时候你启动报错了,不要怀疑,你没有添加阿里连接池的jar包
最后创建controller
@RestController public class OrderController { @Autowired private OrderMapper orderMapper; @RequestMapping(value = "/insert") public String insert(){ for (int i = 0; i < 10; i++) { Order order = new Order(); order.setUserId(i); order.setOrderId( i); orderMapper.insert(order); } for (int i = 10; i < 20; i++) { Order order = new Order(); order.setUserId( i + 1); order.setOrderId( i); orderMapper.insert(order); } return "成功了!"; } @RequestMapping(value = "/test") public String test(){ return "连通!"; } }
启动,请求localhost:3306/insert显示成功,mybatisplus优势就是这么牛逼,不用写sql语句。
接下来就是接入shardingjdbc实现分表操作。
说实话shardingjdbc还是很简单操作的,配置上只需要将数据源的spring改为sharding
导入jar包
<dependency> <groupId>com.dangdang</groupId> <artifactId>sharding-jdbc-config-spring</artifactId> <version>1.5.4.1</version> </dependency> <dependency> <groupId>io.shardingjdbc</groupId> <artifactId>sharding-jdbc-core</artifactId> <version>2.0.3</version> </dependency>
配置数据源
package com.example.demo.config; import com.alibaba.druid.pool.DruidDataSource; import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory; import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule; import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule; import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule; import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy; import com.example.demo.util.SequenceUtil; import com.mysql.jdbc.Driver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.support.TransactionTemplate; import javax.sql.DataSource; import java.sql.SQLException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @Configuration @EnableTransactionManagement @ConditionalOnClass(DruidDataSource.class) @EnableConfigurationProperties(ShardDataSourceProperties.class) public class ShardDataSourceConfig { private final static String order = "order"; @Autowired private ShardDataSourceProperties shardDataSourceProperties; @Bean public DataSource dataSource() throws SQLException { return ShardingDataSourceFactory.createDataSource(shardingRule()); } private DataSource ds() throws SQLException { DruidDataSource ds = parentDs(); return ds; } private DruidDataSource parentDs() throws SQLException { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(shardDataSourceProperties.getDriverClassName()); ds.setUrl(shardDataSourceProperties.getUrl()); ds.setUsername(shardDataSourceProperties.getUsername()); ds.setPassword(shardDataSourceProperties.getPassword()); ds.setFilters(shardDataSourceProperties.getFilters()); ds.setMaxActive(shardDataSourceProperties.getMaxActive()); ds.setInitialSize(shardDataSourceProperties.getInitialSize()); ds.setMaxWait(shardDataSourceProperties.getMaxWait()); ds.setMinIdle(shardDataSourceProperties.getMinIdle()); ds.setTimeBetweenEvictionRunsMillis(shardDataSourceProperties.getTimeBetweenEvictionRunsMillis()); ds.setMinEvictableIdleTimeMillis(shardDataSourceProperties.getMinEvictableIdleTimeMillis()); ds.setValidationQuery(shardDataSourceProperties.getValidationQuery()); ds.setTestWhileIdle(shardDataSourceProperties.isTestWhileIdle()); ds.setTestOnBorrow(shardDataSourceProperties.isTestOnBorrow()); ds.setTestOnReturn(shardDataSourceProperties.isTestOnReturn()); ds.setPoolPreparedStatements(shardDataSourceProperties.isPoolPreparedStatements()); ds.setMaxPoolPreparedStatementPerConnectionSize( shardDataSourceProperties.getMaxPoolPreparedStatementPerConnectionSize()); ds.setRemoveAbandoned(shardDataSourceProperties.isRemoveAbandoned()); ds.setRemoveAbandonedTimeout(shardDataSourceProperties.getRemoveAbandonedTimeout()); ds.setLogAbandoned(shardDataSourceProperties.isLogAbandoned()); ds.setConnectionInitSqls(shardDataSourceProperties.getConnectionInitSqls()); ds.setConnectionProperties(shardDataSourceProperties.getConnectionProperties()); return ds; } private DataSourceRule getDataSourceRule() throws SQLException { Map<String, DataSource> dataSourceMap = new HashMap<>(2); dataSourceMap.put("ds", ds()); DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap); return dataSourceRule; } private TableRule getOrderTableRule() throws SQLException {
//我就建了两张表order_0和order_1,如有需要可以调整数组大小 String[] uns = new String[2]; for (int i = 0; i < 2; i++) { uns[i] = order.concat("_").concat(String.valueOf(i)); }
// for (int i = 10; i <= 99; i++) {
// uns[i] = order.concat("_").concat(String.valueOf(i));
// }
TableRule tableRule = TableRule.builder(order).actualTables(Arrays.asList(uns)) .dataSourceRule(getDataSourceRule()) .tableShardingStrategy(new TableShardingStrategy("user_id", new UserIdShardingAlgorithm())).build(); return tableRule; } private ShardingRule shardingRule() throws SQLException { ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(getDataSourceRule()) .tableRules(Arrays.asList(getOrderTableRule())).build(); return shardingRule; } }
package com.example.demo.config; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "sharding.jdbc") public class ShardDataSourceProperties { private String driverClassName; private String url; private String username; private String password; private String filters; private int maxActive; private int initialSize; private int maxWait; private int minIdle; private int timeBetweenEvictionRunsMillis; private int minEvictableIdleTimeMillis; private String validationQuery; private boolean testWhileIdle; private boolean testOnBorrow; private boolean testOnReturn; private boolean poolPreparedStatements; private int maxPoolPreparedStatementPerConnectionSize; private boolean removeAbandoned; private int removeAbandonedTimeout; private boolean logAbandoned; private List<String> connectionInitSqls; private String connectionProperties; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getFilters() { return filters; } public void setFilters(String filters) { this.filters = filters; } public int getMaxActive() { return maxActive; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public int getInitialSize() { return initialSize; } public void setInitialSize(int initialSize) { this.initialSize = initialSize; } public int getMaxWait() { return maxWait; } public void setMaxWait(int maxWait) { this.maxWait = maxWait; } public int getMinIdle() { return minIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public int getTimeBetweenEvictionRunsMillis() { return timeBetweenEvictionRunsMillis; } public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } public int getMinEvictableIdleTimeMillis() { return minEvictableIdleTimeMillis; } public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } public String getValidationQuery() { return validationQuery; } public void setValidationQuery(String validationQuery) { this.validationQuery = validationQuery; } public boolean isTestWhileIdle() { return testWhileIdle; } public void setTestWhileIdle(boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; } public boolean isTestOnBorrow() { return testOnBorrow; } public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } public boolean isTestOnReturn() { return testOnReturn; } public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } public boolean isPoolPreparedStatements() { return poolPreparedStatements; } public void setPoolPreparedStatements(boolean poolPreparedStatements) { this.poolPreparedStatements = poolPreparedStatements; } public int getMaxPoolPreparedStatementPerConnectionSize() { return maxPoolPreparedStatementPerConnectionSize; } public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) { this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; } public boolean isRemoveAbandoned() { return removeAbandoned; } public void setRemoveAbandoned(boolean removeAbandoned) { this.removeAbandoned = removeAbandoned; } public int getRemoveAbandonedTimeout() { return removeAbandonedTimeout; } public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { this.removeAbandonedTimeout = removeAbandonedTimeout; } public boolean isLogAbandoned() { return logAbandoned; } public void setLogAbandoned(boolean logAbandoned) { this.logAbandoned = logAbandoned; } public List<String> getConnectionInitSqls() { return connectionInitSqls; } public void setConnectionInitSqls(List<String> connectionInitSqls) { this.connectionInitSqls = connectionInitSqls; } public String getConnectionProperties() { return connectionProperties; } public void setConnectionProperties(String connectionProperties) { this.connectionProperties = connectionProperties; } }
分片逻辑
package com.example.demo.config; import java.util.Collection; import java.util.LinkedHashSet; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm; import com.google.common.collect.Range; /** * */ public class UserIdShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer> { @Override public String doEqualSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) { for (String each : tableNames) { if (each.endsWith(shardingValue.getValue()%2+"")) { return each; } } throw new IllegalArgumentException(); } @Override public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) { Collection<String> result = new LinkedHashSet<>(tableNames.size()); for (Integer value : shardingValue.getValues()) { for (String tableName : tableNames) { if (tableName.endsWith(value%2+"")) { result.add(tableName); } } } return result; } @Override public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Integer> shardingValue) { Collection<String> result = new LinkedHashSet<>(tableNames.size()); Range<Integer> range = shardingValue.getValueRange(); for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) { for (String each : tableNames) { if (each.endsWith(i%2+"")) { result.add(each); } } } return result; } }
再次执行controller里的insert会发现分表成功了
以上是关于springboot+mybatisplus,再加入shardingjdbc分表玩法的主要内容,如果未能解决你的问题,请参考以下文章
MyBatisPlus新版本SpringBoot集成MyBatisPlus主键生成策略
MyBatisPlus新版本SpringBoot集成MyBatisPlus主键生成策略
MyBatisPlus新版本SpringBoot集成MyBatisPlus主键生成策略
MyBatisPlus新版本SpringBoot集成MyBatisPlus主键生成策略