96SEO 2026-02-19 22:46 17
。

多租户是一种软件架构技术#xff0c;它允许一个应用程序实例为多个租户提供服务。
每个租户都有自己的数据和配置#xff0c;但应用程序实例是共享的。
而在我们的Spring
在如今的软件开发中多租户(Multi-Tenancy)应用已经变得越来越常见。
多租户是一种软件架构技术它允许一个应用程序实例为多个租户提供服务。
每个租户都有自己的数据和配置但应用程序实例是共享的。
而在我们的Spring
动态数据源实现多租户分库的原理主要是通过切换不同的数据库连接来实现。
对于每个租户应用程序会使用一个独立的数据库连接这样每个租户就拥有了自己的数据隔离空间。
具体来说当我们创建一个新的租户时我们同时也为这个租户创建一个新的数据库连接。
这些数据库连接被存储在一个数据源工厂中我们可以根据租户的ID或者其他唯一标识符来获取对应的数据库连接。
当一个租户需要访问其数据时我们从数据源工厂中获取该租户对应的数据库连接然后使用这个连接来执行数据库操作。
xmlnshttp://maven.apache.org/POM/4.0.0
xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.1.3.RELEASE/versionrelativePath/
--/parentgroupIdcom.bc/groupIdartifactIddemo/artifactIdversion0.0.1-SNAPSHOT/versionnamedemo/namedescriptionDemo
Boot/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.hibernate/groupIdartifactIdhibernate-validator/artifactIdversion6.0.1.Final/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.0/versionscopeprovided/scope/dependencydependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.25/version/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.3.1/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.33/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project
jdbc:mysql://127.0.0.1:3306/demo?useUnicodetruecharacterEncodingutf8serverTimezoneUTCusername:
com.zaxxer.hikari.HikariDataSource
classpath:mapper/*.xmlmybatis-plus:configuration:log-impl:
org.apache.ibatis.logging.stdout.StdOutImpl
在demo库中新建一张名为“tenant_datasource”的表用于存储多租户的数据源配置信息
然后执行下述SQL往“tenant_datasource”表中插入一些测试数据
values(tenant1,jdbc:mysql://localhost:3306/tenant1_db,root,123456);
values(tenant2,jdbc:mysql://localhost:3306/tenant2_db,root,123456);
在tenant1_db库中新建一张名为“user”的表用于存储多租户1的用户信息
然后执行下述SQL往tenant1_db库在的“user”表中插入一些测试数据
在tenant2_db库中新建一张名为“user”的表用于存储多租户2的用户信息
然后执行下述SQL往tenant2_db库在的“user”表中插入一些测试数据
com.baomidou.mybatisplus.annotation.IdType;
com.baomidou.mybatisplus.annotation.TableField;
com.baomidou.mybatisplus.annotation.TableId;
com.baomidou.mybatisplus.annotation.TableName;
com.baomidou.mybatisplus.annotation.IdType;
com.baomidou.mybatisplus.annotation.TableField;
com.baomidou.mybatisplus.annotation.TableId;
com.baomidou.mybatisplus.annotation.TableName;
org.springframework.boot.jdbc.DataSourceBuilder;import
DataSourceBuilder.create().url(this.url).username(this.username).password(this.password).build();}
org.springframework.boot.context.properties.ConfigurationProperties;
org.springframework.stereotype.Component;Data
com.baomidou.mybatisplus.core.mapper.BaseMapper;
org.springframework.stereotype.Repository;Repository
com.baomidou.mybatisplus.core.mapper.BaseMapper;
com.example.demo.entity.TenantDataSource;
org.springframework.stereotype.Repository;Repository
在启动类配置扫描路径MapperScan(com.example.demo.mapper)
org.mybatis.spring.annotation.MapperScan;
org.springframework.boot.SpringApplication;
org.springframework.boot.autoconfigure.SpringBootApplication;MapperScan(com.example.demo.mapper)
{SpringApplication.run(DemoApplication.class,
com.example.demo.mapper.UserMapper;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.stereotype.Service;Service
userMapper.selectById(id);return
org.springframework.beans.factory.annotation.Autowired;
org.springframework.boot.jdbc.DataSourceBuilder;
org.springframework.stereotype.Component;import
javax.annotation.PostConstruct;
dynamicDataSourceProperties;private
DataSourceBuilder.create().url(dynamicDataSourceProperties.getUrl()).username(dynamicDataSourceProperties.getUsername()).password(dynamicDataSourceProperties.getPassword()).build();dataSources.put(default,
dataSources.get(tenantId);}public
lombok.extern.slf4j.Slf4j;Slf4j
使用ThreadLocal来存储当前线程的数据源名称(租户标识)保证多线程情况下各自的数据源互不影响private
{tenantId.set(id);log.info(已切换到数据源:{},
{tenantId.remove();log.info(已切换回默认数据源);}
创建一个动态数据源类继承AbstractRoutingDataSource用于动态切换数据源
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;Slf4j
如果希望所有数据源在启动配置时就加载好这里通过设置数据源Key值来切换数据源**
org.springframework.beans.factory.annotation.Autowired;
org.springframework.context.annotation.Bean;
org.springframework.context.annotation.Configuration;
org.springframework.jdbc.datasource.DataSourceTransactionManager;import
创建数据源配置类用于配置动态数据源*/Configuration
1、将数据源default设置为默认数据源DynamicDataSource
DynamicDataSource();dynamicDataSource.setDefaultTargetDataSource(dataSourceManager.getDataSource(default));//
2、获取初始化时所有的数据源并设置目标数据源必须为targetDataSources设置初始值否则会报错MapObject,
HashMap();targetDataSources.putAll(dataSourceManager.getAllDataSources());dynamicDataSource.setTargetDataSources(targetDataSources);return
transactionManager(DynamicDataSource
DataSourceTransactionManager(dynamicDataSource);}
com.example.demo.entity.TenantDataSource;
com.example.demo.mapper.TenantDataSourceMapper;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.stereotype.Service;import
javax.annotation.PostConstruct;
dataSourceManager;Autowiredprivate
dynamicDataSource;Autowiredprivate
tenantDataSourceMapper;PostConstructpublic
1、从默认的数据源中查询出所有的租户信息然后覆盖DynamicDataSource中的targetDataSources属性MapObject,
tenantDataSourceMapper.selectList(null);for
{dataSourceManager.addDataSource(tenantDataSource.getTenantId(),
tenantDataSource.createDataSource());}targetDataSources.putAll(dataSourceManager.getAllDataSources());dynamicDataSource.setTargetDataSources(targetDataSources);//
2、必须执行此操作才会重新初始化AbstractRoutingDataSource中的resolvedDataSources也只有这样动态切换数据源才会起效dynamicDataSource.afterPropertiesSet();}
十五、构建拦截器并将其注册到InterceptorRegistry中
com.example.demo.config.DataSourceManager;
com.example.demo.config.TenantContext;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.context.annotation.Configuration;
org.springframework.web.servlet.HandlerInterceptor;import
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;Configuration
dataSourceManager;Overridepublic
dataSourceManager.containDataSourceKey(tenantId)
{TenantContext.setTenantId(tenantId);return
afterCompletion(HttpServletRequest
com.example.demo.Interceptor.AuthInterceptor;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.context.annotation.Configuration;
org.springframework.web.servlet.config.annotation.InterceptorRegistry;
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;Configuration
addInterceptors(InterceptorRegistry
{registry.addInterceptor(authInterceptor);}
com.example.demo.serivice.UserService;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.web.bind.annotation.GetMapping;
org.springframework.web.bind.annotation.PathVariable;
org.springframework.web.bind.annotation.RestController;RestController
userService;GetMapping(/user/{userId})public
userService.getUserById(userId);}
启动应用程序通过访问localhost:10086/user/{userId}
可以看到上述测试示例中已经实现了不同的租户查询独立的数据库信息。
多租户系统开发适用于多租户系统每个租户有独立的数据库通过动态数据源切换实现多租户数据隔离。
租户级数据隔离当多个租户共享同一应用但需要数据隔离时可以通过此模式实现。
灵活扩展适用于系统需求可能动态扩展租户每个租户有独立数据库的场景不需修改系统架构。
数据隔离性强每个租户有独立的数据库数据隔离保护租户数据安全。
性能优化每个租户有独立的数据库避免多租户共享同一数据库的性能瓶颈。
方便扩展可以轻松实现动态增加新租户每个租户有独立的数据库。
可维护性高MyBatisPlus提供了便捷的操作数据库的功能减少开发人员的工作量。
易用性强Spring
Boot集成MyBatisPlus简化了配置和集成流程提高开发效率。
Plus结合通过动态数据源实现多租户分库是一种高效、灵活、易维护的解决方案适用于多租户系统的开发。
可以有效地保护租户数据安全提高系统性能同时具有良好的可扩展性和可维护性。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback