分布式事务-03-单体应用分库多数据源改造

需要多库的原因

什么情况下需要多库呢?数据库不够用的时候。

如果应用的用户不断增长,数据量也不断增长,单一数据库的数据量较大(问题来了,多少算较大?),数据库查询成了瓶颈的时候,那么就需要分库分表。

数据量推测

假设是流量充值应用场景。

假设100万注册用户

访问量:一天3万次流量充值

调用接口最少数量:

  1. 进入流量充值界面
  2. 显示流量充值的金额
  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亿订单数据。

当用户量更大的时候,数据量更大,数据库访问不是瓶颈,但是数据库的空间大小成为瓶颈。

数据拆分

一般而言,是按照数据量分库分表,把数据量均匀分布到多个数据库中。
但刚开始就以最简单的按业务来拆分库。

资金、流量券、促销、积分、流量套餐、抽奖、充值订单,分别使用独立的数据库服务器,各个表的数据放在自己的服务器上,使用自己的磁盘空间,这样可以初步的先延长一下我们数据库的使用的周期。

单体应用多数据源改造

  1. 根据业务先建立多个库,再把每个业务对应的表移过去
  2. 设置多个数据源
  3. 把mapper分到各个package里
  4. 在application.yml中,配置相应的参数,便于@Value("${activity.datasource.url}") 获取到参数
  5. 配置mapperscan
  6. @Bean(name = "activityTransactionManager")
  7. @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();
    }   
    
}
上一篇:Spring框架之事务


下一篇:2022年京东春晚摇一摇分15亿红包活动