当前位置: 首页 > wzjs >正文

个人制作网站关键词是怎么排名的

个人制作网站,关键词是怎么排名的,网站用动态图片做背景怎么写,苏州市住房和城乡建设局网站在 Spring Boot 中配置多数据源是一个非常常见的需求,主要用于以下场景: 读写分离:一个主数据库(Master)负责写操作,一个或多个从数据库(Slave)负责读操作,以提高性能和可…

在 Spring Boot 中配置多数据源是一个非常常见的需求,主要用于以下场景:

  • 读写分离:一个主数据库(Master)负责写操作,一个或多个从数据库(Slave)负责读操作,以提高性能和可用性。
  • 业务拆分:不同的业务模块使用不同的数据库(例如,用户库、订单库、商品库)。
  • 连接异构数据库:同时连接 MySQL、PostgreSQL 等不同类型的数据库。

下面我将详细介绍两种主流的实现方式:

  1. 静态方式(推荐用于业务隔离场景):通过包路径区分不同的数据源,配置简单,结构清晰。
  2. 动态方式(推荐用于读写分离场景):使用 AOP 和自定义注解,在方法级别动态切换数据源,更灵活。

方案一:静态方式(按包路径隔离)

这种方式的核心思想是为每个数据源创建一套独立的配置(DataSource, SqlSessionFactory, TransactionManager),并使用 @MapperScan 注解扫描不同包路径下的 Mapper 接口,将它们绑定到对应的数据源上。

1. 添加依赖 (pom.xml)

确保有以下依赖。通常 Spring Boot Starter 会包含大部分。

<dependencies><!-- Spring Boot Web Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis-Plus Starter --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version> <!-- 请使用较新版本 --></dependency><!-- MySQL Driver --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Connection Pool (HikariCP is default) --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency>
</dependencies>
2. 配置文件 (application.yml)

为不同的数据源定义各自的连接信息,并用不同的前缀区分。

spring:datasource:# 主数据源配置 (master)master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_master?serverTimezone=UTCusername: rootpassword: your_passwordtype: com.zaxxer.hikari.HikariDataSource # 指定连接池类型# 从数据源配置 (slave)slave:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3307/db_slave?serverTimezone=UTCusername: rootpassword: your_passwordtype: com.zaxxer.hikari.HikariDataSource
3. 创建数据源配置类

为每个数据源创建一个 Java 配置类。

主数据源配置 (MasterDataSourceConfig.java)

package com.example.config.datasource;import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;@Configuration
// 扫描 Master 库的 Mapper 接口
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionTemplateRef = "masterSqlSessionTemplate")
public class MasterDataSourceConfig {@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")@Primary // 标记为主数据源public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "masterSqlSessionFactory")@Primarypublic SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();bean.setDataSource(dataSource);// 如果有 XML 文件,指定位置// bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/master/*.xml"));return bean.getObject();}@Bean(name = "masterTransactionManager")@Primarypublic DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "masterSqlSessionTemplate")@Primarypublic SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}

从数据源配置 (SlaveDataSourceConfig.java)

package com.example.config.datasource;import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;@Configuration
// 扫描 Slave 库的 Mapper 接口
@MapperScan(basePackages = "com.example.mapper.slave", sqlSessionTemplateRef = "slaveSqlSessionTemplate")
public class SlaveDataSourceConfig {@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveSqlSessionFactory")public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();bean.setDataSource(dataSource);// bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/slave/*.xml"));return bean.getObject();}@Bean(name = "slaveTransactionManager")public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "slaveSqlSessionTemplate")public SqlSessionTemplate slaveSqlSessionTemplate(@Qualifier("slaveSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}
4. 创建 Mapper 接口

将不同数据源的 Mapper 接口放到各自的包下。

  • com.example.mapper.master -> UserMasterMapper.java
  • com.example.mapper.slave -> OrderSlaveMapper.java
5. 使用

现在你可以在 Service 中直接注入并使用对应的 Mapper,Spring 会自动为它们关联正确的数据源。

@Service
public class MyService {@Autowiredprivate UserMasterMapper userMasterMapper; // 操作 master 库@Autowiredprivate OrderSlaveMapper orderSlaveMapper; // 操作 slave 库public void doSomething() {// ...userMasterMapper.insert(someUser); // 写入主库Order order = orderSlaveMapper.selectById(1); // 从从库读取}
}

优点:配置隔离,结构非常清晰,不会混淆。
缺点:如果一个 Service 方法需要同时操作两个库,代码会稍微复杂,且默认的 @Transactional 不能跨数据源生效。


方案二:动态方式(AOP + 自定义注解)

这种方式更灵活,适用于读写分离等需要在同一个 Service 中切换数据源的场景。

1. 配置文件 (application.yml)

与方案一相同。

2. 创建自定义注解

创建一个注解,用于标记方法应该使用哪个数据源。

package com.example.config.dynamic;import java.lang.annotation.*;@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {String value() default "master"; // 默认使用 master 数据源
}
3. 创建数据源上下文持有者

使用 ThreadLocal 来存储当前线程需要使用的数据源 Key。

package com.example.config.dynamic;public class DataSourceContextHolder {private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();public static void setDataSourceKey(String key) {CONTEXT_HOLDER.set(key);}public static String getDataSourceKey() {return CONTEXT_HOLDER.get();}public static void clearDataSourceKey() {CONTEXT_HOLDER.remove();}
}
4. 创建动态数据源类

继承 AbstractRoutingDataSource,重写 determineCurrentLookupKey 方法,从 DataSourceContextHolder 获取当前数据源 Key。

package com.example.config.dynamic;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceKey();}
}
5. 创建AOP切面

