<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>千千</name>
    <email>qianqian9520@gmail.com</email>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <icon>https://qianqian9520.top/img/avatar.png</icon>
  <id>https://qianqian9520.top/</id>
  <link href="https://qianqian9520.top/" rel="alternate"/>
  <link href="https://qianqian9520.top/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, 千千</rights>
  <subtitle>我们曾经仰望星空，思索我们在星辰中的位置</subtitle>
  <title>千千的星际日志</title>
  <updated>2026-06-13T14:05:33.590Z</updated>
  <entry>
    <author>
      <name>千千</name>
      <email>qianqian9520@gmail.com</email>
    </author>
    <category term="tech" scheme="https://qianqian9520.top/categories/tech/"/>
    <category term="Java" scheme="https://qianqian9520.top/tags/Java/"/>
    <category term="Spring Boot" scheme="https://qianqian9520.top/tags/Spring-Boot/"/>
    <category term="电商" scheme="https://qianqian9520.top/tags/%E7%94%B5%E5%95%86/"/>
    <content>
      <![CDATA[<p>最近把「得物实战」做完了。不是那种大而全的项目，但商品、订单、支付整条链路都自己搭了一遍，算是第一次把电商后端从浏览到付钱真正跑通。这篇就记一下我做了什么。</p><p>技术栈是 Spring Boot + MyBatis + MySQL，Redis 用来生成订单号，支付接支付宝。用户侧流程很直观：刷商品列表 → 点进详情选尺码 → 登录 → 提交订单 → 跳转支付宝 → 付完等回调改状态。看起来就几步，做起来模块不少。</p><h2 id="商品模块：SPU-和-SKU"><a href="#商品模块：SPU-和-SKU" class="headerlink" title="商品模块：SPU 和 SKU"></a>商品模块：SPU 和 SKU</h2><p>库表也是两张：<code>product</code> 存 SPU，<code>product_detail</code> 存 SKU，用 <code>product_id</code> 关联。列表接口查 SPU 分页，详情接口按 <code>productId</code> 把下面所有 SKU 拉出来。用户最终下单，关联的是 SKU，不是列表上那个 SPU。</p><p>商品列表还做了分页。前端传页码和每页条数，后端先 <code>count</code> 总数，再 <code>LIMIT</code> 查当前页。页码越界要处理，不然翻到不存在的页会出问题。</p><h2 id="登录：Session-校验"><a href="#登录：Session-校验" class="headerlink" title="登录：Session 校验"></a>登录：Session 校验</h2><p>下单前得知道是谁在买。项目用的是 Session。</p><p>前端调 <code>/api/user/checklogin</code>，后端从 Session 里看有没有登录信息。没登录就引导去登录，登录了才能下单。</p><p>有个细节印象很深：下单时 <code>userId</code> 必须从 Session 取，不能信前端传的。前端啥都能改，Session 是服务端管的。我也理解为啥——不然改个 <code>userId</code> 就能给别人下单了。</p><h2 id="订单模块：从提交到入库"><a href="#订单模块：从提交到入库" class="headerlink" title="订单模块：从提交到入库"></a>订单模块：从提交到入库</h2><p>用户选好尺码点「提交订单」，后端 <code>POST /api/order/add</code>，进来一个 <code>Order</code>，主要就 <code>productId</code> 有用，别的很多是后端填的。我当时的实现逻辑大概是：</p><p>校验 <code>productId</code> → 查 SKU 拿价格和商品信息 → 生成主键 → 状态设成待支付 → 用 Redisson 生成唯一 <code>orderNumber</code> → 转 DO 入库 → 返回订单。</p><p>订单号用 Redisson 而不是自己拼，是要求也是合理做法——分布式下要保证唯一，重复订单号后面支付、对账都麻烦。订单状态就几个：待支付、支付成功、支付失败、已关闭。一开始就是待支付，等支付回调再改。</p><h2 id="订单查询：别在循环里一个个查"><a href="#订单查询：别在循环里一个个查" class="headerlink" title="订单查询：别在循环里一个个查"></a>订单查询：别在循环里一个个查</h2><p>后面做了查最近支付成功订单的接口。列表要展示用户昵称、商品信息，如果只查 <code>order</code> 表，信息不够。我的做法是：</p><ol><li>先分页查订单</li><li>收集所有 <code>userId</code> 和 <code>productId</code></li><li>批量调 <code>UserService</code>、<code>ProductDetailService</code></li><li>内存里组装再返回</li></ol><p>一开始想在循环里一条条查用户和商品，后来知道这叫 N+1，订单一多就慢。批量查是小优化，但是真实项目里会遇到的那种。</p><h2 id="支付模块"><a href="#支付模块" class="headerlink" title="支付模块"></a>支付模块</h2><p>下单只是生成待支付订单，真正掏钱是支付模块。这块我花时间最多，也踩坑最多。</p><h3 id="发起支付"><a href="#发起支付" class="headerlink" title="发起支付"></a>发起支付</h3><p>用户点支付，调 <code>/api/alipay/pay</code>，传 <code>orderNumber</code>、金额这些。后端先记一条支付流水，状态 <code>PENDING</code>，再校验订单存在，然后调支付宝 SDK 组装请求，<code>pageExecute</code> 返回一段 HTML 表单，前端渲染后跳转支付宝收银台。</p><p>流水和订单分开存，因为一笔订单可能支付失败、用户重试，每次尝试都要有记录，方便后面查和对账。</p><h3 id="支付宝两条回调"><a href="#支付宝两条回调" class="headerlink" title="支付宝两条回调"></a>支付宝两条回调</h3><p>这块我一开始搞混了。付完钱之后有两条路：</p><ul><li><code>return_url</code>：用户浏览器跳回你的网站，看个成功页</li><li><code>notify_url</code>：支付宝服务器直接 POST 给你，告诉你付成了没有</li></ul><p>我一开始以为跳回成功页就算完事了。后来才明白——用户可能付完直接关页面，<code>return_url</code> 压根没触发。真正可靠的，是 <code>notify_url</code> 那条异步回调。而且支付宝会反复发，直到你回一个 <code>success</code> 才停。</p><p>所以更新订单状态，<strong>必须以 <code>notify_url</code> 为准</strong>。<code>return_url</code> 只做体验，不能当支付成功的依据。</p><h3 id="回调里干啥"><a href="#回调里干啥" class="headerlink" title="回调里干啥"></a>回调里干啥</h3><p>回调进来，<code>PayController</code> 接到请求，解析参数，交给 <code>PayService</code> 处理。先验签，确认是支付宝发的，不是别人伪造的。再看 <code>trade_status</code>，成了就：</p><ul><li>订单改支付成功</li><li>流水改 <code>SUCCESS</code></li><li>商品付款人数 +1</li></ul><p>失败就记失败状态。同一条回调可能收好几次，更新前先看订单是不是已经成功，别重复加付款人数。这就是幂等，支付场景里基本必做。</p><h2 id="并发和库存"><a href="#并发和库存" class="headerlink" title="并发和库存"></a>并发和库存</h2><p>高并发下的库存问题，这个我印象也深。很多人同时买同一 SKU，如果简单 <code>stock = stock - 1</code>，可能超卖——卖出去的比库存还多，电商里是大事故。</p><p>项目里用 Redis 做并发控制，保证库存不为负、付款人数不超过库存。具体实现课程有讲，核心就是：高并发下核心数据不能靠「先查再改」这种 naive 写法。</p>]]>
    </content>
    <id>https://qianqian9520.top/2026/06/13/%E6%96%87%E7%AB%A0%E6%A0%87%E9%A2%98/</id>
    <link href="https://qianqian9520.top/2026/06/13/%E6%96%87%E7%AB%A0%E6%A0%87%E9%A2%98/"/>
    <published>2026-06-13T12:57:07.000Z</published>
    <summary>
      <![CDATA[<p>最近把「得物实战」做完了。不是那种大而全的项目，但商品、订单、支付整条链路都自己搭了一遍，算是第一次把电商后端从浏览到付钱真正跑通。这篇就记一下我做了什么。</p>
<p>技术栈是 Spring Boot + MyBatis + MySQL，Redis 用来生成订单号，支付]]>
    </summary>
    <title>仿得物电商后端实战：我的一点记录</title>
    <updated>2026-06-13T14:05:33.590Z</updated>
  </entry>
  <entry>
    <author>
      <name>千千</name>
      <email>qianqian9520@gmail.com</email>
    </author>
    <category term="life" scheme="https://qianqian9520.top/categories/life/"/>
    <category term="随笔" scheme="https://qianqian9520.top/tags/%E9%9A%8F%E7%AC%94/"/>
    <category term="博客" scheme="https://qianqian9520.top/tags/%E5%8D%9A%E5%AE%A2/"/>
    <category term="星际穿越" scheme="https://qianqian9520.top/tags/%E6%98%9F%E9%99%85%E7%A9%BF%E8%B6%8A/"/>
    <content>
      <![CDATA[<p>最近花了很多时间，一点点把这个博客从「能看」打磨成「像自己的地方」。</p><p>我原本做的时候花了很多心思，想着弄成科幻大片那种，发文章就可以在星际间跃迁，后来发现我想的太简单了哈哈。这得费多少经费啊，这不是拍科幻片么。。。后来发现字体变小了，我以为是样式的问题，改了又改，都快崩溃了，耗了我很多时间，我又重新推送，改了域名，但是还是不行，已经绝望了。但今天偶然发现原来我误触了ctrl+0，我真服了，这一改过来就好多了。终于成了这个样子，肯定还会继续优化的哦！</p><blockquote><p><em>“We used to look up at the sky and wonder at our place in the stars, now we just look down and worry about our place in the dirt.”</em></p></blockquote><p>写博客大概也是这样：别总低头盯着琐碎，偶尔抬头，给自己留一片能仰望的星空。</p><p>今晚先写到这里。明天也许会有新的想法，也许没有——但页面已经在了，像坐标一样，等着被继续填写。</p><hr>]]>
    </content>
    <id>https://qianqian9520.top/2026/06/11/june-11-starry-pages/</id>
    <link href="https://qianqian9520.top/2026/06/11/june-11-starry-pages/"/>
    <published>2026-06-11T13:00:00.000Z</published>
    <summary>
      <![CDATA[<p>最近花了很多时间，一点点把这个博客从「能看」打磨成「像自己的地方」。</p>
<p>我原本做的时候花了很多心思，想着弄成科幻大片那种，发文章就可以在星际间跃迁，后来发现我想的太简单了哈哈。这得费多少经费啊，这不是拍科幻片么。。。后来发现字体变小了，我以为是样式的问题，改了又]]>
    </summary>
    <title>把星空装进网页里</title>
    <updated>2026-06-12T07:34:37.163Z</updated>
  </entry>
  <entry>
    <author>
      <name>千千</name>
      <email>qianqian9520@gmail.com</email>
    </author>
    <category term="life" scheme="https://qianqian9520.top/categories/life/"/>
    <category term="博客" scheme="https://qianqian9520.top/tags/%E5%8D%9A%E5%AE%A2/"/>
    <category term="星际穿越" scheme="https://qianqian9520.top/tags/%E6%98%9F%E9%99%85%E7%A9%BF%E8%B6%8A/"/>
    <content>
      <![CDATA[<p>博客正式启航。</p><blockquote><p><strong>Do not go gentle into that good night.</strong><br>不要温和地走进那个良夜。</p></blockquote><p>这个站点使用 Hexo 与 Butterfly 主题搭建，背景是夜色下的城市运河——霓虹倒映在水中，像遥远星系投射来的光。愿我们在代码与文字之间，找到属于自己的引力弹弓。</p>]]>
    </content>
    <id>https://qianqian9520.top/2026/06/11/welcome-to-interstellar-blog/</id>
    <link href="https://qianqian9520.top/2026/06/11/welcome-to-interstellar-blog/"/>
    <published>2026-06-11T02:00:00.000Z</published>
    <summary>
      <![CDATA[<p>博客正式启航。</p>
<blockquote>
<p><strong>Do not go gentle into that good night.</strong><br>不要温和地走进那个良夜。</p>
</blockquote>
<p>这个站点使用 Hexo 与 Bu]]>
    </summary>
    <title>欢迎来到星际日志</title>
    <updated>2026-06-11T09:53:44.249Z</updated>
  </entry>
  <entry>
    <author>
      <name>千千</name>
      <email>qianqian9520@gmail.com</email>
    </author>
    <category term="tech" scheme="https://qianqian9520.top/categories/tech/"/>
    <category term="Hexo" scheme="https://qianqian9520.top/tags/Hexo/"/>
    <category term="Butterfly" scheme="https://qianqian9520.top/tags/Butterfly/"/>
    <category term="GitHub Pages" scheme="https://qianqian9520.top/tags/GitHub-Pages/"/>
    <content>
      <![CDATA[<h2 id="为什么选择-Hexo-Butterfly"><a href="#为什么选择-Hexo-Butterfly" class="headerlink" title="为什么选择 Hexo + Butterfly"></a>为什么选择 Hexo + Butterfly</h2><p>Hexo 是轻量、快速的静态博客框架；Butterfly 主题则提供了美观的首页大图、侧边栏卡片和本地搜索，非常适合个人博客。</p><h2 id="部署到-GitHub-Pages"><a href="#部署到-GitHub-Pages" class="headerlink" title="部署到 GitHub Pages"></a>部署到 GitHub Pages</h2><ol><li>安装 <code>hexo-deployer-git</code></li><li>在 <code>_config.yml</code> 中配置 <code>deploy</code> 指向 <code>gh-pages</code> 分支</li><li>在 <code>source/CNAME</code> 写入自定义域名</li><li>执行 <code>hexo deploy</code> 即可发布</li></ol><h2 id="自定义域名"><a href="#自定义域名" class="headerlink" title="自定义域名"></a>自定义域名</h2><p>在 DNS 控制台添加记录：</p><ul><li><strong>CNAME</strong>：<code>www</code> → <code>qianqian9520-pixel.github.io</code></li><li><strong>A 记录</strong>（根域名）：指向 GitHub Pages 的 IP 地址</li></ul><p>就像 Cooper 穿越虫洞一样，一次配置，全宇宙可访问。</p>]]>
    </content>
    <id>https://qianqian9520.top/2026/06/10/hexo-butterfly-setup/</id>
    <link href="https://qianqian9520.top/2026/06/10/hexo-butterfly-setup/"/>
    <published>2026-06-10T06:30:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="为什么选择-Hexo-Butterfly"><a href="#为什么选择-Hexo-Butterfly" class="headerlink" title="为什么选择 Hexo + Butterfly"></a>为什么选择 Hexo + Butterfly</]]>
    </summary>
    <title>用 Hexo + Butterfly 搭建个人博客</title>
    <updated>2026-06-11T09:53:48.240Z</updated>
  </entry>
  <entry>
    <author>
      <name>千千</name>
      <email>qianqian9520@gmail.com</email>
    </author>
    <category term="life" scheme="https://qianqian9520.top/categories/life/"/>
    <category term="成长" scheme="https://qianqian9520.top/tags/%E6%88%90%E9%95%BF/"/>
    <category term="思考" scheme="https://qianqian9520.top/tags/%E6%80%9D%E8%80%83/"/>
    <content>
      <![CDATA[<p>《星际穿越》里，Miller 星球上的一小时等于地球上七年。时间在不同参照系里，流速截然不同。</p><p>学习也是如此：专注的一小时，可能抵得上散漫的一天。重要的不是花了多少时间，而是在哪个”引力场”里度过的。</p><p><strong>Murphy’s law doesn’t mean that something bad will happen. It means something will happen.</strong></p><p>保持好奇，保持行动。愿我们都能找到自己的坐标。</p>]]>
    </content>
    <id>https://qianqian9520.top/2026/06/08/gravity-and-growth/</id>
    <link href="https://qianqian9520.top/2026/06/08/gravity-and-growth/"/>
    <published>2026-06-08T12:00:00.000Z</published>
    <summary>
      <![CDATA[<p>《星际穿越》里，Miller 星球上的一小时等于地球上七年。时间在不同参照系里，流速截然不同。</p>
<p>学习也是如此：专注的一小时，可能抵得上散漫的一天。重要的不是花了多少时间，而是在哪个”引力场”里度过的。</p>
<p><strong>Murphy’s law d]]>
    </summary>
    <title>引力、时间与成长</title>
    <updated>2026-06-11T09:53:51.611Z</updated>
  </entry>
</feed>
