一、为什么要做 Spring Cloud Alibaba+TiDB 整合?
1. 分布式架构的必然需求
- 单体架构用 MySQL 单机足够,但微服务拆分后,多服务并发操作数据会面临「数据一致性」和「水平扩容」问题;
- TiDB 的分布式特性(自动分片、水平扩容)能匹配微服务的弹性需求,避免单库瓶颈;
- Spring Cloud Alibaba 作为国内主流微服务框架,与 TiDB 的 MySQL 兼容性完美适配,开发几乎无需改代码。
2. 整合核心目标
- 实现「服务注册(Nacos)+TiDB 数据存储」的完整微服务雏形;
- 解决 TiDB 在分布式场景下的「连接池优化」和「SQL 适配」问题;
- 产出可直接复用的项目模板,后续微服务可直接基于此扩展。
二、前置准备:确认环境与依赖版本(避坑第一步)
1. 环境要求(必须匹配,否则会出兼容性问题)
组件 | 版本要求 | 验证方式 |
JDK | 11 | java -version输出 11.x.x |
Spring Boot | 2.7.10(LTS 稳定版) | pom.xml 中指定<version>2.7.10</version> |
Spring Cloud Alibaba | 2021.0.5.0 | 对应 Spring Boot 2.7.x 版本 |
TiDB | 7.0(已在第二篇部署) | mysql -h 127.0.0.1 -P 4000 -u root可连接 |
Nacos | 2.2.3(Docker 版,后续部署) | 暂无需提前安装,本篇会同步部署 |
2. 核心依赖清单(pom.xml 关键配置)
<!-- 1. Spring Boot父依赖 --><parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.10</version> <relativePath/></parent><!-- 2. Spring Cloud Alibaba依赖管理 --><dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2021.0.5.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement><!-- 3. 核心功能依赖 --><dependencies> <!-- 服务注册与发现(Nacos) --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- Web支持(接口开发) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- TiDB连接(兼容MySQL JDBC) --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> <!-- 必须8.0+,适配TiDB 7.0 --> </dependency> <!-- MyBatis整合 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.3.0</version> </dependency> <!-- 连接池(HikariCP,Spring Boot默认) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- 工具类(简化开发) --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.20</version> </dependency></dependencies>三、实战步骤:从 0 到 1 搭建「用户服务 + TiDB」
1. 第一步:Docker 部署 Nacos(服务注册中心)
因为是微服务,必须先有注册中心,这里用 Docker 快速部署 Nacos:
# 1. 启动Nacos(单机模式,默认账号nacos/nacos)docker run -d -p 8848:8848 -e MODE=standalone --name nacos-server nacos/nacos-server:v2.2.3# 2. 验证:访问http://localhost:8848/nacos,能登录即成功2. 第二步:配置 TiDB 连接与服务注册(application.yml)
server: port: 8081 # 用户服务端口spring: # 1. 服务注册到Nacos cloud: nacos: discovery: server-addr: localhost:8848 # Nacos地址 service: user-service # 服务名(后续调用用) # 2. TiDB数据源配置(兼容MySQL,无需改驱动) datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:4000/test_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true # 说明:test_db是TiDB中创建的数据库(需提前执行CREATE DATABASE test_db;) username: root # TiDB默认无密码,若设置过则填密码 password: "" # 3. HikariCP连接池优化(针对TiDB分布式特性) hikari: maximum-pool-size: 10 # 最大连接数(TiDB单节点建议≤20,避免连接过载) minimum-idle: 2 # 最小空闲连接 idle-timeout: 300000 # 空闲连接超时(5分钟) connection-timeout: 30000 # 连接超时(30秒) connection-test-query: SELECT 1 # 心跳检测(TiDB支持)# 4. MyBatis配置mybatis: mapper-locations: classpath:mapper/**/*.xml # Mapper文件路径 type-aliases-package: com.example.user.entity # 实体类包路径 configuration: map-underscore-to-camel-case: true # 下划线转驼峰(适配数据库字段)3. 第三步:创建 TiDB 数据表(用户表)
用 MySQL 客户端连接 TiDB,执行建表 SQL(TiDB 支持 InnoDB 引擎,自动分布式存储):
USE test_db;CREATE TABLE `user` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID(分布式自增)', `username` VARCHAR(50) NOT NULL COMMENT '用户名', `phone` VARCHAR(20) UNIQUE COMMENT '手机号', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间') ENGINE=InnoDB COMMENT '用户表(TiDB分布式表)';4. 第四步:开发核心业务代码(Entity+Mapper+Service+Controller)
(1)实体类(User.java)
package com.example.user.entity;import lombok.Data;import java.time.LocalDateTime;@Datapublic class User { private Long id; private String username; private String phone; private LocalDateTime createTime; private LocalDateTime updateTime;}(2)Mapper 接口(UserMapper.java)
package com.example.user.mapper;import com.example.user.entity.User;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper // 必须加此注解,MyBatis才会扫描public interface UserMapper { // 新增用户 int insert(User user); // 根据ID查询 User selectById(@Param("id") Long id); // 分页查询(适配TiDB分页,用LIMIT) List<User> selectPage(@Param("offset") int offset, @Param("size") int size); // 更新用户 int updateById(User user); // 删除用户 int deleteById(@Param("id") Long id);}(3)Mapper XML 文件(UserMapper.xml,放在 resources/mapper 下)
<?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.example.user.mapper.UserMapper"> <!-- 新增 --> <insert id="insert" useGeneratedKeys="true" keyProperty="id"> INSERT INTO user (username, phone) VALUES (#{username}, #{phone}) </insert> <!-- 查询详情 --> <select id="selectById" resultType="com.example.user.entity.User"> SELECT id, username, phone, create_time, update_time FROM user WHERE id = #{id} </select> <!-- 分页查询(TiDB支持LIMIT,无需特殊处理) --> <select id="selectPage" resultType="com.example.user.entity.User"> SELECT id, username, phone, create_time, update_time FROM user LIMIT #{offset}, #{size} </select> <!-- 更新 --> <update id="updateById"> UPDATE user SET username = #{username}, phone = #{phone} WHERE id = #{id} </update> <!-- 删除 --> <delete id="deleteById"> DELETE FROM user WHERE id = #{id} </delete></mapper>(4)Service 层(UserService.java)
package com.example.user.service;import com.example.user.entity.User;import com.example.user.mapper.UserMapper;import org.springframework.stereotype.Service;import javax.annotation.Resource;import java.util.List;@Servicepublic class UserService { @Resource private UserMapper userMapper; // 新增 public boolean addUser(User user) { return userMapper.insert(user) > 0; } // 详情 public User getUserById(Long id) { return userMapper.selectById(id); } // 分页 public List<User> getUserPage(int pageNum, int pageSize) { int offset = (pageNum - 1) * pageSize; return userMapper.selectPage(offset, pageSize); } // 更新 public boolean updateUser(User user) { return userMapper.updateById(user) > 0; } // 删除 public boolean deleteUser(Long id) { return userMapper.deleteById(id) > 0; }}(5)Controller 层(UserController.java)
package com.example.user.controller;import com.example.user.entity.User;import com.example.user.service.UserService;import cn.hutool.core.bean.BeanUtil;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;import java.util.List;import java.util.Map;@RestController@RequestMapping("/user")public class UserController { @Resource private UserService userService; // 新增用户 @PostMapping("/add") public String add(@RequestBody User user) { return userService.addUser(user) ? "新增成功" : "新增失败"; } // 查询详情 @GetMapping("/get/{id}") public User get(@PathVariable Long id) { return userService.getUserById(id); } // 分页查询 @GetMapping("/page") public List<User> page(@RequestParam int pageNum, @RequestParam int pageSize) { return userService.getUserPage(pageNum, pageSize); } // 更新用户 @PostMapping("/update") public String update(@RequestBody User user) { return userService.updateUser(user) ? "更新成功" : "更新失败"; } // 删除用户 @DeleteMapping("/delete/{id}") public String delete(@PathVariable Long id) { return userService.deleteUser(id) ? "删除成功" : "删除失败"; }}5. 第五步:启动服务并验证
(1)启动类(UserApplication.java)
package com.example.user;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication@EnableDiscoveryClient // 开启服务注册(Spring Cloud Alibaba必需)public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); }}(2)验证流程
- 服务注册验证:登录 Nacos(http://localhost:8848/nacos),在「服务列表」中能看到user-service(状态为 UP);
- 接口测试(用 Postman):
- 新增用户:POST http://localhost:8081/user/add,请求体{"username":"test","phone":"13800138000"};
- 查询详情:GET http://localhost:8081/user/get/1(返回新增的用户数据);
- TiDB 数据验证:用 MySQL 客户端执行SELECT * FROM test_db.user;,能看到新增的数据,说明整合成功。
四、避坑指南:整合中最容易踩的 3 个坑
1. 坑 1:依赖版本不兼容(最常见)
- 现象:启动报错NoSuchMethodError或ClassNotFoundException;
- 原因:Spring Boot 与 Spring Cloud Alibaba 版本不匹配(比如 Spring Boot 3.x 配了 2021.x 的 Alibaba);
- 解决:严格按本文的版本组合(Spring Boot 2.7.10 + Alibaba 2021.0.5.0),或参考官方版本对应表。
2. 坑 2:TiDB 连接超时 / 拒绝连接
- 现象:启动报错Communications link failure;
- 原因 1:TiDB 容器没启动,执行docker-compose ps查看 tidb 服务状态;
- 原因 2:JDBC URL 写错(比如端口写成 3306,TiDB 默认是 4000);
- 解决:先通过mysql -h 127.0.0.1 -P 4000 -u root验证 TiDB 可连接,再核对 URL。
3. 坑 3:MyBatis 扫描不到 Mapper
- 现象:报错No qualifying bean of type 'com.example.user.mapper.UserMapper' available;
- 原因 1:没加@Mapper注解(在 UserMapper 接口上必须加);
- 原因 2:application.yml 中mapper-locations路径写错(比如少写了classpath:);
- 解决:检查注解和路径,或在启动类加@MapperScan("com.example.user.mapper")批量扫描。
五、下一篇预告:分布式通信实战(OpenFeign+Gateway)
本篇完成了「单个微服务 + TiDB」的搭建,下一篇将聚焦微服务间的通信问题,实战内容包括:
- 新建「订单服务」,用 OpenFeign 调用「用户服务」的接口;
- 部署 Gateway 网关,实现「统一入口 + 路由转发」;
- 解决跨服务调用的「超时控制」和「异常处理」问题。
现在你已经拥有一个能注册到 Nacos、并操作 TiDB 的微服务,跟着下一篇实战,就能实现多服务协同工作!










