校园商铺平台从零搭建:数据库表设计与实体类建模全解析
校园商铺平台简单说就是让每个同学在校园里都能开店卖点自己的东西——二手教材、自制手工艺品、零食代购、专业课资料买家逛到店铺下单付款卖家发货收货后台还能管管商品和订单。这个系列我不想用网上那些现成的“课程项目”糊弄人而是从最底层开始一行代码一个表结构地搭起来。第一期先把整个项目的地基打牢实体类设计和数据库表的创建。你可以把这个项目理解成一个微缩版电商系统但比那种几十个微服务的电商项目实在得多。它覆盖了单表CRUD、多表联查、事务、状态流转、文件上传这些Java后端开发里最高频的能力。这一期不写Controller也不写Service只做两件事把所有核心业务表设计出来把对应实体类写出来。表设计烂了后面代码怎么写怎么别扭这个坑我踩过太多次所以第一期绕不过去。这篇文章我会把用户、店铺、商品、分类、订单这几张核心表从字段到类型逐一拆开讲给出完整的建表SQL再把表怎么映射成实体类、MyBatis逆向工程怎么用、以及从SSM项目转Spring Boot后到底哪些配置文件没了全部讲清楚。适合正在学SSM想往Spring Boot过渡的同学也适合准备做课设、毕设或个人实战项目的朋友参考。1. 项目定位与整体拆解1.1 校园商铺平台到底在做什么先别急着碰技术得先把业务想明白。校园商铺平台里有三类角色买家、卖家和平台管理员。买家可以浏览店铺、查看商品、下单购买、查看自己的订单卖家可以申请开店、管理自己店里的商品和订单管理员负责审核店铺、上下架违规商品。核心业务流程是一条闭环卖家注册账号申请开店、管理员审核通过、卖家发布商品买家注册登录逛店、把商品加入订单、下单付款卖家收到订单去发货买家确认收货。整个过程涉及的所有数据最后都要落到数据库表里。选这个项目练手有一个很现实的原因它既不是那种“只写一张用户表”的玩具项目也不是那种复杂到你根本写不完的企业级系统。它正好处在一个中间位置——每个业务模块单独看不难但是连起来就涉及非常典型的关联关系和数据一致性处理比如一个订单包含多个商品下单要扣库存退款要回滚库存这里面的坑足够你学到东西。1.2 为什么从SSM起步又落到Spring BootSSM是Spring、SpringMVC、MyBatis三个框架各司其职的组合在我读书那个年代它几乎是Java后端课设的标配。SSM本身没有大问题问题在于配置太折磨人。你要手工配web.xml配Spring容器配SpringMVC的DispatcherServlet再配一份mybatis-config.xml还要把数据源、事务管理器、扫描包一个个塞进XML里。建一个新项目光是让HelloWorld跑起来可能就要折腾一上午。Spring Boot做的事简单说就是把那些重复的配置全部“自动完成”。内嵌一个Tomcat你不再需要外部部署环境准备、框架版本、常用Bean的创建全部通过starter自动搞定。你从重配置的时代一下子切换到重业务的时代。但这个项目我坚持从SSM的思路出发再落到Spring Boot是因为这样转型会让你真正理解Spring Boot到底帮你做了什么。实体类设计和数据库表设计在这两种技术栈下有一套公用的底层逻辑。一张用户表无论SSM还是Spring Boot字段该是什么还是什么一个实体类无论由XML装配还是通过注解扫描映射关系也不会变。所以第一期内容在两种体系下都成立后面几期我再慢慢把每层往里填。1.3 表设计先行实体类紧随其后很多新手写项目喜欢一上来就建实体类把类里的属性写满然后让数据库去适配Java代码。我的习惯正好反过来先建表再写实体类。数据库表是业务的底层存储你如果把一张表的字段定清楚了实体类就是照葫芦画瓢如果你连业务里有几张表、每张表存什么都不知道那写出来的实体类一定乱七八糟。表结构和实体类之间的关系用一个类比就好理解了表是一栋房子的户型图实体类是装修公司根据户型图画出来的效果图。效果图长什么样取决于户型图怎么画你不能先画效果图再倒推承重墙。在正式建表之前我还会做一个动作先把公共字段一次性加到每张表里。id主键、create_time创建时间、update_time更新时间、deleted逻辑删除标记这四个字段我会在每张核心业务表里都放一份。这样做的收益在后面写通用Mapper、做统一查询条件的时候会非常明显但代价是建表SQL看起来有点重复。重复就重复数据库设计不是代码冗余通用字段比后面补字段返工要划算。2. 开发环境与项目骨架2.1 版本选择和技术栈基调我这次用的是JDK 8、Spring Boot 2.7.x、MySQL 8.0、Maven 3.6。看到这个版本组合你可能会有疑问现在Spring Boot 3都出来好久了为什么不直接上新版原因是SSM项目绝大多数跑在JDK 8上如果你直接从Spring Boot 3入手会遇到一个非常麻烦的底层变化Spring Boot 3要求JDK 17以上而且把javax命名空间换成了jakarta。这意味着你原来在SSM里熟悉的import javax.servlet.到了Boot 3要改成import jakarta.servlet.。新手在最开始就被这个细节卡住会非常打击信心。Spring Boot 2.7.x既保留了完整SSM风格的兼容性又能让你体验到自动配置的便利作为过渡版本是最稳的。MySQL用8.0是因为驱动类名发生了变化老项目用com.mysql.jdbc.Driver8.0以后官方推荐com.mysql.cj.jdbc.Driver而且连接URL必须带时区和SSL相关参数否则启动就报错。这些坑我会在后面的常见问题里展开。2.2 pom.xml依赖怎么配创建Spring Boot项目后pom.xml里最关键的是替换成下面这些依赖parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.2/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency /dependencies看到没有这里完全没有出现版本号全靠spring-boot-starter-parent做统一版本管理。SSM时代你要是想用这几个框架得自己记牢Spring版本、SpringMVC版本、MyBatis版本、MyBatis-Spring适配版本版本号之间稍微不匹配就给你抛一堆奇怪的ClassNotFound现在这份苦基本不用吃了。注意mybatis-spring-boot-starter的groupId是org.mybatis.spring.boot不是org.mybatis这个写错就拉不到包。starter的版本也需要自己指定因为parent只管理Spring官方家族的版本。2.3 application.yml配置和SSM配置文件的差别Spring Boot的核心配置文件就是src/main/resources/application.yml。我第一期版本里配置如下server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/campus_shop?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: root jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.campus.shop.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这段配置里有几个点要重点说。mybatis.mapper-locations指定了XML文件位置如果你把mapper.xml放在了resources/mapper目录但忘了这句配置启动后项目会报Invalid bound statement异常因为MyBatis根本扫描不到SQL语句。map-underscore-to-camel-case必须补上true。数据库字段习惯用user_name这种下划线风格Java实体类习惯用userName这种驼峰风格开启这一项后MyBatis会自动帮你做映射转换否则每个查询你都要手动resultMap写法有多痛苦写过的都知道。serverTimezoneAsia/Shanghai这个参数特别关键。MySQL 8的驱动要求客户端明确告知服务器的时区如果你不写有的环境会直接报错有的环境不报错但时间莫名其妙差8个小时。这个坑在7.1里再展开。SSM时代这些配置分别散落在web.xml、spring.xml、springmvc.xml、mybatis-config.xml四五个文件里现在全部压缩成这一个文件。你体会一下这就叫配置简化。2.4 项目目录结构第一期创建完项目后目录结构是这样的campus-shop/ ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── campus │ │ └── shop │ │ ├── CampusShopApplication.java │ │ ├── entity/ │ │ ├── mapper/ │ │ ├── service/ │ │ ├── controller/ │ │ └── vo/ │ └── resources │ ├── application.yml │ └── mapper/ └── test入口类CampusShopApplication上需要加一个注解MapperScan(com.campus.shop.mapper)没有这句后面写的所有Mapper接口都不会被Spring管理项目启动就直接失败。注意这里不同项目的包名不一样你要改成自己实际的mapper包路径。entity放数据库表对应的实体类mapper放数据库访问接口和XMLservice和controller是后几期往里填的vo放联表查询时用的视图对象。第一期先把entity和mapper准备好即可。3. 用户模块最小的表最大的细节3.1 用户表字段逐一拆解用户表是整个平台最基础的一张表卖家要用、买家要用、管理员也要用几乎所有表都跟它有关联。这张表的设计看起来最简单但里面埋的细节最多。CREATE TABLE tb_user ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, username VARCHAR(32) NOT NULL COMMENT 用户名, password VARCHAR(100) NOT NULL COMMENT 密码, nickname VARCHAR(32) DEFAULT NULL COMMENT 昵称, avatar VARCHAR(255) DEFAULT NULL COMMENT 头像地址, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, email VARCHAR(64) DEFAULT NULL COMMENT 邮箱, user_type TINYINT NOT NULL DEFAULT 0 COMMENT 0-买家 1-卖家, status TINYINT NOT NULL DEFAULT 1 COMMENT 0-禁用 1-正常, deleted TINYINT NOT NULL DEFAULT 0 COMMENT 逻辑删除0-未删 1-已删, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;主键字段我用BIGINT UNSIGNED AUTO_INCREMENT没采用UUID。原因是自增主键在InnoDB的聚簇索引上有顺序写入优势查询时也方便索引UUID虽然看着像是不暴露真实数量但它是随机字符串做主键会导致索引页频繁分裂数据量大以后性能明显下降。校园商铺这种量级完全不需要为了隐藏数据量而牺牲性能和代码复杂度。user_type用TINYINT而不是字符串代表用户类型0是买家1是卖家。这里不用枚举存数据库是因为枚举类型在Java里好写但在数据库里修改枚举值需要执行ALTER TABLE太麻烦了。用TINYINT加注释的方式又轻量又灵活。username字段加了唯一索引UNIQUE KEY因为用户名登录时要查询且不允许重复。但注意密码用的是VARCHAR(100)不是32下面会单独解释。create_time和update_time都给了默认值特别是update_time配合ON UPDATE CURRENT_TIMESTAMP这样你在代码里做UPDATE操作时就不用手动维护更新时间了省心。你可能会觉得这些字段太琐碎但实际开发里时间字段出问题是最多的。3.2 User实体类如何对应表结构表结构定完实体类直接映射过来package com.campus.shop.entity; import lombok.Data; import java.time.LocalDateTime; Data public class User { private Long id; private String username; private String password; private String nickname; private String avatar; private String phone; private String email; private Integer userType; private Integer status; private Integer deleted; private LocalDateTime createTime; private LocalDateTime updateTime; }这里我用了Lombok的Data注解自动生成getter和setter实体类里就看不到一堆冗长的getter/setter代码了。SSM时代很多老项目里你看到实体类几百行全是getter/setter那就是没引入Lombok造成的。如果你要手写记得每个字段都要生成对应的get和set方法漏一个后面赋值全是null。注意类型选择。所有数字状态都用包装类型Integer而不是int。原因非常简单数据库字段如果允许NULL实体类用int去映射拿到null时拆箱会直接抛NullPointerException用Integer就安全得多能表达出没有值这个语义。价格用BigDecimal而不是double时间字段用LocalDateTime而不是java.util.Date这几个选择在后续章节都会展开。还有一个小技巧实体类字段名和数据库字段名不一致时比如数据库是user_name而Java是userName靠的是前面配置的map-underscore-to-camel-case完成自动映射。所以你建表时用下划线命名Java类里用驼峰命名两边风格各取所长这是Java项目最常用的约定不需要额外写映射注解。3.3 密码、状态和逻辑删除的设计讲究密码字段设成VARCHAR(100)刚开始我写的是32因为传统MD5加密后是32位十六进制字符串。后来想明白了如果用BCrypt这类加盐算法加密后的字符串长度是60个字符32完全不够。既然还不知道最终会选哪种算法干脆用100后面怎么换都装得下。密码存储两个原则必须坚持第一绝对不允许明文存库哪怕是在课程设计和个人项目里明文存储一旦数据库泄露所有用户密码裸奔这是事故级别的问题第二加密必须加盐不要直接用MD5裸算用Spring Security里自带的BCryptPasswordEncoder或者自作聪明地拼一个固定盐都行加盐和不加盐的防彩虹表能力差距是数量级的。status字段用来控制账号启停0禁用1正常。deleted字段做逻辑删除。每次查询用户列表时都要记得带上deleted 0条件这个条件写漏了把逻辑删除当成物理删除玩就会出现删了还在的诡异现象。我建议在Mapper的查询SQL里把deleted条件写进where而不是依赖业务层提醒自己去加。逻辑删除的好处是误删了还能恢复数据不会被真正抹掉这在电商场景里非常实用。有同学会问那为什么不直接物理删除逻辑删除不是反而要在每个查询里加条件吗存在即合理逻辑删除是为数据安全和可追溯性服务的。比如你想分析哪些商品是删除过的没有deleted字段你永远不知道答案。4. 店铺和商品一对多关系的核心4.1 店铺表设计店铺表是平台上“卖家侧”的核心。一个用户开店先创建一条店铺记录店铺需要管理员审核后才能营业这个审核状态必须在表里体现。CREATE TABLE tb_shop ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, owner_id BIGINT NOT NULL COMMENT 店铺所有者用户ID, shop_name VARCHAR(64) NOT NULL COMMENT 店铺名称, shop_desc VARCHAR(255) DEFAULT NULL COMMENT 店铺描述, shop_address VARCHAR(255) DEFAULT NULL COMMENT 地址, shop_phone VARCHAR(20) DEFAULT NULL COMMENT 联系电话, logo_url VARCHAR(255) DEFAULT NULL COMMENT 店铺LOGO地址, shop_status TINYINT NOT NULL DEFAULT 0 COMMENT 0-待审核 1-正常 2-禁用, deleted TINYINT NOT NULL DEFAULT 0 COMMENT 逻辑删除, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_owner_id (owner_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT店铺表;owner_id是外键逻辑关联用户的id。我没有在数据库层面加FOREIGN KEY外键约束很多生产环境里的表都这么做理由是外键约束会影响插入性能而且业务层已经保证了引用关系。新手可能很难接受“不建外键”但你要明白外键的本质是数据完整性约束在业务代码里通过事务和逻辑同样能保证这个完整性代价是代码上更自觉一点。店铺状态用了三个值0待审核、1正常、2禁用。为什么不直接用0和1两个状态因为现实业务里必须有审核环节。你如果直接给一个“可营业”和“不可营业”两个状态无法区分“还没提交审核”和“提交了但没通过”后面对管理员的审核列表就没法做。shop_name没有加唯一索引因为不同卖家理论上是可以取重名店铺名的但如果你想限制重名把UNIQUE KEY加在这上面也很容易这个取决于产品规则不是技术问题。4.2 商品分类表设计分类表很容易被忽略但它是商品模块的骨架。没有分类表的话商品表里只能硬编码一个category字段查子分类会变得非常痛苦。CREATE TABLE tb_product_category ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, category_name VARCHAR(32) NOT NULL COMMENT 分类名称, category_desc VARCHAR(255) DEFAULT NULL COMMENT 分类描述, parent_id BIGINT NOT NULL DEFAULT 0 COMMENT 父分类ID0表示顶级分类, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品分类表;parent_id是分类表独有的设计。顶级分类的parent_id记为0二级分类的parent_id记录它所属顶级分类的id。这样设计的好处是分类可以无限级地嵌套下去比如“数码”下面挂“手机”“手机”下面挂“苹果手机”。实体类对应起来也是很直白Data public class ProductCategory { private Long id; private String categoryName; private String categoryDesc; private Long parentId; private LocalDateTime createTime; private LocalDateTime updateTime; }这里我同样没在实体类里写List children这个属性。原因下面专门展开说这也是很多新手项目容易走偏的地方。4.3 商品表设计商品表是店铺和分类两棵树的连接点也是订单数据的数据源。CREATE TABLE tb_product ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, shop_id BIGINT NOT NULL COMMENT 所属店铺ID, category_id BIGINT NOT NULL COMMENT 分类ID, product_name VARCHAR(64) NOT NULL COMMENT 商品名称, product_desc VARCHAR(255) DEFAULT NULL COMMENT 商品描述, product_img VARCHAR(255) DEFAULT NULL COMMENT 商品图片, price DECIMAL(10,2) NOT NULL COMMENT 销售价格, stock INT NOT NULL DEFAULT 0 COMMENT 库存, sales INT NOT NULL DEFAULT 0 COMMENT 销量, product_status TINYINT NOT NULL DEFAULT 1 COMMENT 0-下架 1-上架, deleted TINYINT NOT NULL DEFAULT 0 COMMENT 逻辑删除, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_shop_id (shop_id), KEY idx_category_id (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;商品表的三个核心点是第一个price必须用DECIMAL(10,2)而不是double十进制精确存储金额二进制浮点存金额会出0.1加0.2不等于0.3的问题这个在后面订单模块会再深入第二个stock库存是INT卖出一个扣一个但扣库存的SQL不能简单写成UPDATE tb_product SET stock stock - 1那样并发会超卖需要在WHERE条件里加上stock 0这个细节等实现下单接口那期再写具体SQL第三个sales销量字段是个反范式设计理论上可以从订单表统计但每次统计订单表太慢所以商品表里冗余一个累加字段订单完成时加1。shop_id和category_id都加了普通索引不是为了规范好看是因为后面商品列表经常按店铺查、按分类查没有索引这些查询会走全表扫描数据量稍微上来页面直接就卡了。4.4 Java实体里的一对多怎么写不怎么写到了这里你可能会觉得商品实体类里应该有一个List 属性店铺实体里应该放一个List 的集合这样看起来才面向对象。我建议第一期不要这么写。POJO实体类最好只放数据库里那一行的字段映射一对多关系应该放到VO视图对象里去组装。例如查询店铺详情页你需要返回店铺信息和这个店铺下的商品列表正确的做法是新建一个ShopVO里面包含Shop的字段加上一个List 然后通过一次查询把数据组装出来。原因有三个第一如果实体类里直接放关联集合你查一次用户可能会把他关联的所有订单、所有地址、所有购物车全部加载出来查询性能极差还会出现循环引用问题第二MyBatis在返回实体类时如果你只是单表查询集合属性永远是null你还要花心思去处理它非常尴尬第三实体类保持纯净复用的时候不用考虑这次查出来的User里有没有Orders”逻辑清爽。正确做法是实体类只对应单表联表查询和组合数据放到VO/DTO里在Mapper中单独写方法、单独写resultMap。这个原则从第一期就要养成。5. 订单模块与状态机5.1 订单主表和订单明细表订单模块是整个系统最值得花心思的部分也是表设计里最能体现经验的地方。我用了两张表订单主表和订单明细表。CREATE TABLE tb_order ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_no VARCHAR(32) NOT NULL COMMENT 订单编号, user_id BIGINT NOT NULL COMMENT 下单用户ID, shop_id BIGINT NOT NULL COMMENT 所属店铺ID, total_amount DECIMAL(10,2) NOT NULL COMMENT 订单总金额, order_status TINYINT NOT NULL DEFAULT 0 COMMENT 0-待付款 1-已付款 2-已发货 3-已收货 4-已取消, receiver_name VARCHAR(32) NOT NULL COMMENT 收货人姓名, receiver_phone VARCHAR(20) NOT NULL COMMENT 收货人手机号, receiver_address VARCHAR(255) NOT NULL COMMENT 收货地址, remark VARCHAR(255) DEFAULT NULL COMMENT 买家备注, deleted TINYINT NOT NULL DEFAULT 0, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, pay_time DATETIME DEFAULT NULL COMMENT 付款时间, send_time DATETIME DEFAULT NULL COMMENT 发货时间, receive_time DATETIME DEFAULT NULL COMMENT 收货时间, cancel_time DATETIME DEFAULT NULL COMMENT 取消时间, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id), KEY idx_shop_id (shop_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单主表;订单主表存的是一次订单的整体信息包括下单人、收货信息、总金额、订单状态以及各个关键节点的时间。pay_time、send_time、receive_time、cancel_time这四个字段是时间戳字段它们的作用是记录订单每个重要步骤的完成时间方便后面做超时未支付自动关单、物流超时提醒这些功能。CREATE TABLE tb_order_item ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_id BIGINT NOT NULL COMMENT 订单ID, product_id BIGINT NOT NULL COMMENT 商品ID, product_name VARCHAR(64) NOT NULL COMMENT 商品名称快照, product_img VARCHAR(255) DEFAULT NULL COMMENT 商品图片快照, product_price DECIMAL(10,2) NOT NULL COMMENT 成交单价快照, quantity INT NOT NULL DEFAULT 1 COMMENT 购买数量, subtotal DECIMAL(10,2) NOT NULL COMMENT 小计金额, PRIMARY KEY (id), KEY idx_order_id (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单明细表;注意订单明细表里为什么要冗余product_name、product_img、product_price这些商品字段。你可能会想为什么不直接通过product_id去关联查询商品表因为商品是会变得。卖家改个商品名、调个价格、换张图片如果你订单只存product_id那历史订单显示的名称价格就会跟着商品表变这就完全失真了。买家购买时的商品信息应该是一张“快照”当时是什么样子就是什么样子。这是电商系统里非常经典的冗余设计叫数据快照。以后你写订单导出、对账、开发票功能会发现这些冗余字段能帮你省下无数麻烦。5.2 订单状态机设计订单状态字段用0到4五个数字分别代表0待付款、1已付款、2已发货、3已收货、4已取消。这些数字如果用int散落在代码里时间长了绝对会写错判断条件所以我强烈建议在第一期就定义一个枚举类public enum OrderStatus { UNPAID(0, 待付款), PAID(1, 已付款), SHIPPED(2, 已发货), RECEIVED(3, 已收货), CANCELED(4, 已取消); private final Integer code; private final String desc; OrderStatus(Integer code, String desc) { this.code code; this.desc desc; } public Integer getCode() { return code; } public String getDesc() { return desc; } }状态不是随便乱串的它是一个状态机几条转移路径必须先定死待付款可以变为已付款可以变为已取消。已付款可以变为已发货不允许直接变为已取消。已发货可以变为已收货。已收货是终态。已取消是终态。这些规则在Service层做校验在后端写订单状态流转方法时不要用一堆if else裸写而应该用一个统一的方法接收当前状态、目标状态在方法内判断路径是否合法。这个设计逻辑现在你理解了后几期写订单接口时会非常省力。为什么我不推荐直接用数据库的枚举类型存状态因为MySQL里的ENUM类型修改枚举值需要ALTER TABLE而且与Java层的状态定义不一致会很难排查。TINYINT加注释Java侧用枚举去映射两边各自干自己擅长的事。5.3 金额与库存的硬性约定订单总金额total_amount和明细金额我全部用了DECIMAL(10,2)这是一个一开始就必须定死的约定。任何金额字段不管是价格、总价、小计、退款金额还是优惠金额都不能用float或double。计算机里的二进制浮点数是没法精确表示大多数十进制的你用double做两次运算结果可能是9.999999999打印出来你都能吓一跳。DECIMAL是真正的十进制精确类型在MySQL里就是为金额这种需求准备的。长度选10,2代表整数部分8位小数2位校园商铺这个量级够了。另一个硬性约定是库存。我曾经在处理库存扣减时写过一个看起来没毛病的代码逻辑先查询库存判断库存大于0再UPDATE stock stock - 1。结果高并发下有两个请求同时读到库存是1都认为可以扣最后把库存扣成了负数。正确的方式是把判断条件放到UPDATE语句里UPDATE tb_product SET stock stock - 1 WHERE id #{productId} AND stock 0;这条SQL返回的影响行数是0就说明库存不足。这个设计在表结构层面很早就能确定下来不需要等到写Service那天。6. 建库建表SQL与逆向工程6.1 完整的建库建表SQL把本期设计的表汇总成一份完整SQL文件命名为schema.sql放在项目resources目录下。这里给出完整内容CREATE DATABASE IF NOT EXISTS campus_shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE campus_shop; DROP TABLE IF EXISTS tb_order_item; DROP TABLE IF EXISTS tb_order; DROP TABLE IF EXISTS tb_product; DROP TABLE IF EXISTS tb_product_category; DROP TABLE IF EXISTS tb_shop; DROP TABLE IF EXISTS tb_user; CREATE TABLE tb_user ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, username VARCHAR(32) NOT NULL COMMENT 用户名, password VARCHAR(100) NOT NULL COMMENT 密码, nickname VARCHAR(32) DEFAULT NULL COMMENT 昵称, avatar VARCHAR(255) DEFAULT NULL COMMENT 头像地址, phone VARCHAR(20) DEFAULT NULL COMMENT 手机号, email VARCHAR(64) DEFAULT NULL COMMENT 邮箱, user_type TINYINT NOT NULL DEFAULT 0 COMMENT 0-买家 1-卖家, status TINYINT NOT NULL DEFAULT 1 COMMENT 0-禁用 1-正常, deleted TINYINT NOT NULL DEFAULT 0 COMMENT 逻辑删除标记, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; CREATE TABLE tb_shop ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, owner_id BIGINT NOT NULL COMMENT 店主用户ID, shop_name VARCHAR(64) NOT NULL COMMENT 店铺名称, shop_desc VARCHAR(255) DEFAULT NULL COMMENT 店铺描述, shop_address VARCHAR(255) DEFAULT NULL COMMENT 店铺地址, shop_phone VARCHAR(20) DEFAULT NULL COMMENT 店铺电话, logo_url VARCHAR(255) DEFAULT NULL COMMENT 店铺LOGO, shop_status TINYINT NOT NULL DEFAULT 0 COMMENT 0-待审核 1-正常 2-禁用, deleted TINYINT NOT NULL DEFAULT 0, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_owner_id (owner_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT店铺表; CREATE TABLE tb_product_category ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, category_name VARCHAR(32) NOT NULL COMMENT 分类名称, category_desc VARCHAR(255) DEFAULT NULL COMMENT 分类描述, parent_id BIGINT NOT NULL DEFAULT 0 COMMENT 父分类ID0为顶级, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品分类表; CREATE TABLE tb_product ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, shop_id BIGINT NOT NULL COMMENT 店铺ID, category_id BIGINT NOT NULL COMMENT 分类ID, product_name VARCHAR(64) NOT NULL COMMENT 商品名称, product_desc VARCHAR(255) DEFAULT NULL COMMENT 商品描述, product_img VARCHAR(255) DEFAULT NULL COMMENT 商品图片, price DECIMAL(10,2) NOT NULL COMMENT 价格, stock INT NOT NULL DEFAULT 0 COMMENT 库存, sales INT NOT NULL DEFAULT 0 COMMENT 销量, product_status TINYINT NOT NULL DEFAULT 1 COMMENT 0-下架 1-上架, deleted TINYINT NOT NULL DEFAULT 0, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_shop_id (shop_id), KEY idx_category_id (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表; CREATE TABLE tb_order ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_no VARCHAR(32) NOT NULL COMMENT 订单编号, user_id BIGINT NOT NULL COMMENT 买家ID, shop_id BIGINT NOT NULL COMMENT 店铺ID, total_amount DECIMAL(10,2) NOT NULL COMMENT 总金额, order_status TINYINT NOT NULL DEFAULT 0 COMMENT 0-待付款 1-已付款 2-已发货 3-已收货 4-已取消, receiver_name VARCHAR(32) NOT NULL COMMENT 收货人, receiver_phone VARCHAR(20) NOT NULL COMMENT 收货电话, receiver_address VARCHAR(255) NOT NULL COMMENT 收货地址, remark VARCHAR(255) DEFAULT NULL COMMENT 备注, deleted TINYINT NOT NULL DEFAULT 0, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, pay_time DATETIME DEFAULT NULL, send_time DATETIME DEFAULT NULL, receive_time DATETIME DEFAULT NULL, cancel_time DATETIME DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id), KEY idx_shop_id (shop_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表; CREATE TABLE tb_order_item ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_id BIGINT NOT NULL COMMENT 订单ID, product_id BIGINT NOT NULL COMMENT 商品ID, product_name VARCHAR(64) NOT NULL COMMENT 商品名称快照, product_img VARCHAR(255) DEFAULT NULL COMMENT 商品图片快照, product_price DECIMAL(10,2) NOT NULL COMMENT 成交单价快照, quantity INT NOT NULL DEFAULT 1 COMMENT 数量, subtotal DECIMAL(10,2) NOT NULL COMMENT 小计金额, PRIMARY KEY (id), KEY idx_order_id (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单明细表;执行这份SQL时有个顺序问题带外键逻辑关系的表要先删子表再删父表这里没有物理外键约束但DROP TABLE的顺序依然按依赖关系从强到弱排列。tb_order_item依赖tb_ordertb_product依赖tb_shoptb_shop依赖tb_user所以倒序删除最安全。数据库字符集一定要用utf8mb4而不是utf8。MySQL里的utf8最多3字节存emoji表情会报错utf8mb4是完整4字节对utf8的超集。现在不知道什么时候用户就会在昵称里放个表情提前用utf8mb4能省一个以后的大坑。6.2 用逆向工程生成实体类建完表之后MyBatis提供的一套逆向工程工具可以帮我们批量生成实体类、Mapper接口和XML文件。配置一个generatorConfig.xml放在resources下?xml version1.0 encodingUTF-8? !DOCTYPE generatorConfiguration PUBLIC -//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd generatorConfiguration context idcampusShopContext targetRuntimeMyBatis3Simple jdbcConnection driverClasscom.mysql.cj.jdbc.Driver connectionURLjdbc:mysql://localhost:3306/campus_shop?serverTimezoneAsia/Shanghai userIdroot passwordroot/ javaModelGenerator targetPackagecom.campus.shop.entity targetProjectsrc/main/java/ sqlMapGenerator targetPackagemapper targetProjectsrc/main/resources/ javaClientGenerator typeXMLMAPPER targetPackagecom.campus.shop.mapper targetProjectsrc/main/java/ table tableNametb_user domainObjectNameUser/ table tableNametb_shop domainObjectNameShop/ table tableNametb_product_category domainObjectNameProductCategory/ table tableNametb_product domainObjectNameProduct/ table tableNametb_order domainObjectNameOrder/ table tableNametb_order_item domainObjectNameOrderItem/ /context /generatorConfiguration然后在pom.xml里加插件plugin groupIdorg.mybatis.generator/groupId artifactIdmybatis-generator-maven-plugin/artifactId version1.4.0/version configuration configurationFilesrc/main/resources/generatorConfig.xml/configurationFile overwritetrue/overwrite verbosetrue/verbose /configuration dependencies dependency groupIdmysql/groupId artifactIdmysql-connector-j/artifactId version8.0.33/version /dependency /dependencies /plugin执行mvn mybatis-generator:generate它会自动为每张表生成一个对应实体类、一个Mapper接口和一个XML文件。这个工具的价值在于快速生成最基础的CRUD方法比如selectByPrimaryKey、insert、updateByPrimaryKey、deleteByPrimaryKey。但必须清醒认识到逆向工程只帮你解决“表怎么映射成实体”的重复劳动复杂联表查询、动态条件SQL、批量插入它一概不管。比如订单查询需要联表把商品快照带出来还是得手写XML里的大段SQL。工具是加速器不是替代品。关于targetProject路径用src/main/java这种相对路径时如果你是用IDEA直接执行Maven命令大概率没问题如果在命令行执行且路径报错改成绝对路径src/main/java或者直接指定targetProjectsrc/main/java对应的完整文件路径即可这个报错很常见见到了别慌。6.3 从SSM到Spring Boot的配置差异清单这一期最核心的目标就是搞清楚SSM和Spring Boot的差异。实体类没有变Mapper接口没有变Service和Controller的写法也没有伤筋动骨真正变掉的是装配方式。我把差异做成了一张表配置项SSM传统方式Spring Boot方式依赖管理pom里手动维护各个框架版本starter统一管理版本parent指定版本Web容器外部Tomcat配置web.xml内嵌Tomcat无需web.xmlSpring配置applicationContext.xml加扫描入口类SpringBootApplication自动扫描SpringMVC配置springmvc.xml配视图解析器、拦截器自动配置少量自定义用WebMvcConfigurerMyBatis配置mybatis-config.xml独立文件application.yml的mybatis节点数据源手动创建DataSourceBeanspring.datasource自动装配Mapper扫描XML里配MapperScan一行注解SQL映射mapper XML路径在mybatis-config里配置mybatis.mapper-locations这张表基本概括了从SSM迁到Spring Boot要动的所有关键位置。你如果手头有一个SSM老项目把配置按表格右边换一遍业务代码大部分可以原样保留。我在迁移时踩过一个关于MyBatis版本适配的坑SSM老项目用的是mybatis 3.2Spring Boot里用mybatis-spring-boot-starter 2.3.2代码里直接用LocalDateTime时发现SQL执行后时间字段映射不上。后来查明白是MyBatis从3.4版本才内置了对Java 8日期类型的支持老版要么加依赖要么升级这种问题在迁移时一抓一个准。所以版本升级也要关注不是Spring Boot本身解决一切。7. 常见问题与排查技巧7.1 时间差8小时的三个原因时间字段是新手最容易踩的坑而且踩完还懵。程序里查出来时间是北京时间存到数据库少了8小时或者反过来从库里查出来比本地时间晚了8小时。这通常有三个层面的原因叠加第一JDBC连接URL里没有加serverTimezoneAsia/Shanghai。MySQL 8的驱动要求必须指定时区加了这参数告诉驱动以北京时间解析。第二Jackson序列化时没有设置时区Spring Boot默认时区不是GMT8需要加spring.jackson.time-zoneGMT8。第三数据库服务器本身时区设置不对可以通过SQL执行SELECT NOW()看看返回的时间是否正常不正常需要改MySQL配置。排查思路是先看MySQL返回的时间对不对再看Java代码查询出来的时间对不对逐层定位是哪一层出了问题。我建议从第一期建表开始就把这三处统一配好后面时间相关的聚合查询就不会莫名奇妙地差出8小时。7.2 下划线转驼峰映射失败建表用的是user_name实体类写的是userName查询返回后userName为null这种问题十有八九是map-underscore-to-camel-case没配置。在SSM里这个配置写在mybatis-config.xml的 节点在Spring Boot里写在application.yml的mybatis.configuration节点注意节点的层级写错位置也会默默失效。配置项一旦生效MyBatis会在映射结果时自动把数据库列名user_name转成Java属性userName不需要你手动写resultMap。如果你不想依靠自动转换而是想精确控制映射可以手写resultMap并用columnuser_name propertyuserName。但一张表几十个字段全手写resultMap那个模板量真的很劝退所以我强烈建议在项目初期就把自动驼峰转换打开。这也是表设计统一用下划线风格的前提风格不一致会导致这个配置也救不了你。7.3 表名和关键字冲突表名命名的第一个原则是避开数据库保留字。order是一个MySQL保留字你如果建一张order表很多SQL语句里是SELECT * FROM order直接报语法错误必须写成order加反引号。我当时为了避免所有问题统一给业务表加了tb_前缀这纯粹是命名习惯但能规避大量潜在冲突。另外还有一个关于表名大小写的坑。MySQL在Windows上默认大小写不敏感在Linux上是敏感的。你如果在Windows开发时建的表名是Tb_User部署到Linux服务器上SQL里写tb_user可能就找不到表。所以团队约定最省事的做法就是全小写命名字段也是全小写加下划线这样不管部署到什么系统都不会因为大小写问题炸掉。7.4 其他容易踩的配置坑逆向工程生成实体类时如果targetProject的值在项目里不存在工具会直接报错。解决方式很简单先确保src/main/java目录存在或者直接用绝对路径。这个报错信息可能不太直观新手容易卡在那一步。Lombok在编译时的注解处理也需要IDE支持。如果你用的是高版本IDEA直接在设置里勾上Annotation Processing否则就算依赖配好实体类里的getter/setter也生成不出来编译会报错。还有一点如果你后来接手一个老项目项目里实体类没有用Lombok而是手动写了getter/setter不要贸然的把两者混用一个类里既有Data又手写某些getter生成规则会乱。密码字段的范围用VARCHAR(100)是我踩过坑得来的结论。最早用MD5时写的VARCHAR(32)后来切换BCrypt原来所有密码字段都放不下只能ALTER TABLE去扩宽。这种早期设计失误代价不大但很烦一开始留够余量会省很多事。最后分享一个关于建模节奏的体会这一期虽然只完成了实体类和表结构的创建但如果你真的照着把SQL执行一遍、把实体类写出来会发现自己对项目的理解已经上了一个台阶。因为数据库表结构其实就是产品需求的浓缩版——业务有哪些角色、有哪些核心状态、哪些数据需要保存历史全都在表里暴露无遗。我个人在实际操作中的体会是建表这件事是“前期多花一小时后期省一天”的典型。刚开始写这个校园商铺项目时我一直在纠结订单表需不需要快照字段后来发现没有快照字段订单详情页就永远无法展示买家下单那一刻的商品价格和名称。想明白这一层之后我在设计其他表时都会下意识问自己一句这个字段如果现在不加以后要加会有多痛苦下一期我会顺着这几张表把Mapper层写起来用逆向工程生成的代码作为底子再补上手写的联表查询SQL把商品列表、店铺详情、订单详情这些基础查询接口一步一步跑通。到时候你会真正体会到地基打得稳往上盖楼真的是一马平川。

相关新闻

iOS依赖治理:用Carthage把第三方库编译成静态xcframework

iOS依赖治理:用Carthage把第三方库编译成静态xcframework

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 5:48:43 阅读更多 →
ZYNQ 7000双裸核AMP实战:共享内存与核间中断

ZYNQ 7000双裸核AMP实战:共享内存与核间中断

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 5:48:43 阅读更多 →
Dijkstra算法进阶:从朴素版到堆优化与链式前向星存图

Dijkstra算法进阶:从朴素版到堆优化与链式前向星存图

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 5:48:43 阅读更多 →

最新新闻

Lunar 6.7.11 修复说明:Sync Mode 在 MacBook Air 与 iMac 上改用 nits 同步

Lunar 6.7.11 修复说明:Sync Mode 在 MacBook Air 与 iMac 上改用 nits 同步

桌面应用 【免费下载链接】Lunar Intelligent adaptive brightness for your external monitors 项目地址: https://gitcode.com/gh_mirrors/lu/Lunar 点击查看 免费下载 Lunar 6.7.11 是一个针对 Sync Mode(同步模式) 的定向修复版本。此次…

2026/10/16 6:27:53 阅读更多 →
MooTool Next-Compose 增量演进:MCP stdio 工具链、F03 格式化引擎与更新下载流的工程化落地

MooTool Next-Compose 增量演进:MCP stdio 工具链、F03 格式化引擎与更新下载流的工程化落地

桌面应用开发工具 【免费下载链接】MooTool Handy tool set for developers 项目地址: https://gitcode.com/gh_mirrors/mo/MooTool 点击查看 免费下载 导读 本篇以仓库中的增量开发记录 next-compose/docs/diff/561-mcp-reformat-update-env-net-vault-css-slice…

2026/10/16 6:27:53 阅读更多 →
AtCoder Beginner Contest 478

AtCoder Beginner Contest 478

AtCoder Beginner Contest 478 A - Grapes 题意:有N个人,编号为1到N,现在要把M颗葡萄分给他们。每次按照1, 2, …, N的顺序,每人分一颗,分到第N个人以后再从第1个人开始,直到所有葡萄分完。最后输出每个人分…

2026/10/16 6:27:53 阅读更多 →
google-api-nodejs-client 的 ondemandscanning 模块演进全解读:从 CHANGELOG 版本脉络到容器镜像漏洞扫描实战

google-api-nodejs-client 的 ondemandscanning 模块演进全解读:从 CHANGELOG 版本脉络到容器镜像漏洞扫描实战

后端 【免费下载链接】google-api-nodejs-client Googles officially supported Node.js client library for accessing Google APIs. Support for authorization and authentication with OAuth 2.0, API Keys and JWT (Service Tokens) is included. 项目地址: h…

2026/10/16 6:27:53 阅读更多 →
用Python和SQLite自建个人财务数据中台:从记账到自由分析

用Python和SQLite自建个人财务数据中台:从记账到自由分析

1. 从"financial-services"到个人财务数据中台:我为什么自建了一套记账分析系统先说个背景。我一直在关注"financial-services"这个方向,但说实话,金融服务的概念太大了——从银行App到支付工具,从个人记账软…

2026/10/16 6:27:53 阅读更多 →
Zabbix 监控 TACACS 服务实战:App TACACS Service 模板(net.tcp.service 简单检查)全解析

Zabbix 监控 TACACS 服务实战:App TACACS Service 模板(net.tcp.service 简单检查)全解析

【免费下载链接】community-templates Zabbix Community Templates repository 项目地址: https://gitcode.com/gh_mirrors/co/community-templates 点击查看 免费下载 本文围绕 Zabbix Community Templates 仓库中的 App TACACS Service 模板展开,讲解…

2026/10/16 6:26:53 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →