需要多库的原因
什么情况下需要多库呢?数据库不够用的时候。
如果应用的用户不断增长,数据量也不断增长,单一数据库的数据量较大(问题来了,多少算较大?),数据库查询成了瓶颈的时候,那么就需要分库分表。
数据量推测
假设是流量充值应用场景。
假设100万注册用户
访问量:一天3万次流量充值
调用接口最少数量:
- 进入流量充值界面
- 显示流量充值的金额
- 完成支付
可以假设,每天调用的次数最少为:3万次 * 3 = 9万次接口的调用,认为一天大约10万次接口调用。
高峰时期调用数量
高峰时间段:中午2小时,晚上2小时,假设一天高峰是4小时。
高峰承载量:假设承载80%的请求数量,即10万 * 80% = 8万次。
高峰每秒请求次数:每小时2万次调用,2万 / 3600 = 5.5,大约5/s。
高峰数据库写入量:以订单数计算,一天3万条,一个月150万数据,一年就是2000万订单数据
假设1000万注册用户
假设就是100万用户放大十倍,那么每年至少2亿订单数据。
当用户量更大的时候,数据量更大,数据库访问不是瓶颈,但是数据库的空间大小成为瓶颈。
数据拆分
一般而言,是按照数据量分库分表,把数据量均匀分布到多个数据库中。
但刚开始就以最简单的按业务来拆分库。
资金、流量券、促销、积分、流量套餐、抽奖、充值订单,分别使用独立的数据库服务器,各个表的数据放在自己的服务器上,使用自己的磁盘空间,这样可以初步的先延长一下我们数据库的使用的周期。
单体应用多数据源改造
- 根据业务先建立多个库,再把每个业务对应的表移过去
- 设置多个数据源
- 把mapper分到各个package里
- 在application.yml中,配置相应的参数,便于
@Value("${activity.datasource.url}")
获取到参数 - 配置mapperscan
- @Bean(name = "activityTransactionManager")
- @Primary 这个注解只要一个bean写,不写或者在多个配置bean里写都不行
改完测试功能是否完整
@Configuration
@MapperScan(basePackages = "com.zhss.data.refill.center.mapper.activity",
sqlSessionFactoryRef = "activitySqlSessionFactory")
public class ActivityDataSourceConfig {
@Value("${activity.datasource.url}")
private String dbUrl;
@Value("${activity.datasource.username}")
private String username;
@Value("${activity.datasource.password}")
private String password;
@Value("${activity.datasource.driverClassName}")
private String driverClassName;
@Value("${activity.datasource.initialSize}")
private int initialSize;
@Value("${activity.datasource.minIdle}")
private int minIdle;
@Value("${activity.datasource.maxActive}")
private int maxActive;
@Value("${activity.datasource.maxWait}")
private int maxWait;
@Value("${activity.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${activity.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${activity.datasource.validationQuery}")
private String validationQuery;
@Value("${activity.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${activity.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${activity.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${activity.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${activity.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${activity.datasource.filters}")
private String filters;
@Value("${activity.datasource.connectionProperties}")
private String connectionProperties;
/**
* 创建druid数据库连接池bean
* @return
*/
@Bean(name = "activityDataSource")
@Primary
public DataSource activityDataSource(){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
@Bean(name = "activityTransactionManager")
@Primary
public DataSourceTransactionManager activityTransactionManager() {
return new DataSourceTransactionManager(activityDataSource());
}
@Bean(name = "activitySqlSessionFactory")
@Primary
public SqlSessionFactory activitySqlSessionFactory(
@Qualifier("activityDataSource") DataSource activityDataSource) throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(activityDataSource);
return sessionFactory.getObject();
}
}