基于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的原理与hibernate在某些方面是一致的,先回顾一下Hibernate原理(原理主要上是要掌握并理解下列六个对象: Hibernate中重要的六个对象: Configuration:读取配置文件(主要指hibernate-config.
1374 0
|
存储 关系型数据库 Java
mybatis: 利用多数据源实现分库存储
之前写过一篇mybatis 使用经验小结 提到过多数据源的处理方式,虽然简单但是姿势不太优雅,今天介绍一些更美观的办法: spring中有一个AbstractRoutingDataSource的抽象类可以很好的支持多数据源,我们只需要继续它即可。
876 0
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
106 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
54 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
295 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
1月前
|
SQL Java 数据库连接
mybatis使用二:springboot 整合 mybatis,创建开发环境
这篇文章介绍了如何在SpringBoot项目中整合Mybatis和MybatisGenerator,包括添加依赖、配置数据源、修改启动主类、编写Java代码,以及使用Postman进行接口测试。
17 0
mybatis使用二:springboot 整合 mybatis,创建开发环境
|
1月前
|
Java 数据库连接 API
springBoot:后端解决跨域&Mybatis-Plus&SwaggerUI&代码生成器 (四)
本文介绍了后端解决跨域问题的方法及Mybatis-Plus的配置与使用。首先通过创建`CorsConfig`类并设置相关参数来实现跨域请求处理。接着,详细描述了如何引入Mybatis-Plus插件,包括配置`MybatisPlusConfig`类、定义Mapper接口以及Service层。此外,还展示了如何配置分页查询功能,并引入SwaggerUI进行API文档生成。最后,提供了代码生成器的配置示例,帮助快速生成项目所需的基础代码。
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
1月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
43 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
1月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
127 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码