ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot电商项目实战:从SSM整合到Redis缓存与JWT认证

Spring Boot电商项目实战:从SSM整合到Redis缓存与JWT认证 简介前后端分离架构是现代Web开发的标配通过解耦前端展示与后端逻辑既支持多端复用也便于团队并行开发。Spring Boot作为Java后端的主流框架以自动配置简化SSM整合搭配MyBatis完成数据持久化Redis凭借内存级读写性能常被用于商品缓存、分布式锁等高频场景。基于这套技术栈构建的电商系统天然覆盖用户认证、商品管理、订单一致性、库存扣减等核心业务是验证后端工程能力的经典项目。本文从技术选型底层逻辑讲起依次拆解数据库设计、接口规范、JWT无状态登录、缓存旁路模式、下单事务与防超卖实现并针对缓存穿透、跨域拦截、MySQL时区等实战高频问题给出排查方案。无论是毕业设计还是简历项目这套完整实践路径都值得参考。 在Java后端这个方向上电商项目永远是最经典、最不会出错的练手选题。原因很简单一个像样的电商系统几乎覆盖了后端开发需要面对的所有核心问题——用户认证、商品管理、高并发查询、库存扣减、订单一致性、缓存策略、前后端联调。你把这个项目吃透了去面试Java岗位时提到的技术点基本都有真实场景支撑而不是背八股文。下面我会从技术选型的底层逻辑说起把整个网上电商项目的模块拆解、核心代码实现、Redis在其中的真实用途以及我在实际开发中踩过的坑一次性讲清楚。不管你是拿它做毕业设计还是作为求职简历上的项目经验这篇文章都可以直接照着实践。1. 项目整体设计与技术选型思路1.1 前后端分离的本质为什么不用JSP而用Vue很多同学在学校里做的电商项目还是JSP Servlet那套页面和后端代码揉在一起。这个项目明确写了前后端分离意味着前端静态资源和后端业务逻辑彻底分开部署。前端通过Ajax或Fetch调用后端提供的JSON接口后端不再返回HTML页面只处理数据。这个转变带来的直接好处是前端和后端可以并行开发互不阻塞。你在写Spring Boot接口的时候前端同学或者你自己的Vue部分可以用Mock数据先把页面搭起来等接口联调时再替换成真实请求。而且前后端分离之后后端接口可以同时服务Web端、小程序端甚至App端一套接口多端复用。选Vue而不是React或Angular核心原因是Vue的上手曲线更平缓。它的模板语法接近原生HTML数据绑定用双大括号{{ }}包裹事件绑定用click指令系统v-if、v-for非常直观。对于一个以Java为主、前端为辅的开发者来说Vue是投入产出比最高的选择。1.2 Spring Boot SSM的关系它们不冲突是进化这个项目标题里同时写了Spring Boot和SSM很多初学者会困惑这不冲突吗其实不冲突。SSM是Spring Spring MVC MyBatis的组合而Spring Boot并不是替代这三个组件的新框架它是用来简化Spring全家桶配置的工具。本质上你在Spring Boot项目里用的还是Spring的IOC容器、Spring MVC的注解式控制器、MyBatis的Mapper持久层只是省掉了大量XML配置。传统SSM项目需要配置web.xml、spring-mvc.xml、mybatis-config.xml、数据源、事务管理器一个环境配半天。Spring Boot通过自动配置机制把这些默认行为都封装好了你只需要在application.yml里写数据源地址MyBatis的SqlSessionFactory就会自动创建Spring MVC的DispatcherServlet会自动注册。所以这个项目的技术栈理解为一句话Spring Boot做骨架Spring MVC做Web层MyBatis做持久层这就是SSM在Spring Boot时代的标准形态。1.3 Maven在项目中的真实角色不只是依赖管理Maven的作用经常被低估。很多人觉得Maven就是pom.xml里粘贴依赖的其实它承担了三件关键事。第一是依赖仲裁。电商项目至少需要十几个依赖spring-boot-starter-web、mybatis-spring-boot-starter、mysql-connector-java、spring-boot-starter-data-redis、jjwt、lombok等等。Maven能自动拉取这些依赖的传递依赖并且解决版本冲突。比如spring-boot-starter-parent这个父POM统一锁定了所有Spring生态组件的版本你不用自己操心Spring Boot 2.7和Spring Framework 5.3是否兼容。第二是项目生命周期管理。mvn clean package一行命令就能完成编译、测试、打包生成可执行的jar包。部署到服务器上就是java -jar mall.jar非常干净。第三是多模块工程支持。如果项目规模变大可以把common、pojo、mapper、service、controller拆成多个Maven模块模块之间用坐标依赖。虽然这个课程级别的项目不需要拆这么多模块但用Maven管理结构后面扩展会很方便。1.4 MySQL与Redis的搭配逻辑各司其职MySQL负责持久化核心数据——商品信息、用户信息、订单记录、库存流水。它的强项是事务一致性ACID特性保证订单和库存不会出错。Redis负责处理高频访问的数据——商品详情缓存、首页轮播图缓存、验证码、购物车、分布式锁。它的强项是读写速度快因为数据存储在内存中单机QPS可以轻松过万。两者搭配的逻辑是读请求先查Redis查不到再查MySQL把查到的结果回填到Redis写请求直接操作MySQL然后主动删除或更新Redis缓存。这套缓存旁路模式是电商系统的性能基石后面我会详细讲代码实现。2. 数据库设计与核心模块拆解2.1 数据库表设计电商项目到底需要几张表我设计这个项目时一共建了8张核心表。这里直接给出建表要点你可以根据自己的需求增删。表名作用关键字段备注user用户表id、username、password、nickname、phone、avatar、create_timepassword存MD5后加盐的值category商品分类表id、name、parent_id、sort_order支持两级分类product商品表id、category_id、name、subtitle、main_image、detail、price、stock、statusstatus控制上下架cart购物车表id、user_id、product_id、quantity、checked一个用户对应多个商品记录address收货地址表id、user_id、receiver_name、receiver_phone、province、city、district、detail可设置默认地址order订单主表id、order_no、user_id、total_price、status、receiver_info、create_timestatus待付款/已付款/已发货/已完成/已取消order_item订单明细表id、order_no、product_id、product_name、product_image、current_price、quantity、total_price冗余商品快照信息cart也可以直接用Redis实现商品表里有两个字段容易被忽略subtitle是商品副标题用于列表页展示detail是富文本详情。订单明细表里的product_name、product_image、current_price是故意冗余的因为商品改名或调价后订单里必须保留下单那一刻的信息不能随着商品表变动。2.2 索引设计别等数据量大了再后悔小项目可以不在乎索引但电商场景商品表几十万条数据很正常这时候索引就是生命线。user表的username要建唯一索引因为登录需要按用户名查询而且必须保证用户名不重复。product表的category_id建普通索引支撑分类查询。order表的user_id和order_no都要建索引前者用于我的订单列表后者用于订单查询接口。订单主表的数据量增长最快建议按月分表但这超出了基础项目的范畴。我做完这个项目后的体会是建表时把索引设计好比后续发现慢查询再优化SQL要省心得多。2.3 功能模块划分从用户侧到管理侧整个电商系统的功能可以拆成两大端。用户端是C端买家使用的包括注册登录、浏览商品、搜索商品、购物车、下单支付这里用模拟支付、查看订单、收货地址管理。管理端是B端运营使用的包括分类管理、商品上下架、订单发货处理。前后端分离后管理端和用户端是两套独立的前端工程但它们调用同一套后端接口。为了权限隔离后端用Spring MVC拦截器对请求路径做白名单放行和Token校验区分用户角色。3. 核心实现环节从配置到代码一步步搭起来3.1 项目搭建与核心配置用IDEA新建Spring Boot项目时直接选择Spring InitializrGroup填com.mallArtifact填mallJava版本用8或11都行Spring Boot版本建议用2.7.x。为什么不用3.x因为Spring Boot 3要求JDK 17并且javax包名改成了jakarta很多网上教程的代码拿过来直接会报包名错误。对于学生项目2.7.x生态最成熟遇到的坑最少。pom.xml里的核心依赖如下直接抄即可dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /dependencyapplication.yml文件里最需要注意的是MySQL连接串MySQL 8.x驱动要求指定serverTimezone不然会报时区错误。Redis默认端口6379本地装了Redis服务端后直接连即可spring: datasource: url: jdbc:mysql://localhost:3306/mall?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 0 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.mall.pojo configuration: map-underscore-to-camel-case: truemap-underscore-to-camel-case: true这个配置特别重要。数据库字段是create_timeJava属性是createTime开启这个选项后MyBatis会自动映射不用手写ResultMap。3.2 前后端分离的接口规范与跨域处理前后端分离开发中接口约定是重中之重。我采用的是RESTful风格返回体统一封装。定义统一返回对象时要使用泛型这样强类型语言里的类型转换是安全的Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); return result; } }接口写好后前端项目跨域访问后端是必然遇到的问题。浏览器出于安全策略会阻止跨域请求解决方案是在Spring Boot里配置全局跨域Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }注意这里的坑如果用了自定义拦截器做Token校验OPTIONS预检请求会被拦截器拦住。因为浏览器在正式请求前会先发一个OPTIONS请求探测服务器是否允许跨域这个请求不带Token校验必然失败。所以拦截器里必须直接放行OPTIONS请求。3.3 用户认证JWT的无状态登录设计电商系统的用户登录状态不能依赖Session因为前后端分离后后端服务可能是多实例部署的Session在A机器上创建、B机器上就找不到。Redis可以用来解决Session共享问题但更现代的做法是直接用JWT。我选择用一个独立工具类来处理JWT的生成与解析public class JwtUtil { private static final String SECRET_KEY mall-secret-key; private static final long EXPIRE_TIME 7 * 24 * 60 * 60 * 1000; public static String generateToken(Integer userId, String username, Integer role) { return Jwts.builder() .claim(userId, userId) .claim(username, username) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public static Claims parseToken(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); } }JWT的机制是用户登录成功后后端生成一个包含用户信息的签名字符串返回给前端前端把Token存在localStorage里每次请求在请求头加上Authorization: Bearer token后端拦截器解析Token得到用户信息放行请求。因为JWT自带签名服务端不需要保存任何会话状态。实际操作中要注意几个细节。Token放在请求头而不是URL参数中避免被浏览器历史记录或服务器日志泄漏。用自定义注解RequireLogin加在需要登录的Controller方法上拦截器判断方法上是否有这个注解比按路径匹配灵活得多。JWT的密钥要配置在环境变量或者配置中心不要硬编码提交到Git仓库否则等于把用户登录凭证交给了别人。3.4 商品查询与Redis缓存的接入商品详情和首页数据是访问量最大的接口不能每次都查MySQL。我在这里演示一个商品详情接口的缓存实现。为了不侵入业务代码使用Spring AOP或者直接用简单的缓存逻辑都行Service public class ProductServiceImpl implements ProductService { Autowired private ProductMapper productMapper; Autowired private StringRedisTemplate stringRedisTemplate; private static final long CACHE_TTL 30 * 60; Override public ProductVO getProductDetail(Integer productId) { String cacheKey product:detail: productId; String cacheValue stringRedisTemplate.opsForValue().get(cacheKey); if (StringUtils.hasText(cacheValue)) { return JSON.parseObject(cacheValue, ProductVO.class); } ProductVO product productMapper.selectDetailById(productId); if (product ! null) { stringRedisTemplate.opsForValue() .set(cacheKey, JSON.toJSONString(product), CACHE_TTL, TimeUnit.SECONDS); } return product; } }这里有几个关键点。Redis存的必须是JSON字符串所以用StringRedisTemplate它默认的序列化器就是String不会出现乱码问题。缓存Key要设计成业务:类别:唯一标识的格式方便后续清理。过期时间一定要给避免商品下架后缓存还活着。另外存进去之前要判断product ! null不然空值会被缓存形成缓存穿透。还有一个容易被忽视的问题更新商品信息后必须主动删除缓存而不是等待缓存过期。在更新商品的Service方法里加一行redisTemplate.delete(product:detail: productId)这样才能保证用户看到的信息是最新的。3.5 购物车实现选MySQL还是Redis购物车有两种实现方式。未登录状态下用前端的localStorage存储但是换浏览器或者清缓存就丢失了体验不好。我建议做成登录后同步到Redis这样换设备购物车也能同步。Redis实现购物车非常顺手用Hash结构key是cart:{userId}field是商品IDvalue是数量。每次加购就是一条HSET命令查询购物车就是HGETALL性能极高。但如果要在购物车里展示商品的价格和图片Redis里只存了商品ID和数量还需要批量查询MySQL拿到商品详情。所以实际项目中我更推荐MySQL存储购物车表结构是userId、productId、quantity、checked。原因很简单购物车涉及商品价格变化在用户结算时要实时验证库存和价格放在MySQL里和商品表做关联查询更方便。对于课程设计来说MySQL版的购物车逻辑更清晰而且能写出CRUD的完整代码面评时有的讲。3.6 下单扣库存事务与并发控制下单是整个项目中逻辑最复杂的环节需要同时操作订单表、订单明细表、库存扣减三步必须保证原子性。用Spring的Transactional注解实现事务管理Override Transactional(rollbackFor Exception.class) public OrderVO createOrder(Integer userId, ListCartItemVO cartItems, Integer addressId) { // 1. 生成订单号格式时间戳 用户ID 随机数 String orderNo generateOrderNo(userId); // 2. 计算订单总额 BigDecimal totalPrice new BigDecimal(0); // 3. 扣减库存含乐观锁防超卖 for (CartItemVO item : cartItems) { int result productMapper.deductStock(item.getProductId(), item.getQuantity()); if (result 0) { throw new RuntimeException(商品库存不足 item.getProductName()); } // 累计价格、写入明细... } // 4. 插入订单主记录 // 5. 清空购物车 // 6. 返回订单数据 }防超卖的悲观锁可以在SQL里用SELECT ... FOR UPDATE但对这个场景有点重。我采用乐观锁方案商品表的stock字段上加上version或者直接在更新SQL里加库存条件判断。问题在于执行下单操作时Redis分布式锁已经在这里没用了——答案是有用而且不同级别对应不同方案。你如果只做最基础的版本上面的乐观锁就够但如果考虑到一个用户频繁点击提交订单按钮就需要在入口处加一个防重复提交的分布式锁。我在项目里结合Redis实现了一个简单版本public boolean tryLock(String lockKey, String requestId, long expireTime) { return stringRedisTemplate.opsForValue() .setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS); } public void unlock(String lockKey, String requestId) { String value stringRedisTemplate.opsForValue().get(lockKey); if (requestId.equals(value)) { stringRedisTemplate.delete(lockKey); } }setIfAbsent是原子操作多个线程同时请求时只有一个能获取锁。requestId的作用是防止误删别人的锁释放前先判断是不是自己加的。这个锁用在同一个用户短时间内的重复下单请求上锁的Key设计成lock:order:{userId}过期时间设1秒就足够了。3.7 Vue前端工程与接口联调Vue部分用Vue CLI或Vite创建工程推荐使用Vite启动速度比Webpack快很多。脚手架初始化命令npm create vuelatest mall-web前端最重要的工作是封装axios请求实例。统一处理BaseURL、Token注入、响应码拦截import axios from axios import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) request.interceptors.response.use( response { const res response.data if (res.code 200) { return res.data } if (res.code 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(new Error(res.message)) }, error { return Promise.reject(error) } ) export default request这里解决了前后端联调中最常见的两个问题。一个是Token统一注入不用在每个请求方法里手动带Token。另一个是401统一跳登录当Token过期时自动踢回登录页。跨域问题在开发环境下可以用Vite的代理配置解决不用每次都去改后端CORS配置server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } }Vue路由配置时使用路由懒加载组件按需加载减少首屏白屏时间const routes [ { path: /, component: () import(/views/Home.vue) }, { path: /product/:id, component: () import(/views/ProductDetail.vue) }, { path: /cart, component: () import(/views/Cart.vue), meta: { requiresAuth: true } }, { path: /order/confirm, component: () import(/views/OrderConfirm.vue), meta: { requiresAuth: true } } ] router.beforeEach((to, from, next) { if (to.meta.requiresAuth !localStorage.getItem(token)) { next(/login) } else { next() } })4. 实战中的常见问题与排查技巧4.1 MySQL时区与连接问题连接MySQL时最容易碰到的是The server time zone value Öйú±ê׼ʱ¼ä这样的乱码时区错误。解决方案两种MySQL命令行执行set global time_zone 8:00修改数据库时区或者在JDBC连接串里加serverTimezoneAsia/Shanghai。我建议两种都做因为只改连接串数据库服务器本身的时区仍然是错的后面做时间统计、定时任务时也会踩坑。MySQL 8.x还要注意使用com.mysql.cj.jdbc.Driver而不是旧的com.mysql.jdbc.Driver否则会直接报ClassNotFound。4.2 Redis连接不上或启动闪退本地装了Redis Desktop Manager连不上Redis时先检查服务端是否真正启动了。Windows环境下Redis服务端默认是前台运行关掉窗口就会停。用命令redis-server --service-install redis.windows.conf注册成Windows服务再用net start redis启动这样就不会被误关了。Redis 5.0以上版本直接运行redis-server.exe接redis.windows.conf时配置文件里没有appendonly yes配置的话启动后数据不会持久化。开发阶段可以不关持久化但部署前一定要开启AOF或RDB中的至少一种。还有一个小坑新版的Redis默认绑定127.0.0.1并且需要密码认证。本地开发没问题如果要部署到云服务器记得修改bind 0.0.0.0和设置requirepass。但注意不要使用明文弱密码否则服务器会被扫描爆破这已经是重灾区。4.3 Spring Boot项目启动报端口被占用开发阶段最常见的错误是Port 8080 was already in use。排查方法netstat -ano | findstr 8080 taskkill /f /pid 对应进程号如果是多个Spring Boot实例同时启动也可以直接改端口号server: port: 90904.4 缓存穿透、击穿、雪崩的应对当Redis缓存失效后大量请求同时打进数据库会造成缓存雪崩。解决办法有几个层次。最简单的给过期时间加随机偏移量比如基础30分钟加上0到5分钟的随机值避免同一时刻集体失效。加锁的方案是使用互斥锁缓存失效时只放行一个线程去查数据库其他线程等待后重新查缓存上面的Redis分布式锁在这里也可以复用。缓存穿透是查询一个根本不存在的数据每次都会落到数据库。我前面代码里已经提到了预防方法写入时判断空值把空值也缓存起来并且设置较短的过期时间。更严谨的办法是在Controller入口使用布隆过滤器先用布隆过滤器判断商品ID是否存在不存在直接返回但这需要额外的容器维护课程设计阶段可以先不加。4.5 前后端联调时的跨域和404联调时最常见的问题就是前端请求404。排查步骤固定直接打开浏览器开发者工具查看Network面板中请求的URL和状态码。如果请求到达了后端但返回404大概率是路径不对检查Controller的RequestMapping和前端请求路径是否完全一致。如果请求根本没到达后端就返回404检查前端代理配置或后端CORS配置。另一个老大难问题是POST请求返回403或405通常是Spring Security拦截了CSRF攻击。如果项目没引入Spring Security却出现403检查是不是自定义拦截器拦掉了或者前端发送的Content-Type是application/json但后端接口参数用RequestParam接收Spring MVC解析不到参数也会报400。4.6 数据库并发下的死锁多用户同时购买同一款商品时可能触发数据库死锁。死锁场景通常发生在事务中多条SQL语句对资源的锁定顺序不一致。比如A事务先更新商品表再插入订单表B事务先插入订单表再更新商品表两边相互等待就死锁了。排查方法是用SHOW ENGINE INNODB STATUS查看死锁日志看最后等待的资源。解决的思路是要保持所有事务按照相同的顺序访问资源先锁商品再插入订单。还有就是缩短事务执行时间不要在事务里调用外部接口、发送短信等耗时操作这些应该放到事务外异步执行。5. 项目复盘做完这个电商项目后我的几点体会5.1 这个项目在简历上应该怎么写很多同学项目做完了简历上只写一句基于Spring Boot和Vue的电商系统这等于白做。你需要把项目拆成可量化的描述重点突出你解决过的问题而不是罗列技术名词。我建议的写法是项目描述部分写清楚系统的功能范围前台商品展示、购物车、订单管理、后台管理系统技术架构部分写清前后端分离、Spring Boot MyBatis Redis Vue。然后单独列出你最有亮点的工作比如设计并实现了基于Redis的商品详情缓存缓存命中率达到xx%、使用Redis分布式锁解决了订单并发下的库存超卖问题、基于JWT实现无状态登录认证支持跨域访问。这些描述才真正能引起面试官的兴趣。5.2 关键技术点如何应对面试提问面试官看到这个项目大概率会追问几个方向。Redis相关的问题是最多的你要能讲清楚Redis为什么快纯内存操作、单线程避免了锁竞争、IO多路复用、缓存和数据库的一致性如何保证先更新数据库再删缓存、缓存穿透和击穿的区别及应对方案。Spring Boot相关的问题会集中在自动配置原理上。你要能说清楚SpringBootApplication组合了哪几个注解EnableAutoConfiguration是怎么通过META-INF/spring.factories加载自动配置类的。这个知识点是Java后端面试的高频考点建议专门花时间深入一下。MySQL相关的问题集中在索引和事务隔离级别。你要能说出聚簇索引和二级索引的区别、explain执行计划怎么分析、InnoDB的默认隔离级别为什么是可重复读以及如何处理幻读。5.3 线上环境与本地开发的差异如果这个项目要部署到线上有几件事必须提前考虑。本地用的MySQL账号是root线上必须创建独立的应用程序账号只授予业务库的最小权限。Redis要设置密码并且不能使用默认端口。配置文件里的数据库密码、Redis密码不能写死在application.yml里可以用环境变量注入或者使用Spring Cloud Config、Nacos这类配置中心。打包部署的时候前端Vue项目执行npm run build会生成dist目录把dist里的静态文件交给Nginx托管Nginx配置反向代理把/api路径的请求转发到后端的Java服务。这样一个标准的全栈部署就完成了。实际部署踩过几次坑之后我才真正理解为什么前后端分离项目要用Nginx这种Web服务器来托管静态资源、做请求转发和负载均衡。5.4 从课程设计到生产级项目的差距做完这个项目只是第一步。如果要往生产级方向发展你还需要考虑很多当前没做的东西秒杀场景下的队列削峰、订单超时自动取消的定时任务、消息队列做订单创建和库存扣减的解耦、分布式事务的最终一致性方案、ELK日志收集、Prometheus监控报警。但我是比较务实的人对于一个毕业生或者转行的开发者来说**把基础版本吃透能在面试中讲清楚每个技术点的来龙去脉比在简历上堆砌分布式微服务更有说服力。**先把这版做出来跑起来出了问题能定位这就是实打实的能力。我个人的建议是做完这个项目后选一个方向做深做实。比如往高并发方向扩展用JMeter压测商品详情接口找出性能瓶颈然后有针对性的优化缓存策略和SQL或者往工程化方向扩展写单元测试、写接口文档、加日志链路追踪。任何一个方向的深入都会让你的简历在几十份候选者里脱颖而出。本文还有配套的精品资源点击获取
返回列表