0
点赞
收藏
分享

微信扫一扫

《分布式 + 国产数据库 + Docker:技术选型避坑指南》(四)

一、为什么要做 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)验证流程
  1. 服务注册验证:登录 Nacos(http://localhost:8848/nacos),在「服务列表」中能看到user-service(状态为 UP);
  2. 接口测试(用 Postman)
  • 新增用户:POST http://localhost:8081/user/add,请求体{"username":"test","phone":"13800138000"};
  • 查询详情:GET http://localhost:8081/user/get/1(返回新增的用户数据);
  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」的搭建,下一篇将聚焦微服务间的通信问题,实战内容包括:

  1. 新建「订单服务」,用 OpenFeign 调用「用户服务」的接口;
  2. 部署 Gateway 网关,实现「统一入口 + 路由转发」;
  3. 解决跨服务调用的「超时控制」和「异常处理」问题。

现在你已经拥有一个能注册到 Nacos、并操作 TiDB 的微服务,跟着下一篇实战,就能实现多服务协同工作!

举报

相关推荐

0 条评论