前篇内容已经实现了spring boot集成mybatis访问MySQL,本篇在此基础上集成sharding-jdbc实现分库分表等功能。
首先创建创建数据库和表。这是sharding-jdbc所要求的。
create database db_201810;
create database db_201811;
use db_201810;
create table gps_20181014(id int not null auto_increment,gprs varchar(16) NOT NULL,sys_time datetime,PRIMARY KEY (id));
create table gps_20181015(id int not null auto_increment,gprs varchar(16) NOT NULL,sys_time datetime,PRIMARY KEY (id));
insert into gps_20181014 values(0,'0123456789012345','2018-10-14 0:0:0');
insert into gps_20181015 values(0,'0123456789012345','2018-10-15 0:0:0');
use db_201811;
create table gps_20181114(id int not null auto_increment,gprs varchar(16) NOT NULL,sys_time datetime,PRIMARY KEY (id));
create table gps_20181115(id int not null auto_increment,gprs varchar(16) NOT NULL,sys_time datetime,PRIMARY KEY (id));
insert into gps_20181114 values(0,'0123456789012345','2018-11-14 0:0:0');
insert into gps_20181115 values(0,'0123456789012345','2018-11-15 0:0:0');
接着是pom.xml文件,添加sharding-jdbc到工程中。主要是下面两个依赖:
完整的pom.xml文件内容如下
4.0.0
com
SpringBootDemo
0.0.1-SNAPSHOT
jar
SpringBootDemo
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.5.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
io.shardingjdbc
sharding-jdbc-core
2.0.3
commons-dbcp
commons-dbcp
1.3
org.springframework.boot
spring-boot-maven-plugin
剩下就是代码了。首先是数据源配置和库策略、表策略:
DataSourceConfig.java
package com.net.config;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.net.config.DatabaseShardingAlgorithm;
import com.net.config.TableShardingAlgorithm;
import io.shardingjdbc.core.api.config.ShardingRuleConfiguration;
import io.shardingjdbc.core.api.config.TableRuleConfiguration;
import io.shardingjdbc.core.api.config.strategy.StandardShardingStrategyConfiguration;
import io.shardingjdbc.core.jdbc.core.datasource.ShardingDataSource;
@Configuration
@MapperScan(basePackages = "com.net.domain", sqlSessionFactoryRef = "sqlSessionFactory")
public class DataSourceConfig {
//配置sharding-jdbc的DataSource,给上层应用使用,这个DataSource包含所有的逻辑库和逻辑表,应用增删改查时,修改对应sql
//然后选择合适的数据库继续操作。因此这个DataSource创建很重要。
@Bean
@Primary
public DataSource shardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
//用户表配置,可以添加多个配置
shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration());
shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration1());
shardingRuleConfig.getBindingTableGroups().add("gps");
//设置数据库策略,传入的是sys_time
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("sys_time", DatabaseShardingAlgorithm.class.getName()));
//设置数据表策略,传入的是sys_time
shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("sys_time", TableShardingAlgorithm.class.getName()));
return new ShardingDataSource(shardingRuleConfig.build(createDataSourceMap()));
}
//创建用户表规则
@Bean
TableRuleConfiguration getUserTableRuleConfiguration() {
TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
orderTableRuleConfig.setLogicTable("gps");
//设置数据节点,格式为dbxx.tablexx。这里的名称要和map的别名一致。下面两种方式都可以
//orderTableRuleConfig.setActualDataNodes("db_${0..1}.gps_${0..1}");
orderTableRuleConfig.setActualDataNodes("db_201810.gps_20181014,db_201810.gps_20181015,db_201811.gps_20181114,db_201811.gps_20181115");
//设置纵列名称
orderTableRuleConfig.setKeyGeneratorColumnName("sys_time");
return orderTableRuleConfig;
}
@Bean
TableRuleConfiguration getUserTableRuleConfiguration1() {
TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
//设置用户表逻辑
orderTableRuleConfig.setLogicTable("tb_user");
//设置数据节点,格式为dbxx.tablexx。这里的名称要和map的别名一致
orderTableRuleConfig.setActualDataNodes("gps_com.tb_user");
return orderTableRuleConfig;
}
//下面函数是获取数据源,即包含有多少个数据库,读入到系统中存放于map中
private Map createDataSourceMap() {
Map result = new HashMap<>();
result.put("gps_com", createDataSource("jdbc:mysql://localhost:3306/gps_com?characterEncoding=utf8&useSSL=false"));
result.put("db_201810", createDataSource("jdbc:mysql://localhost:3306/db_201810?characterEncoding=utf8&useSSL=false"));
result.put("db_201811", createDataSource("jdbc:mysql://localhost:3306/db_201811?characterEncoding=utf8&useSSL=false"));
return result;
}
private DataSource createDataSource(final String dataSourceName) {
//使用默认连接池
BasicDataSource result = new BasicDataSource();
result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
//设置数据库路径
result.setUrl(dataSourceName);
//设置数据库用户名
result.setUsername("root");
//设置数据密码
result.setPassword("123456");
return result;
}
/**
* 需要手动配置事务管理器
*/
@Bean
public DataSourceTransactionManager transactitonManager(DataSource shardingDataSource) {
return new DataSourceTransactionManager(shardingDataSource);
}
//下面是SessionFactory配置,二选一,由类前语句选择 @MapperScan(basePackages = "com.net.domain", sqlSessionFactoryRef = "sqlSessionFactory")
@Bean
@Primary
public SqlSessionFactory sqlSessionFactory(DataSource shardingDataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(shardingDataSource);
return sessionFactory.getObject();
}
}
DatabaseShardingAlgorithm.java
package com.net.config;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
public class DatabaseShardingAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
String db_name="db_";
try {
Date date = (Date) new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(preciseShardingValue.getValue());
String year = String.format("%tY", date);
String mon = String.format("%tm",date);
db_name=db_name+year+mon;
System.out.println("db_name:" + db_name);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (String each : collection) {
System.out.println("db:" + each);
if (each.equals(db_name)) {
return each;
}
}
throw new IllegalArgumentException();
}
}
TableShardingAlgorithm.java
package com.net.config;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
public class TableShardingAlgorithm implements PreciseShardingAlgorithm {
@Override
public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
String tb_name=preciseShardingValue.getLogicTableName() + "_";
try {
Date date = (Date) new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(preciseShardingValue.getValue());
String year = String.format("%tY", date);
String mon = String.format("%tm",date);
String dat = String.format("%td",date);
tb_name=tb_name+year+mon+dat;
System.out.println("tb_name:" + tb_name);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (String each : collection) {
System.out.println("tb:" + each);
if (each.equals(tb_name)) {
return each;
}
}
throw new IllegalArgumentException();
}
}
这时工程结构如图所示:
运行程序,没有问题,浏览器触发访问数据库也能正常访问gps_com的tb_user表。
以上说明集成sharding-jdbc没有问题。至于能访问数据库是由于DataSourceConfig.java中加上了下面代码。
shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration1());
@Bean
TableRuleConfiguration getUserTableRuleConfiguration1() {
TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
//设置用户表逻辑
orderTableRuleConfig.setLogicTable("tb_user");
//设置数据节点,格式为dbxx.tablexx。这里的名称要和map的别名一致
orderTableRuleConfig.setActualDataNodes("gps_com.tb_user");
return orderTableRuleConfig;
}
上面完成了sharding-jdbc的集成,但是还没有真正发挥作用,也就是分库分表的功能。
继续添加代码,最后工程结构图是:
GpsData.java
package com.net.domain;
import java.io.Serializable;
public class GpsData implements Serializable{
private static final long serialVersionUID = 1L;
String gprs;
String sys_time;
public void setGprs(String gprs)
{
this.gprs = gprs;
}
public String getGprs()
{
return this.gprs;
}
public void setSystime(String sys_time)
{
this.sys_time = sys_time;
}
public String getSystime()
{
return this.sys_time;
}
}
GpsDataMapper.java
package com.net.domain;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.net.domain.GpsData;
@Mapper
public interface GpsDataMapper {
@Select("select * from gps where sys_time = #{sys_time}")
List findAll(@Param("sys_time") String sys_time);
}
GpsDataService.java
package com.net.service;
import java.util.List;
import com.net.domain.GpsData;
public interface GpsDataService {
List getAll(String sys_time);
}
GpsDataServiceImpl.java
package com.net.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.net.domain.GpsData;
import com.net.domain.GpsDataMapper;
import com.net.service.GpsDataService;
@Service("gpsDataService")
public class GpsDataServiceImpl implements GpsDataService{
@Autowired
private GpsDataMapper gpsDataMapper;
@Override
public List getAll(String sys_time)
{
return gpsDataMapper.findAll(sys_time);
}
}
最后是测试代码
TestWithWeb.java
package com.net.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.net.domain.User;
import com.net.domain.GpsData;
import com.net.service.GpsDataService;
import com.net.service.UserService;
@RestController
public class TestWithWeb {
@Autowired
@Qualifier("userService")
private UserService userService;
@Autowired
@Qualifier("gpsDataService")
private GpsDataService gpsDataService;
@RequestMapping("/log")
public String login()
{
System.out.println("hello");
User user = userService.login("root", "123456");
System.out.println(user.toString());
List GpsData_list = gpsDataService.getAll("2018-11-14 0:0:0");
System.out.println(GpsData_list.get(0).getGprs());
System.out.println(GpsData_list.get(0).getSystime());
return "OK";
}
}
代码展示结束,开始运行测试。
测试语句:gpsDataService.getAll("2018-11-14 0:0:0");
结果如下:
由于在代码里面直接配置了数据源,所以application.properties里面关于数据库的信息不起作用,可以直接去掉。
结束。