精选案例:一个基于Spring Boot & MySQL的微型电商系统后端
这个案例将模拟一个真实的电商系统,包含用户管理、商品管理、购物车和订单处理等核心功能,我们将采用当前业界主流的技术栈。
技术栈选型
选择合适的技术栈是项目成功的第一步。
| 类别 | 技术选型 | 说明 |
|---|---|---|
| 核心框架 | Spring Boot 2.7.x / 3.x | 简化Spring应用开发,内嵌Tomcat,自动配置。 |
| 持久层框架 | MyBatis-Plus 3.5.x | MyBatis的增强工具,极大简化CRUD操作,代码生成。 |
| 数据库 | MySQL 8.0 | 主流关系型数据库,性能稳定,生态成熟。 |
| 构建工具 | Maven / Gradle | 项目依赖管理和构建。 |
| 开发工具 | IntelliJ IDEA | 强大的Java IDE,支持Spring Boot。 |
| 测试框架 | JUnit 5, Mockito | 单元测试和模拟测试。 |
| API文档 | Swagger (OpenAPI 3) | 自动生成API文档,方便前后端协作。 |
| 数据库连接池 | HikariCP | Spring Boot 2.x默认,性能卓越。 |
数据库设计
数据库是应用的基石,我们设计一个包含用户、商品、购物车和订单的简单电商数据库。
核心表结构:
-
用户表 (t_user)
id(BIGINT, PK, AI): 用户IDusername(VARCHAR(50), UQ): 用户名password(VARCHAR(100): 密码 (加密存储)nickname(VARCHAR(50)): 昵称email(VARCHAR(100)): 邮箱create_time(DATETIME): 创建时间update_time(DATETIME): 更新时间
-
商品表 (t_product)
id(BIGINT, PK, AI): 商品IDname(VARCHAR(100)): 商品名称description(TEXT): 商品描述price(DECIMAL(10, 2)): 商品价格stock(INT): 库存数量status(TINYINT): 商品状态 (1-上架, 0-下架)create_time(DATETIME): 创建时间update_time(DATETIME): 更新时间
-
购物车表 (t_cart)
id(BIGINT, PK, AI): 购物车项IDuser_id(BIGINT, FK): 关联用户IDproduct_id(BIGINT, FK): 关联商品IDquantity(INT): 商品数量create_time(DATETIME): 创建时间update_time(DATETIME): 更新时间
-
订单表 (t_order)
id(BIGINT, PK, AI): 订单IDorder_no(VARCHAR(64), UQ): 订单号 (业务唯一)user_id(BIGINT, FK): 关联用户IDtotal_amount(DECIMAL(12, 2)): 订单总金额status(TINYINT): 订单状态 (1-待支付, 2-已支付, 3-已发货, 4-已完成, 5-已取消)create_time(DATETIME): 创建时间update_time(DATETIME): 更新时间
-
订单详情表 (t_order_item)
id(BIGINT, PK, AI): 订单详情IDorder_id(BIGINT, FK): 关联订单IDproduct_id(BIGINT, FK): 关联商品IDproduct_name(VARCHAR(100)): 下单时的商品快照product_price(DECIMAL(10, 2)): 下单时的商品价格快照quantity(INT): 商品数量create_time(DATETIME): 创建时间
ER图关系:
- 一个
User可以有多个Cart(一对多) - 一个
User可以有多个Order(一对多) - 一个
Product可以在多个Cart中出现 (一对多) - 一个
Product可以在多个OrderItem中出现 (一对多) - 一个
Order包含多个OrderItem(一对多)
项目结构与核心代码实现
我们采用经典的Maven分层结构。
micro-shop/
├── src/main/java/com/example/microshop/
│ ├── MicroShopApplication.java // 启动类
│ ├── config/ // 配置类
│ ├── controller/ // 控制层 (API入口)
│ ├── service/ // 业务逻辑层
│ │ ├── impl/ // 业务逻辑实现
│ │ └── CartService.java
│ ├── mapper/ // 数据访问层 (MyBatis-Plus)
│ │ ├── UserMapper.java
│ │ ├── ProductMapper.java
│ │ └── ...
│ ├── entity/ // 实体类 (与数据库表对应)
│ │ ├── User.java
│ │ ├── Product.java
│ │ └── ...
│ ├── dto/ // 数据传输对象 (API请求/响应)
│ │ ├── AddToCartDTO.java
│ │ └── ...
│ └── common/ // 通用工具类
├── src/main/resources/
│ ├── application.yml // Spring Boot配置文件
│ ├── mapper/ // MyBatis Mapper XML文件
│ └── schema.sql // 数据库初始化脚本
项目配置 (application.yml)
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/micro_shop?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: your_password
hikari:
maximum-pool-size: 10
minimum-idle: 5
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发环境打印SQL
global-config:
db-config:
id-type: auto # 主键自增
实体类 (entity/Product.java)
使用Lombok简化Getter/Setter等样板代码。
package com.example.microshop.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("t_product") // 指定对应的数据库表
public class Product {
@TableId(type = IdType.AUTO) // 指定主键为自增
private Long id;
private String name;
private String description;
private BigDecimal price;
private Integer stock;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
数据访问层 (mapper/ProductMapper.java)
MyBatis-Plus的Mapper接口继承BaseMapper即可获得强大的CRUD能力。
package com.example.microshop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.microshop.entity.Product;
import org.apache.ibatis.annotations.Mapper;
@Mapper // 声明为MyBatis Mapper接口
public interface ProductMapper extends BaseMapper<Product> {
// BaseMapper已经提供了 selectById, insert, updateById, deleteById 等方法
// 如果有复杂查询,可以在这里定义自定义方法,并在XML中实现
}
业务逻辑层 (service/ProductService.java & service/impl/ProductServiceImpl.java)
定义接口和实现,进行业务逻辑处理,如库存检查、价格计算等。
// ProductService.java (接口)
package com.example.microshop.service;
import com.example.microshop.entity.Product;
import java.util.List;
public interface ProductService {
List<Product> listAllProducts();
Product getProductById(Long id);
boolean reduceStock(Long productId, int quantity); // 减少库存
}
// ProductServiceImpl.java (实现)
package com.example.microshop.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.microshop.entity.Product;
import com.example.microshop.mapper.ProductMapper;
import com.example.microshop.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Override
public List<Product> listAllProducts() {
return productMapper.selectList(new QueryWrapper<>());
}
@Override
public Product getProductById(Long id) {
return productMapper.selectById(id);
}
@Override
@Transactional // 确保操作的原子性
public boolean reduceStock(Long productId, int quantity) {
// 使用乐观锁机制,防止并发问题
Product product = productMapper.selectById(productId);
if (product == null || product.getStock() < quantity) {
throw new RuntimeException("商品库存不足或不存在");
}
product.setStock(product.getStock() - quantity);
int updateResult = productMapper.updateById(product);
return updateResult > 0;
}
}
控制层 (controller/CartController.java)
处理HTTP请求,调用Service层,并返回JSON格式的响应。
package com.example.microshop.controller;
import com.example.microshop.dto.AddToCartDTO;
import com.example.microshop.service.CartService;
import com.example.microshop.common.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/cart")
public class CartController {
@Autowired
private CartService cartService;
@PostMapping("/add")
public R<Void> addToCart(@RequestBody AddToCartDTO addToCartDTO) {
// R 是一个统一的返回对象,{ "code": 200, "message": "success", "data": null }
cartService.addToCart(addToCartDTO);
return R.success();
}
}
关键技术与最佳实践
事务管理
在电商场景下,事务至关重要,创建订单时,需要同时扣减商品库存、清空购物车、生成订单记录,这些操作必须作为一个原子单元,要么全部成功,要么全部失败。
Spring的@Transactional注解提供了声明式事务管理。
// 在Service层的方法上使用
@Transactional
public Order createOrder(Long userId) {
// 1. 检查购物车
// 2. 计算总金额
// 3. 扣减商品库存 (调用ProductService.reduceStock)
// 4. 创建订单记录
// 5. 创建订单详情记录
// 6. 清空用户购物车
// ...
return order;
}
性能优化
- 索引优化:
- 为所有外键 (
user_id,product_id,order_id) 和常用查询条件 (username,status) 建立索引。 CREATE INDEX idx_user_id ON t_cart(user_id);
- 为所有外键 (
- 缓存:
- 对于不常变动的数据,如商品详情,可以使用Redis进行缓存,查询时先查缓存,缓存未命中再查数据库,然后将结果存入缓存。
- 分页查询:
- 商品列表、订单列表等数据量大的查询,必须使用分页,MyBatis-Plus提供了
Page对象和selectPage方法,非常方便。
- 商品列表、订单列表等数据量大的查询,必须使用分页,MyBatis-Plus提供了
// 使用MyBatis-Plus分页 Page<Product> page = new Page<>(current, size); // current: 当前页, size: 每页大小 IPage<Product> productPage = productMapper.selectPage(page, new QueryWrapper<>());
安全性
-
密码加密: 永远不要明文存储密码,使用BCrypt等强哈希算法,Spring Security提供了
BCryptPasswordEncoder。@Autowired private PasswordEncoder passwordEncoder; // 注册时 String encodedPassword = passwordEncoder.encode(rawPassword); user.setPassword(encodedPassword); // 登录时 boolean isMatch = passwordEncoder.matches(rawPassword, encodedPasswordFromDB);
-
SQL注入防护: MyBatis-Plus的参数化查询能有效防止SQL注入,避免使用字符串拼接SQL。
-
接口安全: 对需要登录的接口进行权限校验,可以使用Spring Security或自定义拦截器。
扩展与进阶
- 引入Spring Security: 替换简单的权限校验,提供更完善的认证、授权和会话管理。
- 引入消息队列 (如RabbitMQ/Kafka): 处理耗时操作,如订单创建后的短信通知、邮件发送、日志记录等,实现系统解耦和异步处理。
- 微服务化: 当业务变得复杂时,可以将用户、商品、订单等模块拆分成独立的微服务,通过API Gateway进行统一访问。
- 容器化部署: 使用Docker将应用打包成镜像,再使用Kubernetes进行编排部署,实现弹性伸缩和高可用。
这个微型电商系统案例虽然简单,但它涵盖了Java数据库系统开发的核心要素:
- 技术选型: 稳定且主流的Spring Boot + MyBatis-Plus + MySQL组合。
- 分层架构: 清晰的Controller-Service-Mapper分层,职责分明,易于维护。
- 数据库设计: 合理的表结构和ER关系是系统健壮的基础。
- 核心实践: 事务管理保证数据一致性,性能优化(索引、缓存)保证系统响应速度,安全措施保护系统免受攻击。
通过深入学习和实践这个案例,开发者可以掌握从零开始构建一个完整Java数据库应用的全过程,并有能力将其应用到更复杂的项目中去。
