MybatisPlus 多数据源Mysql +SqlServer分页
时间: 2025-02-22 09:09:41 浏览: 94
### MyBatis Plus 多数据源 MySQL 和 SQL Server 的分页配置与实现
#### 一、项目依赖设置
为了支持多个数据库并简化动态切换逻辑,推荐使用 `dynamic-datasource-spring-boot-starter` 来管理不同类型的数据库连接池。仅需引入此单一的核心依赖即可完成基本的数据源配置工作[^4]。
```xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
```
#### 二、配置文件调整
在 Spring Boot 应用程序的 `application.yml` 或者 `application.properties` 文件中定义主次两个数据源的相关参数,包括但不限于 URL、用户名以及密码等基本信息。对于不同的数据库类型(如 MySQL 和 SQL Server),应当分别指定对应的 JDBC 驱动类名和特定属性。
```yaml
spring:
datasource:
dynamic:
primary: master # 设置默认数据源名称为master
strict: false # 关闭严格模式,允许访问未定义的数据源
datasource:
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 123456
slave:
type: com.microsoft.sqlserver.jdbc.SQLServerDataSource
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://localhost:1433;DatabaseName=slave_db
username: sa
password: 123456
```
#### 三、实体映射设计
针对每种数据库创建相应的实体对象,并通过继承或组合的方式共享公共字段;同时利用 MyBatis Plus 提供的自动填充机制处理时间戳等通用业务逻辑[^1]。
例如,在 MySQL 中有一个名为 `base_adult` 表:
```java
@Table(name = "base_adult")
public class BaseAdult {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
// getter setter 方法省略...
}
```
而在 SQL Server 上则对应着相似结构但可能命名有所区别的表 `Base_Adults`:
```java
@Table(name = "[dbo].[Base_Adults]")
public class SqlServerBaseAdult extends BaseAdult {
// 可能存在的额外字段...
// getter setter 方法省略...
}
```
#### 四、Mapper 接口编写
基于上述实体模型构建 Mapper 接口时需要注意区分具体使用的数据库方言,因为这会影响到最终生成 SQL 语句的形式特别是涉及到 LIMIT 子句的部分[^3]。
对于 MySQL 数据库而言可以直接采用如下方式来实现带条件查询加分页的功能:
```java
@Select("<script>" +
"SELECT * FROM base_adult WHERE 1=1" +
"<if test='name != null and name != \"\"'> AND name=#{name}</if>" +
"</script>")
IPage<BaseAdult> list(IPage<BaseAdult> page, @Param("name") String name);
```
而对于 SQL Server 则需要稍微修改下 SELECT 语句以适应其特有的 TOP N 查询语法:
```java
@Select("<script>" +
"WITH Temp AS (SELECT *, ROW_NUMBER() OVER(ORDER BY ${orderBy}) as rownum FROM [dbo].[Base_Adults]) " +
"SELECT * FROM Temp WHERE rownum BETWEEN #{startRow} AND #{endRow}" +
"<where>" +
"<if test='name != null and name != \"\"'>AND name=#{name}</if>" +
"</where>" +
"</script>")
List<SqlServerBaseAdult> sqlServerList(@Param("startRow") int startRow,
@Param("endRow") int endRow,
@Param("name") String name,
@Param("orderBy") String orderBy);
```
这里值得注意的是,SQL Server 不像 MySQL 支持直接使用 OFFSET-FETCH NEXT 进行分页操作,因此采用了 CTE(Common Table Expression) 结合窗口函数的方法模拟实现了相同的效果。
#### 五、服务层封装
最后一步是在 Service 层面上对以上 DAO 操作进行进一步抽象化包装,使得调用方无需关心底层具体的存储介质差异就能享受到一致性的 API 设计体验。
```java
@Service
public class AdultService {
@Autowired
private BaseAdultMapper adultMapper;
public PageResult queryByName(String name, Integer pageNum, Integer pageSize){
IPage<BaseAdult> page = new Page<>(pageNum,pageSize);
if ("mysql".equals(DynamicDataSourceContextHolder.peek())) {
return convertToPageResult(adultMapper.list(page,name));
} else if ("mssql".equals(DynamicDataSourceContextHolder.peek())){
List<SqlServerBaseAdult> adults = adultMapper.sqlServerList(
(pageNum - 1)*pageSize + 1 ,
pageNum*pageSize ,
name,"id"
);
long total = ((BigInteger)((SimpleJdbcOperations)adultMapper).queryForObject(
"SELECT COUNT(*) FROM [dbo].[Base_Adults]" +
"<where>"+
"<if test='name != null and name != \"\"'>AND name=#{name}</if>"+
"</where>",new MapSqlParameterSource().addValue("name",name),BigInteger.class))
.longValue();
return new PageResult(total,adults);
}
throw new UnsupportedOperationException("Unsupported database type");
}
private static final class PageResult{
private final long totalCount;
private final Collection<?> items;
public PageResult(long totalCount,Collection<?> items){
this.totalCount = totalCount;
this.items = items;
阅读全文
相关推荐