创建一个切面,拦截 @DataSource 注解,在方法执行前设置数据源 Key,在方法执行后清除它。

package com.example.config.dynamic;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Aspect
@Component
@Order(1) // 保证该AOP在@Transactional之前执行
public class DataSourceAspect {@Pointcut("@annotation(com.example.config.dynamic.DataSource)")public void dsPointCut() {}@Around("dsPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();DataSource dataSource = method.getAnnotation(DataSource.class);// 设置数据源if (dataSource != null) {DataSourceContextHolder.setDataSourceKey(dataSource.value());}try {return point.proceed();} finally {// 清除数据源,防止内存泄漏DataSourceContextHolder.clearDataSourceKey();}}
}
6. 整合数据源配置

创建一个统一的配置类来管理所有数据源。

package com.example.config;import com.example.config.dynamic.DynamicDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DynamicDataSourceConfig {@Bean(name = "masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}@Bean@Primary // 必须!将动态数据源设置为主数据源public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterDataSource);targetDataSources.put("slave", slaveDataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 设置默认数据源return dynamicDataSource;}
}

注意:这种方式下,SqlSessionFactoryTransactionManager 只需要配置一个,并让它们使用这个 @PrimaryDynamicDataSource 即可。Spring Boot 会自动配置好。

7. 使用

在 Service 方法上添加 @DataSource 注解来切换数据源。

@Service
public class ProductService {@Autowiredprivate ProductMapper productMapper;// 默认不加注解,使用 master 数据源(因为我们配置了默认值)@Transactional // 事务仍然有效public void addProduct(Product product) {productMapper.insert(product);}// 显式指定使用 slave 数据源@DataSource("slave")public Product getProductById(Integer id) {return productMapper.selectById(id);}
}

重要提醒:关于事务

  • 单数据源事务:在以上两种方案中,只要 DataSourceTransactionManagerSqlSessionFactory 绑定的是同一个 DataSource@Transactional 注解就能正常工作。在动态方案中,事务管理器绑定的是 DynamicDataSource,它能确保事务在当前线程选择的数据源上生效。
  • 跨数据源事务(分布式事务):标准的 @Transactional 无法管理跨多个数据源的事务。如果你需要在同一个方法中对 masterslave 都进行写操作,并保证它们的原子性,你需要引入 JTA(Java Transaction API)事务管理器,例如 AtomikosNarayana。这会增加配置的复杂度。

总结

  • 如果你的业务模块和数据库绑定关系固定,方案一(静态方式) 更简单、更直观。
  • 如果你需要实现读写分离,或者在业务逻辑中频繁切换数据源,方案二(动态方式) 提供了更高的灵活性。
http://www.dtcms.com/wzjs/302507.html

相关文章:

  • 广东高端网站建设公司如何让新网站被收录
  • 北京网站建设公司收购手机百度搜索
  • 又拍网站怎么做semir森马
  • 国外教育网站模板搜索引擎优化的技巧有哪些
  • 西安网站建设有那些公司怎么做线上推广
  • 做任务得佣金的网站网页制作培训教程
  • 网站首页设计过程信息推广服务
  • 做电影网站挣钱吗在线工具网站
  • 要找做冲压件的厂去哪个网站找网络营销是学什么的
  • 用闲置的安卓手机做网站企业品牌网站营销
  • 做网站和做app哪个难中小企业网站
  • 要录制课堂上学生讨论的声音应该选用优化课程设置
  • 网站设计外包协议惠州seo报价
  • 郑州网站开发工程师做互联网推广的公司
  • 做网站v1认证是什么意思营销推广策划
  • wordpress公众号验证码seo免费课程视频
  • 网站 404 错误页面是否自动跳转市场推广策略
  • 石家庄小学网站建设seo网站推广目的
  • 广州哪家公司做网站站内推广方式有哪些
  • 网站开发说明书最新的即时比分
  • 怎样做网站教程游戏代理
  • 装饰设计网站什么叫网络营销
  • vue Wordpress淘宝优化
  • 龙港哪里有做阿里巴巴网站汽车网站建设
  • 视频上传网站如何做百度手机助手下载安卓
  • 网站开发留言板能够免费换友链的平台
  • 付费做SPaSS统计分析的网站1688官网
  • 网站建设特色百度浏览器官网下载
  • 电子商务网站模板页面营销策划机构
  • 网站网页切换怎么做上海seo服务