电影院购票系统实战:高并发锁座与事务一致性设计
简介一套基于SpringBootVue的电影院购票系统Java源码包采用B/S架构与MVC分层设计适合计算机、电子信息工程等专业学生用于毕业设计、课程设计或期末大作业。项目整合SpringBoot、Mybatis、MySQL、Ajax、Vue等技术栈覆盖用户登录、影片管理、场次排片、在线选座购票等核心业务模块前后端代码结构清晰便于二次开发与功能扩展。压缩包共773个文件包含109个Java后端源码、58个Vue页面组件、156个JavaScript脚本、49个CSS样式表、13个XML映射及配置另附2个YML配置文件、3个bat便捷运行脚本和docx/pdf说明文档整体大小约26.14MB环境要求为JDK1.8、Maven3.6、MySQL5.7及Tomcat8/9。所有源码均经过严格测试解压后按说明配置数据库即可运行并配有常见问题处理思路。目前已有614人学习浏览适合需要快速获取完整可运行项目源码的开发者参考使用。1. 电影院购票系统代码先把它当成一个交易系统而不是 CRUD Demo电影院购票系统代码这个搜索词在高校实训和 Java 面试题里出现的频率一直不低但真正把它当生产级项目看待的人很少。很多人以为这就是一套增删改查教学案例跑起来能选座下单就算完事而实际上它的核心难点绕不开两件事高并发下的座位不超卖以及订单在支付、取消、退款之间的状态一致性。这两个点恰恰是 Java 后端面试里最常追问的内容也是从学生项目走向可上线系统必须迈过的坎。这篇文章会从一个能落地的角度把表结构、锁座接口、支付回调和排片查询完整拆开讲适合正在做课程设计、准备实习项目以及想往订单交易方向深入的后端开发。读完你不仅能照着复现还能解释清楚每个关键参数为什么这么设。2. 从需求到库表五张核心表怎么设计才能不返工2.1 技术选型主流的 Spring Boot MyBatis-Plus 组合这个项目用 Spring Boot MyBatis-Plus 是当前最常见的选择没有之一。原因很实际Spring Boot 把配置收敛了一个人就能在半小时内把工程拉起来MyBatis-Plus 对单表 CRUD 几乎不用写 XML分页插件也是现成的省掉大量重复劳动。相比之下十年前流行的 SSHStruts Spring Hibernate现在连新同事都不好招JSP 渲染那套更是完全没有必要。既然是做购票系统核心是交易链路ORM 只要可靠、可控、好排查就行。MyBatis 的 SQL 自己写在 Mapper XML 里线上出问题时可以直接拷到数据库客户端里执行比 Hibernate 那种自动生成的 SQL 好定位得多。这个选择也贴合大多数 java 面试题里对 SSM 和 Spring Boot 的考察方向做完项目之后去聊实习岗项目讲述逻辑会很顺不会卡在“为什么用这个框架”这种基础问题上。工程结构上我一般按controller / service / mapper / entity / dto分包。实体类只承担数据映射业务逻辑全部收在 Service 层Controller 层不做任何判断只做参数校验和结果包装。这样做的直接好处是后面接入支付回调、定时对账、消息通知时不会因为逻辑散落而到处改代码。2.2 表结构把场次、影厅、座位、订单分开建模购票系统的核心表有五张影片表、影厅表、场次表、场次座位表、订单表。很多入门版本把座位直接存在影厅表里把订单和场次揉在一张表里一旦要做退票、锁座、排片冲突校验就全乱套。正确做法是把“影厅”和“场次”拆开因为同一个影厅在不同时间会排不同影片座位状态必须跟着场次走而不是跟着影厅走。CREATE TABLE film ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(100) NOT NULL, duration INT NOT NULL COMMENT 片长(分钟), release_date DATE NOT NULL, status TINYINT NOT NULL DEFAULT 1 COMMENT 1上映 0下架, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT影片表; CREATE TABLE cinema_hall ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, hall_name VARCHAR(50) NOT NULL, row_count SMALLINT NOT NULL, col_count SMALLINT NOT NULL, special_seat_json TEXT NULL COMMENT 维修位/情侣座标记 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT影厅表; CREATE TABLE show_session ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, film_id BIGINT UNSIGNED NOT NULL, hall_id BIGINT UNSIGNED NOT NULL, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, price DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL DEFAULT 1 COMMENT 1正常 0取消, UNIQUE KEY uk_hall_time (hall_id, start_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT场次表; CREATE TABLE show_seat ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, session_id BIGINT UNSIGNED NOT NULL, row_num SMALLINT NOT NULL, col_num SMALLINT NOT NULL, seat_status TINYINT NOT NULL DEFAULT 0 COMMENT 0可售 1锁定 2已售 3维修, order_id BIGINT UNSIGNED DEFAULT NULL, version INT NOT NULL DEFAULT 0, UNIQUE KEY uk_session_seat (session_id, row_num, col_num) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT场次座位表; CREATE TABLE t_order ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL, user_id BIGINT UNSIGNED NOT NULL, session_id BIGINT UNSIGNED NOT NULL, total_amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1已支付 2已取消 3已退款, pay_trade_no VARCHAR(64) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, paid_at DATETIME NULL, UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;这里有个关键设计show_seat不是影厅的物理座位而是“某一场次里的可售座位”。每次排片完成后系统会按影厅的row_count * col_count批量初始化出该场次的座位记录seat_status默认 0。这样才能做到同一个影厅、不同场次各自独立锁座互不干扰。字段类型上金额必须用DECIMAL(10,2)不能用float或double二进制浮点数在累加对账时会出现精度漂移这是 Java 基础里踩过无数次的坑。时间字段统一用DATETIME不要用TIMESTAMP后者在多个时区切换和 2038 年问题上会给你埋雷。所有状态字段加注释避免出现裸奔的魔法数字。2.3 关键约束唯一索引和状态字段要提前想清楚这套表结构里三个唯一索引是底线uk_hall_time防同一影厅同一开始时间重复排片uk_session_seat防同一场次同一座位重复初始化uk_order_no防订单号重复。数据库唯一索引不是性能杀手恰恰是并发场景下的最后一道后悔药哪怕应用层判断漏了数据库也会把脏数据挡在门外。我一般不建议加物理外键。外键会让插入、删除都要去检查关联表在订单表这种高频写入的表上尤其拖速度而且购票系统后期要做分库分表时物理外键几乎没法迁。关联关系靠应用层保证必要时用索引兜底。还有一个小细节删数据不要用DELETE订单和场次表都保留status字段做逻辑删除。用户取消订单是把订单置为 2不是把订单记录删掉场次取消是把场次置为 0不是删场次。否则排片报表、对账单、座位释放都会对不上到时候想查历史数据只能干瞪眼。3. 核心购票链路选座、锁座、下单、支付回调的完整代码3.1 锁座的核心用状态条件更新代替先查后改购票系统最容易翻车的地方就是锁座。很多第一次写的人会这样做先SELECT查座位状态如果等于 0 再UPDATE为已售。这个思路在单线程下没毛病一上并发就出事——两个请求同时查到状态是 0然后都去更新谁也没拦住谁同一个座位卖给了两个人。这是典型的“先查后改”竞态靠程序逻辑无法根治。正确做法是把“判断状态”和“修改状态”合并成一条 SQL让数据库的行锁来保证原子性。public interface ShowSeatMapper { int lockSeat(Param(sessionId) Long sessionId, Param(rowNum) Integer rowNum, Param(colNum) Integer colNum, Param(now) LocalDateTime now); }update idlockSeat UPDATE show_seat SET seat_status 1, version version 1, update_time #{now} WHERE session_id #{sessionId} AND row_num #{rowNum} AND col_num #{colNum} AND seat_status 0 /update这条UPDATE的WHERE条件里带上seat_status 0就同时完成了“检查状态”和“占用座位”两个动作。InnoDB 会先对命中的行加排他锁第二个事务更新同一行时会阻塞等第一个事务提交后第二个事务基于最新数据再判断条件发现seat_status已经变成 1更新行数为 0程序就能立刻感知到座位被抢。lockSeat返回的int就是受影响行数。判断行数为 0 就不允许继续下单这个信号比任何应用层的锁都直接。version字段现在是预留的等后面要做“管理员强制改座位”“拼座调整”这类操作时可以拿它做乐观锁避免覆盖别人的修改。3.2 订单创建与支付回调事务边界和幂等处理锁座成功之后要创建订单这两个操作必须在同一个事务里。锁了座位但订单没建成功座位要被释放订单建了但座位没锁上这张单就是无效单。我把核心事务写在 Service 层事务边界直接包住“锁座 建单”两件事Override Transactional(rollbackFor Exception.class) public String createOrder(LockSeatRequest request) { ShowSession session showSessionMapper.selectById(request.getSessionId()); LocalDateTime now LocalDateTime.now(); if (session.getStartTime().isBefore(now)) { throw new BusinessException(该场次已开场停止售票); } if (session.getStatus() ! 1) { throw new BusinessException(场次已取消无法购票); } ListSeatItem seats request.getSeats(); for (SeatItem seat : seats) { int rows showSeatMapper.lockSeat(session.getId(), seat.getRowNum(), seat.getColNum(), now); if (rows 0) { throw new BusinessException(座位已被抢占请重新选座); } } BigDecimal total session.getPrice().multiply(new BigDecimal(seats.size())); Order order Order.create(request.getUserId(), session.getId(), total); orderMapper.insert(order); showSeatMapper.bindOrderId(order.getId(), session.getId(), seats); return order.getOrderNo(); }注意Transactional上必须写rollbackFor Exception.class。Spring 默认只对RuntimeException回滚如果业务代码抛的是受检异常事务不会回滚座位就被永久锁住了。这个细节在 java 面试题里出现过很多次值得养成肌肉记忆。bindOrderId是把订单号回写到座位记录上这样取消订单时能精准释放哪些座位。创建完成后前端拿着orderNo去调支付平台支付平台异步回调后端接口。回调处理的第一原则是幂等因为支付平台会重试多次同一笔订单可能回调好几遍Transactional(rollbackFor Exception.class) public void handlePayCallback(PayCallbackDTO callback) { Order order orderMapper.selectByOrderNo(callback.getOrderNo()); if (order null) { throw new BusinessException(订单不存在); } if (order.getStatus() 1) { log.info(重复通知订单{}已是支付状态, order.getOrderNo()); return; } if (order.getStatus() 3) { throw new BusinessException(订单已退款拒绝支付回调); } int rows orderMapper.markPaid(order.getId(), callback.getPayTradeNo(), LocalDateTime.now()); if (rows 0) { throw new BusinessException(订单状态变更失败需人工介入); } }核心是markPaid这条更新只允许status 0的待支付订单变成已支付UPDATE t_order SET status 1, pay_trade_no #{payTradeNo}, paid_at #{paidAt} WHERE id #{id} AND status 0第一次回调时rows为 1事务成功重复回调进来时订单状态已经是 1WHERE status 0匹配不到直接命中上面那个“重复通知”的分支不会重复改状态。这种用更新条件代替先查后改的思路和锁座是同一个套路在交易系统里到处都用得上。3.3 一次购票的接口时序Controller、Service、Mapper 怎么串接口层面保持精简。前端选完座之后只调一个接口参数是场次 ID 和座位列表RestController RequestMapping(/api/order) public class OrderController { PostMapping(/lock) public ResultString lock(RequestBody Valid LockSeatRequest request) { return Result.ok(orderService.createOrder(request)); } }public class LockSeatRequest { NotNull(message 场次不能为空) private Long sessionId; Size(min 1, max 8, message 单笔购票数量必须在1到8张之间) private ListSeatItem seats; private ListSeatItem getSeats() { return seats; } }单笔限 8 张是行业惯例防止黄牛把整个影厅包圆也避免一个事务里锁太多座位导致锁等待时间过长。座位列表在前端就做过排重后端在 Service 里也要用Set再排一次防止同一排同一列传两遍否则第二条lockSeat会因为seat_status1失败整单回滚白白消耗数据库性能。整体时序是这样的前端选座后调/api/order/lock后端在事务里锁座并建单返回orderNo前端拿orderNo调支付平台支付平台异步回调/api/pay/callback后端把订单状态置为已支付。这个链路里没有轮询也没有前端“假支付成功”状态变更全部以支付平台回调为准。这个设计同时决定了后续所有对账逻辑都基于订单状态字段而不是基于前端传回来的结果。4. 排片与查询优化晚高峰接口不卡的两个关键点4.1 场次冲突校验同一影厅在同一时间段只能排一场排片是购票系统的上游排片一旦冲突座位和订单全乱。校验规则很简单同一影厅的场次开始时间不能落在另一场次的开始和结束时间之间结束时间也不能越界。重叠区间的判断在 SQL 里这么写SELECT COUNT(*) FROM show_session WHERE hall_id #{hallId} AND start_time #{newEndTime} AND end_time #{newStartTime} AND status 1这个条件的记忆方法很直观两个区间有重叠当且仅当“对方的开始小于我的结束”且“对方的结束大于我的开始”。count大于 0 就拒绝插入。uk_hall_time唯一索引只能挡住完全相同开始时间的重复场次挡不住区间交叉所以应用层校验不能省。并发排片时两个操作同时查count都可能查到 0然后同时插入重叠场次。要完全堵死常见做法是在排片事务里对影厅行加锁让同一影厅的排片操作串行化Override Transactional(rollbackFor Exception.class) public void createSession(SessionCreateRequest request) { hallMapper.selectByIdForUpdate(request.getHallId()); int conflict showSessionMapper.countConflict( request.getHallId(), request.getStartTime(), request.getEndTime()); if (conflict 0) { throw new BusinessException(该影厅当前时间段已有排片); } showSessionMapper.insert(request); }selectByIdForUpdate就是SELECT ... FOR UPDATE。事务期间其他排片请求会阻塞在这一步直到首个事务提交或回滚。代价是排片本身变成串行但排片操作频率低串行完全可接受换来的是绝对的冲突隔离。4.2 热点接口优化场次列表的索引、分页与参数设置用户打开购票 App 看到的第一屏是“正在上映的影片”点进影片后看“未来三天的场次”。这个接口是晚高峰第一个被打爆的点查询条件通常是影片和日期范围。基础的 SQL 长这样SELECT s.id, s.start_time, f.title, s.price, (SELECT COUNT(*) FROM show_seat st WHERE st.session_id s.id AND st.seat_status ! 0) AS sold_count FROM show_session s JOIN film f ON f.id s.film_id WHERE s.start_time BETWEEN #{dateStart} AND #{dateEnd} AND s.status 1 ORDER BY s.start_time LIMIT #{offset}, #{pageSize}索引加在show_session(status, start_time)上让“有效场次 按时间范围”的过滤能走索引。sold_count这个子查询会带来比较大的成本如果场次很多可以在show_session上加一个冗余字段sold_seat_count锁座成功时1取消订单时-1。读接口只查冗余字段只有写路径需要多更新一次这个计数。这是典型的“读多写少”优化项目里收益很高。分页参数我一般给pageSize设置上限 50前端传 1000 就直接拒绝。LIMIT 100000, 20这种深分页是性能杀手它会扫描前 10 万行再丢弃场次列表是时间流天然适合改成键集分页也就是把翻页条件直接写进WHEREWHERE s.start_time #{lastStartTime} AND s.start_time BETWEEN #{dateStart} AND #{dateEnd} AND s.status 1 ORDER BY s.start_time LIMIT 20这样每次查询都从上一页最后一条的时间点往后取走索引翻到第 100 页也不会越来越慢。如果 QPS 实在高可以在中间加一层 Redis 缓存key 用filmId:yyyy-MM-ddTTL 设为 30 秒左右。30 秒足够挡住瞬时高峰又不会让新场次长时间看不到。4.3 座位图返回二维数组如何一次性返回给前端选座页面的核心接口是“取座位图”。前端需要知道三件事影厅有几排几列、每个位置是否可售、以及哪些位置是维修座。后端最省事的返回格式是二维数组不要返回一个平铺的 List 让前端自己拼。ShowSession session sessionMapper.selectById(sessionId); CinemaHall hall hallMapper.selectById(session.getHallId()); ListShowSeat seats showSeatMapper.selectBySessionId(sessionId); int[][] seatMap new int[hall.getRowCount()][hall.getColCount()]; for (ShowSeat seat : seats) { if (seat.getRowNum() hall.getRowCount() seat.getColNum() hall.getColCount()) { seatMap[seat.getRowNum()][seat.getColNum()] seat.getSeatStatus(); } }前端拿到seatMap[i][j]后按值渲染颜色0 可售、1 已锁定显示为等待支付、2 已售、3 维修不可选。二维数组的坐标天然对应影厅的排和列完全不需要前端再做行列换算。这里的边界检查不能省万一上游初始化座位时数据出问题rowNum越界会导致ArrayIndexOutOfBoundsException整个选座接口 500。多一层判断也就几行代码但能挡住一次线上事故。seatMap里每个值都是int传输体积很小。几百个座位的影厅返回体也就几 KB不需要做压缩。如果影厅座位数很大比如 IMAX 上千座可以考虑只返回非可售座位列表但常规影院没必要保持简单更重要。5. 避坑专章并发超卖、事务失效、时间格式翻车实录5.1 座位超卖加了锁还会卖重的原因现象压测时两个线程同时提交同一个座位接口都返回下单成功数据库里出现两张订单引用同一个座位。原因锁座逻辑改对了但创建订单和锁座不在同一个事务里。先锁座、事务提交再开新事务建单两个线程分别锁座成功后都去建单座位状态虽然是 1但订单表里没人记录“被哪个订单占用”第二笔单照样能建出来。解决锁座和创建订单必须放在同一个事务里并且座位落单后立刻把order_id回写到show_seat。回写完成才提交事务。这样第二个请求在锁座阶段就会因为seat_status 1失败根本走不到建单。我之前排查这种问题时习惯先看show_seat.order_id是不是有值有值就说明回写丢了再去找事务边界为什么断开。5.2 事务自调用注解明明写了却不回滚现象Service 里buyTicket()方法调用了同类的另一个被Transactional标注的方法内部方法抛异常外层数据没有回滚。原因Spring 的声明式事务靠 AOP 增强对象来接管调用链。外部 bean 调用时才会经过增强逻辑同类内部this.xxx()是普通对象方法调用切面根本不会介入事务注解形同虚设。解决把需要事务的方法拆到独立的 Service bean 里或者注入当前类的 Spring 增强对象再调用。我一般直接拆类结构更清晰Service public class OrderService { private final OrderActionService actionService; public void buyTicket(Long sessionId, ListSeatItem seats) { actionService.lockSeatsAndCreateOrder(sessionId, seats); // 事务提交后再做其他操作 } }lockSeatsAndCreateOrder里的Transactional是跨 bean 调用事务正常生效。还有一个配套注意点Transactional只对 public 方法生效private 方法写了也是白写。这个知识点在 java 面试里高频出现实际项目里也经常有人被坑。5.3 时间字段LocalDateTime 序列化出来的格式不对现象接口返回的场次时间是2021-06-01T21:30:00中间带个 T前端直接显示英文格式或者数据库里存的时间比预期少了 8 小时。原因LocalDateTime 的 JSON 序列化不受spring.jackson.date-format控制那个配置只对java.util.Date生效。少了 8 小时则是 JDBC 连接时区的锅服务器时区、MySQL 时区、连接串时区三者不一致就会乱。解决实体字段上加JsonFormat强制指定格式和时区JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8) private LocalDateTime startTime;同时 JDBC URL 里显式写时区不要依赖服务器默认值jdbc:mysql://localhost:3306/cinema?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai容器部署时再把 JVM 时区设成Asia/Shanghai。三个地方对齐时间问题基本绝迹。时间格式这类问题属于看着小、排查起来极耗精力的类型我吃过几次亏后现在接任何 Java 项目都会先确认这三点再也不信“默认应该没问题”这种玄学。5.4 订单号生成时间戳拼接的重复风险现象并发量到一定程度后数据库报Duplicate entry唯一索引uk_order_no被击穿。原因订单号用yyyyMMddHHmmss 6位随机数生成同一秒内并发超过一定数量随机数撞车概率会明显上升一旦重试逻辑没写好就直接抛异常。解决简单可靠的方案是接入雪花算法生成 ID足够撑起单机几万的并发如果不想引入额外依赖至少在订单号里混入用户 ID 或座位序号提高唯一性。但无论用哪种方案uk_order_no唯一索引必须保留它是防重复的最终兜底。生成订单号的工具方法单独封装统一出口不要在每个 Service 里各写一套拼接逻辑否则后期想换算法只能到处找。6. 往上线再走一步压测验证、对账报表与异步出票6.1 用 JMeter 把锁座接口压到 500 并发写代码是第一步验证锁座是否真的不超卖是第二步。我用 JMeter 建一个线程组500 个线程同时打/api/order/lock请求体固定传同一个座位。跑完后去数据库查这张单如果show_seat.seat_status 1且order_id只对应一个订单就算通过。命令行跑更省资源jmeter -n -t lockseat.jmx -l result.jtl -e -o report压测前先把测试座位重置成 0压完看聚合报告里的异常率和 TPS。如果出现BusinessException: 座位已被抢占这是符合预期的正常失败不算接口报错真正要盯的是 500 和事务回滚异常。6.2 对账报表查每场次售出、退票、流水金额上线前至少要有一张对账 SQL每天核对系统里每个场次卖了多少张、收了多少钱和影院自己的售票终端对得上。订单状态只认 1已支付SELECT DATE(s.start_time) AS biz_date, s.id AS session_id, COUNT(o.id) AS sold_count, COALESCE(SUM(o.total_amount), 0) AS settled_amount FROM show_session s LEFT JOIN t_order o ON o.session_id s.id AND o.status 1 GROUP BY s.id, DATE(s.start_time) ORDER BY biz_date DESC;LEFT JOIN 的过滤条件要写在ON里而不是WHERE里否则已售数量统计会把没有订单的场次也过滤掉。这张报表能跑通说明订单状态机和场次表关联没有问题。6.3 异步出票订单支付成功后如何通知与补发支付回调里不建议同步去发短信、生成电子票这些操作慢且依赖外部服务会把支付回调接口拖垮。我一般用 Spring 事件在事务提交后触发异步任务TransactionalEventListener(phase TransactionPhase.AFTER_COMMIT) Async(ticketTaskExecutor) public void onOrderPaid(OrderPaidEvent event) { ticketService.generateAndPush(event.getOrderNo()); }线程池单独配一个核心线程 4最大 8队列容量 500拒绝策略用CallerRunsPolicy保证任务不会无声丢弃。出票失败要留重试表和重试任务用户可以点击“重新出票”触发补发。这一环做完购票系统的主链路从选座、锁座、下单、支付到出票就完整闭环了。我最早写这套系统时在锁座接口上翻过车后来养成的习惯是先确认 InnoDB 的行锁语义和事务隔离级别再写并发代码而不是靠感觉堆积锁。每个项目的数据库行为不完全一样动手前先用一条更新语句验证一下锁的阻塞效果能省下好几个通宵。希望这篇能让你少踩几个同样的坑希望帮到你。本文还有配套的精品资源点击获取

相关新闻

MATLAB处理NCEP风场数据绘制全球彩色风场图全流程

MATLAB处理NCEP风场数据绘制全球彩色风场图全流程

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

2026/10/4 1:20:14 阅读更多 →
Tecplot散点转云图:坐标系、插值与渲染三大技术关节

Tecplot散点转云图:坐标系、插值与渲染三大技术关节

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

2026/10/4 1:20:14 阅读更多 →
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/4 1:20:14 阅读更多 →

最新新闻

GQA数据集详解:从语言先验到视觉推理的评测革命

GQA数据集详解:从语言先验到视觉推理的评测革命

1. 为什么需要GQA:VQA评测中的“语言偏见”问题1.1 老数据集的问题做过多模态或者视觉问答(VQA)的朋友,大概率都踩过这套坑:模型在VQAv2上刷分刷得飞起,一换到真实场景就露馅。原因并不神秘,VQA…

2026/10/4 1:49:33 阅读更多 →
如何用UniMate实现文生动画?从文本提示到3D角色动作的完整流程

如何用UniMate实现文生动画?从文本提示到3D角色动作的完整流程

如何用UniMate实现文生动画?从文本提示到3D角色动作的完整流程 【免费下载链接】UniMate [SIGGRAPH Asia 2026] UniMate: One Unified Model to Animate Diverse Skeletons 项目地址: https://gitcode.com/GitHub_Trending/un/UniMate UniMate 是一个"文…

2026/10/4 1:49:33 阅读更多 →
基于SPI MRAM的工业掉电数据保存方案:MR25H40CDF与TM4C1299实战

基于SPI MRAM的工业掉电数据保存方案:MR25H40CDF与TM4C1299实战

直接讲正事。最近在做一块工业控制板,需要在掉电瞬间把运行参数、故障日志和校准数据可靠地存下来。项目里选了 MR25H40CDF 这颗 4Mbit SPI MRAM,搭配 TM4C1299KCZAD 主控。两个器件搭起来的这套存储方案,在工业和嵌入式场景里用起来很顺手&a…

2026/10/4 1:49:33 阅读更多 →
Vue Flow 拖拽式节点编辑器实战:DnD Sidebar 完整实现指南

Vue Flow 拖拽式节点编辑器实战:DnD Sidebar 完整实现指南

前端UI组件 【免费下载链接】vue-flow A highly customizable Flowchart component for Vue 3. Features seamless zoom & pan 🔎, additional components like a Minimap 🗺 and utilities to interact with state and graph. 项目地址:…

2026/10/4 1:49:33 阅读更多 →
STM32+MRAM工业存储实战:替代Flash实现高频写入与掉电保存

STM32+MRAM工业存储实战:替代Flash实现高频写入与掉电保存

做了这么多年嵌入式,存储方案来来去去选了不下七八种,从 I2C EEPROM、SPI NOR Flash 到铁电存储器,各有各的脾气。这次的活儿是要给一块以 STM32F446RE 为主控的工业采集板做非易失存储,刷进去的是设备运行状态、传感器采样值和配…

2026/10/4 1:49:33 阅读更多 →
talebook 写作审查输出格式规范(review-output.md):Findings 表、严重级别与裁决机制的完整解析

talebook 写作审查输出格式规范(review-output.md):Findings 表、严重级别与裁决机制的完整解析

后端前端CMS 【免费下载链接】talebook 一个简单好用的个人书库 项目地址: https://gitcode.com/gh_mirrors/ta/talebook 点击查看 免费下载 写作审查(writing review)是 talebook 前端体验工程中用于评估界面文案质量的标准流程&#xff0c…

2026/10/4 1:48:33 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/2 10:36:31 阅读更多 →
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/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练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/3 9:42:36 阅读更多 →