基于mybatis分库之小试牛刀

简介: 基于mybatis分库之小试牛刀

背景:

数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;另外,由于无法进行分布式式部署,而一台服务器的资源(CPU、磁盘、内存、IO等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。

mybatis分库分表,核心是使用Spring的AbstractRoutingDataSource进行数据源的动态切换、一般有两种方式:一个是基于Mybatis的拦截器插件,一个是基于Spring的AOP的拦截器。

以下基于aop方式小试牛刀:

public enum  DatabaseEnum {
    order1,order2;
}

ShardingContextHolder是通过线程局部变量保存数据源的key值

public class DatabaseContextHolder {
    public static final ThreadLocal<DatabaseEnum> contextHolder = new ThreadLocal<>();
    public static void setDatabaseEnum(DatabaseEnum databaseEnum) {
        contextHolder.set(databaseEnum);
    }
    public static DatabaseEnum getDatabaseEnum() {
        return contextHolder.get();
    }
    public static void clearDatabaseEnum() {
        contextHolder.remove();
    }
}

重写AbstractRoutingDataSource的determineCurrentLookupKey方法

public class DynamicDatasource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseEnum();
    }
}
@Configuration
public class MybatisConfig {
    @Autowired
    private Environment environment;
    @Autowired
    DefaultListableBeanFactory beanFactory;
    @Bean
    public DataSource order1DataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(environment.getProperty("order.sharding.datasource.order_1.driver-class-name"));
        hikariConfig.setJdbcUrl(environment.getProperty("order.sharding.datasource.order_1.jdbc-url"));
        hikariConfig.setUsername(environment.getProperty("order.sharding.datasource.order_1.user-name"));
        hikariConfig.setPassword(environment.getProperty("order.sharding.datasource.order_1.password"));
        hikariConfig.setMinimumIdle(environment.getProperty("order.sharding.datasource.order_1.minimum-idle", Integer.class));
        //
        return new HikariDataSource(hikariConfig);
    }
    @Bean
    public DataSource order2DataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(environment.getProperty("order.sharding.datasource.order_2.driver-class-name"));
        hikariConfig.setJdbcUrl(environment.getProperty("order.sharding.datasource.order_2.jdbc-url"));
        hikariConfig.setUsername(environment.getProperty("order.sharding.datasource.order_2.user-name"));
        hikariConfig.setPassword(environment.getProperty("order.sharding.datasource.order_2.password"));
        hikariConfig.setMinimumIdle(environment.getProperty("order.sharding.datasource.order_2.minimum-idle", Integer.class));
        //
        return new HikariDataSource(hikariConfig);
    }
    @Bean
    @Primary
    public DynamicDatasource datasource(@Qualifier("order1DataSource") DataSource order1Datasource, @Qualifier("order2DataSource") DataSource order2Datasource) {
        Map<Object, Object> map = new HashMap<>();
        map.put(DatabaseEnum.order1, order1Datasource);
        map.put(DatabaseEnum.order2, order2Datasource);
        DynamicDatasource dynamicDatasource = new DynamicDatasource();
        dynamicDatasource.setTargetDataSources(map);
        return dynamicDatasource;
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory(@Autowired DynamicDatasource ds) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(ds);
        sqlSessionFactoryBean.setTypeAliasesPackage(environment.getProperty("order.sharding.mybatis.typeAliasesPackage"));
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(environment.getProperty("order.sharding.mybatis.mapperLocations")));
        //set plugin TODO
        return sqlSessionFactoryBean.getObject();
    }
}

dao层编写

@Mapper
public interface OrderMapper {
    public OrderEntity getByUserId(@Param("userId") int userId,  @Param("shard") ShardingInfo  shardingInfo);
}

aop切面

@Aspect
@Component
public class DataSourceAspect {
    @Before("execution(* com.sq.order.data.service.myDao.*.*(..))")
   public void setDatasourcePgKey(JoinPoint point) {
        Object[] args = point.getArgs();
        for (Object arg : args) {
           if (arg instanceof ShardingInfo) {
               ShardingInfo shardingInfo = (ShardingInfo)arg;
               if (shardingInfo.getShardKey() != null) {
                   int i = Math.floorDiv((shardingInfo.getShardKey() % 512), 256);
                   if (i == 0) {
                       DatabaseContextHolder.setDatabaseEnum(DatabaseEnum.order1);
                       System.out.println("使用数据源 ====== order1");
                   } else {
                       DatabaseContextHolder.setDatabaseEnum(DatabaseEnum.order2);
                       System.out.println("使用数据源 ======= order2");
                   }
               }
           }
       }
   }
}
<?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.sq.order.data.service.myDao.OrderMapper">
    <select id="getByUserId" parameterType="map" resultType="orderEntity">
        select  * FROM  ${shard.dbName}.order where booking_user_id = #{userId}
    </select>
</mapper>

大功告成

相关文章
|
存储 关系型数据库 Java
mybatis: 利用多数据源实现分库存储
之前写过一篇mybatis 使用经验小结 提到过多数据源的处理方式,虽然简单但是姿势不太优雅,今天介绍一些更美观的办法: spring中有一个AbstractRoutingDataSource的抽象类可以很好的支持多数据源,我们只需要继续它即可。
847 0
|
4月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
2月前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
45 1
|
4月前
|
Java 关系型数据库 MySQL
基于ssm实现图书商城(spring+springmvc+mybatis)
基于ssm实现图书商城(spring+springmvc+mybatis)
|
2月前
|
druid Java 数据库连接
Spring Boot3整合MyBatis Plus
Spring Boot3整合MyBatis Plus
46 1
|
4月前
|
Java 数据库连接 Maven
SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!
SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!
|
2月前
|
敏捷开发 监控 前端开发
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
84 0
|
2月前
|
Java Windows Perl
mybatis+spring报错PropertyAccessException 1: org.springframework.beans.MethodInvocationException
mybatis+spring报错PropertyAccessException 1: org.springframework.beans.MethodInvocationException
13 0
|
2月前
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
ssm(Spring+Spring mvc+mybatis)Dao层实现类——DeptDaoImpl
12 0
|
2月前
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
ssm(Spring+Spring mvc+mybatis)Dao接口——IDeptDao
9 0