Skip to content
DAILY QUOTE

“ ”

实体类与@TableId

作用:

@TableId(type=IdType.AUTO)
private Long id;

IdType.AUTO表示主键由数据库自增生成。

也就是说,Java在执行insert时,不主动给id赋值,而是把数据交给MYSQL,由MYSQL根据表中的AUTO_INCREMENT规则生成主键。

也就是把主键的生成交给了数据库。

优点:

  1. 简单,不需要Java自己维护 ID
  2. 单库单表场景下,能保证主键不重复
  3. MySQL 自增机制成熟,适合普通业务表

但如果时分布式系统、多库多表、高并发写入等场景,数据库自增ID可能遇到:

  1. 单点依赖数据库
  2. 分库分表时ID不好统一
  3. 暴露数据增长趋势
  4. 高并发下自增锁可能成为瓶颈

故在复杂场景优先考虑雪花算法、号段模式、Redis自增等其他ID生成方案。

Mapper层:查数据库实现

  • 核心原因:动态代理

在MyBatis中,我们通常只写Mapper接口:

java
@Mapper
public interface UserMapper extends BaseMapper<User>{
}

但没有实现类,程序却可以正常执行:

java
userMapper.selectById(1L);

因为MyBatis地城使用了动态代理机制

  • Mapper接口本质:

Mapper接口本身只是声明方法,他告诉MyBatis:这个接口里有哪些数据库操作方法,但真正的执行逻辑时MyBatis在运行时创建的代理对象完成的。

运行流程:

Spring 启动

扫描到 @Mapper 接口

MyBatis 为这个接口创建代理对象

Controller / Service 调用 Mapper 方法

代理对象拦截方法调用

找到对应 SQL

执行 SQL

把结果封装成实体类返回

Service层:接口与实现类

常规写法:

java
public interface UserService extends IService<User> {
}
java
@Service
public class UserServiceImpl
        extends ServiceImpl<UserMapper, User>
        implements UserService {
}
  • 接口存在的意义:

分层规范: Controller不应该直接操作Mapper,而应该调用Service

java
Controller

Service

Mapper

Database

解耦: Controller依赖的是接口,

java
private final UserService userService;

而不是直接依赖实现类

java
private final UserServiceImpl userServiceImpl;

好处:以后实现方式变了,比如

JAVA
1. 本地 Service 实现
2. 远程 RPC 实现
3. 缓存增强实现
4. 不同数据库实现

只要UserService接口不变,Controller基本不用改

方便SpringAop与事务管理

Spring很多功能,比如

java
@Transactional
日志切面
权限校验
性能监控
缓存增强

底层都依赖代理机制

Service是业务逻辑集中的地方,所以AOP通常加载Service层

java
@Transactional
public void createOrder() {
    // 创建订单
    // 扣减库存
    // 写入日志
}

Spring会为Service创建代理对象,在方法执行前后增加事务逻辑

读取设计

查询购物车列表,通常不只需要购物车表数据,还需要商品表数据。

购物车表可能有:

java
cart_id
user_id
product_id
quantity

商品表可能有:

java
product_id
product_name
price
image
stock

前端需要的是一个完整展示对象,比如:

java
商品名称
商品图片
商品价格
购买数量
小计金额

这就需要把购物车比数据与商品数据组合起来。

  • 使用SQL JOIN 直接使用多表查询:
java
SELECT c.id, c.quantity, p.name, p.price, p.image
FROM cart c
JOIN product p ON c.product_id = p.id
WHERE c.user_id = ?

一次就能查出完整结果,但复杂JOIN会增加数据库压力,SQL维护成本可能变高。

  • 代码缝合 也可以分两步查询:
java
1. 先查购物车表,拿到 product_id
2. 再查商品表,拿到商品信息
3. 在 Java Service 层组装成 VO 返回给前端

流程:

java
查询购物车列表

提取商品ID集合

批量查询商品信息

转成 Map

遍历购物车数据

组装 CartVO

返回前端

大型项目应减少复杂JOIN,原因:

java
1. 数据库 CPU 和内存资源比较宝贵
2. 复杂 JOIN 可能影响索引使用
3. 数据库不容易像 Java 服务一样水平扩展
4. 分库分表后跨库 JOIN 很麻烦
5. Service 层组装更方便加缓存、权限控制和业务逻辑

将一部分计算和拼接压力交给Java应用服务器,减轻数据库压力。