杰瑞科技汇

Java数据库开发案例如何精选?

精选案例:一个基于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默认,性能卓越。

数据库设计

数据库是应用的基石,我们设计一个包含用户、商品、购物车和订单的简单电商数据库。

核心表结构:

  1. 用户表 (t_user)

    • id (BIGINT, PK, AI): 用户ID
    • username (VARCHAR(50), UQ): 用户名
    • password (VARCHAR(100): 密码 (加密存储)
    • nickname (VARCHAR(50)): 昵称
    • email (VARCHAR(100)): 邮箱
    • create_time (DATETIME): 创建时间
    • update_time (DATETIME): 更新时间
  2. 商品表 (t_product)

    • id (BIGINT, PK, AI): 商品ID
    • name (VARCHAR(100)): 商品名称
    • description (TEXT): 商品描述
    • price (DECIMAL(10, 2)): 商品价格
    • stock (INT): 库存数量
    • status (TINYINT): 商品状态 (1-上架, 0-下架)
    • create_time (DATETIME): 创建时间
    • update_time (DATETIME): 更新时间
  3. 购物车表 (t_cart)

    • id (BIGINT, PK, AI): 购物车项ID
    • user_id (BIGINT, FK): 关联用户ID
    • product_id (BIGINT, FK): 关联商品ID
    • quantity (INT): 商品数量
    • create_time (DATETIME): 创建时间
    • update_time (DATETIME): 更新时间
  4. 订单表 (t_order)

    • id (BIGINT, PK, AI): 订单ID
    • order_no (VARCHAR(64), UQ): 订单号 (业务唯一)
    • user_id (BIGINT, FK): 关联用户ID
    • total_amount (DECIMAL(12, 2)): 订单总金额
    • status (TINYINT): 订单状态 (1-待支付, 2-已支付, 3-已发货, 4-已完成, 5-已取消)
    • create_time (DATETIME): 创建时间
    • update_time (DATETIME): 更新时间
  5. 订单详情表 (t_order_item)

    • id (BIGINT, PK, AI): 订单详情ID
    • order_id (BIGINT, FK): 关联订单ID
    • product_id (BIGINT, FK): 关联商品ID
    • product_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分页
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或自定义拦截器。


扩展与进阶

  1. 引入Spring Security: 替换简单的权限校验,提供更完善的认证、授权和会话管理。
  2. 引入消息队列 (如RabbitMQ/Kafka): 处理耗时操作,如订单创建后的短信通知、邮件发送、日志记录等,实现系统解耦和异步处理。
  3. 微服务化: 当业务变得复杂时,可以将用户、商品、订单等模块拆分成独立的微服务,通过API Gateway进行统一访问。
  4. 容器化部署: 使用Docker将应用打包成镜像,再使用Kubernetes进行编排部署,实现弹性伸缩和高可用。

这个微型电商系统案例虽然简单,但它涵盖了Java数据库系统开发的核心要素

  • 技术选型: 稳定且主流的Spring Boot + MyBatis-Plus + MySQL组合。
  • 分层架构: 清晰的Controller-Service-Mapper分层,职责分明,易于维护。
  • 数据库设计: 合理的表结构和ER关系是系统健壮的基础。
  • 核心实践: 事务管理保证数据一致性,性能优化(索引、缓存)保证系统响应速度,安全措施保护系统免受攻击。

通过深入学习和实践这个案例,开发者可以掌握从零开始构建一个完整Java数据库应用的全过程,并有能力将其应用到更复杂的项目中去。

分享:
扫描分享到社交APP
上一篇
下一篇