??? 三面滴滴 Java 岗,我直接当场淘汰

本文记录了一位程序员真实的美团面试经历,包含三轮面试中涉及的技术问题,如Redis、MySQL、RabbitMQ、并发编程、JVM等内容,以及面试官提问的具体场景。

前情提要

这是一个发生在我朋友身上的真实事情:

这里就叫他程序员 Y 吧。

程序员 Y 工作不到两年,周末在朋友圈发了个喜报,准备入职滴滴。

之后,我就带着祝福跟 Y 聊了许久,聊天的内容就是具体了解一下他面试的过程,心路历程和未来的打算。

之所以今天才发文章,是因为我一直在等他整理面试问的内容。今天正好就一并分享出来。

严格来讲是三面,但是 Y 笑着说其实只有二面...

请尽情细看吧(各位看官)

美团一面(80min)

(为保证内容纯正,下面的语言是由程序员 Y 自己整理的,没有任何改动)

面试主要是从一个系统设计出发,考察基础跟项目架构经验。美团相当重视基础问题(计算机网络、操作系统)

主要是围绕一个系统优化来的,下面就只写中间问的几个点:

1、项目介绍(聊一下自己做的项目,互相了解了一下)

2、redis 相关问题

  • redis 主要能解决什么问题,聊一下你所知道的?

  •  聊一下 redis 高可用的相关。主要说一下哨兵集群的流程,包括选举、以及宕机之后的处理方案。cluster 集群的工作流程

  •  聊一下 redis 哈希槽,为什么不用一致性哈希的方案

  •  redis 为什么这么快

  •  redis 跟 mq 的技术选型

3、mysql 相关问题

  • mysql 的事务隔离级别

  •  面试官描述了一个场景.....这种情况下你怎么优化 mysql,说说你优化的流程步骤

  •  你能想到什么优化 mysql 吞吐量的方案

  •  mysql 的底层数据结构?索引怎么存储的?

4、rabbitmq

  •  rabbitmq 的优势,能解决什么问题

  •  说一下 rabbitmq 怎么保证高可用的?

  •  聊聊镜像队列,怎么运作的?口述下代码??

5、并发编程相关

  •  hashmap 跟 concurrentHashMap

6、接近一个小时的计算机网络基础、操作系统基础

  •  进程、线程

  •  http1 与 http2

  •  网络五层架构,分别是做什么的?

  •  TCP、UDP 区别,UDP 怎么实现可靠性的,在哪一层实现的?

  •  TCP 的流量控制、拥塞控制

  •  进程调度算法

  •  等等....记不清了,美团贼喜欢问基础,接近一小时

7、JVM 相关

  •  类加载、双亲委派

  •  垃圾回收相关?怎么判断?算法?收集器?

  •  内存区域

8、手撸算法题两道

美团二面(70min)

正儿八经的面试了.....

1、再来一个场景,优化 mysql,具体步骤,什么命令,怎么操作,比较详细

2、redis 分布式锁的作用?什么场景用过?会有什么问题?(原子性的问题、误删锁、误得锁等等)怎么解决这些问题?(面试官提了几个场景,这块聊了半个多小时)

3、详细聊了 rabbitmq 的工作流程。介绍下 rabbitmq 的组建,分别有什么类型,具体是怎么用的?口述代码

4、redis 高可用

5、聊聊你了解的 RPC,dubbo 与 springcloud?我因为没做过微服务项目,因此,问我,你觉得应该有什么功能,我从 springcloud 的角度回答的

6、RPC 与 mq 技术选型,说下原因

7、Spring 源码,我讲了事务的源码(撸了好几次了,比较熟悉)

8、手撸算法题两道

9、聊实习时间、地点,未来发展

美团三面(5min)

这个 5min 很关键了↑

HR 直接给录用函

谈笑风生....聊薪资,工作地点,还有一些要录入系统的基本信息,留了电话


淦!太特么优秀了!

我问他,为何如此的胸有成竹?

他给我发来了一份文件,说你可以从里面随便挑一个问我!更别说这次美团问得这么基础...基础...基础...

我打开文件一看...

且不说内含阿里云、蚂蚁金服、腾讯、百度、携程等一线互联网大厂的真题,后面还有涵盖微服务、并发编程、数据库、消息中间件、JVM、MySQL、Redis、Spring、SpringBoot、SpringCloud、SpringMVC、MyBatis 等 java 主流技术的面试题及解析,原来如此了~

需要领取这些资料的朋友,在一键三连+评论☛☛☛【点击此处即可免费领取】

祝各位看官前程似锦,offer 不断!

<think> 我们正在解决UniApp对接滴滴支付时的重复扣款问题。根据之前讨论,滴滴支付流程涉及创建订单和支付申请。避免重复扣款的关键在于订单状态的幂等性控制和支付回调处理。 解决方案: 1. **订单唯一标识**:每次创建订单时生成唯一的业务订单号(out_trade_no),并在系统中记录该订单的状态(未支付/已支付/已关闭)。 2. **支付请求幂等性**:当用户发起支付请求时,先检查订单状态。若订单已支付,则直接返回支付成功;若未支付,再调用滴滴支付接口。 3. **支付回调处理**: - 在支付回调接口中,验证回调的签名和订单状态。 - 使用数据库事务更新订单状态,确保操作原子性。 - 处理成功后返回明确的成功响应(如HTTP 200)给滴滴支付平台,避免平台重试导致重复回调。 具体步骤(UniApp + 服务端协同): **步骤1:创建订单时生成唯一订单号** 服务端生成唯一订单号并保存到数据库,状态为"待支付"。 **步骤2:支付前状态检查(关键)** UniApp端在调用支付接口前,先请求服务端检查订单状态: ```javascript // UniApp端代码示例 function checkOrderStatus(orderId) { uni.request({ url: 'https://your-server.com/check-order', method: 'POST', data: { order_id: orderId }, success: (res) => { if (res.data.status === 'paid') { // 已支付,直接跳转成功页面 uni.navigateTo({ url: '/pages/pay/success' }); } else if (res.data.status === 'unpaid') { // 未支付,调用支付接口 startDidiPayment(orderId); } } }); } ``` **步骤3:支付请求(服务端中转)** 为避免客户端直接调用滴滴支付导致密钥泄露和重复请求,应通过服务端发起支付: ```javascript // UniApp端调用服务端支付接口 function startDidiPayment(orderId) { uni.request({ url: 'https://your-server.com/start-didi-payment', method: 'POST', data: { order_id: orderId }, success: (res) => { // 获取到支付参数(如调起支付的token) if (res.data.pay_token) { // 调用滴滴支付SDK(示例为伪代码,实际参考滴滴支付文档) dd.pay({ token: res.data.pay_token, success: () => { /* 支付成功处理 */ }, fail: () => { /* 支付失败处理 */ } }); } } }); } ``` **服务端关键逻辑(以Node.js为例)**: ```javascript // 服务端支付接口 router.post('/start-didi-payment', async (ctx) => { const { order_id } = ctx.request.body; // 1. 检查订单状态 const order = await db.getOrder(order_id); if (order.status === 'paid') { ctx.body = { code: 400, msg: '订单已支付' }; return; } // 2. 调用滴滴支付接口(伪代码) const payResult = await didiPayApi.createPayment({ out_trade_no: order.out_trade_no, total_amount: order.amount, subject: '滴滴加油' }); // 3. 记录支付请求日志(用于对账) await db.logPaymentRequest(order_id, payResult); // 4. 返回支付参数给客户端 ctx.body = { pay_token: payResult.token }; }); ``` **步骤4:支付回调处理(服务端)** 接收滴滴支付回调,确保幂等性: ```javascript // 滴滴支付回调接口 router.post('/didi-pay-notify', (ctx) => { const { out_trade_no, trade_status, sign } = ctx.request.body; // 1. 验证签名(忽略具体实现) if (!verifySign(sign)) { ctx.status = 403; return; } // 2. 查询本地订单 const order = await db.getOrderByOutTradeNo(out_trade_no); // 3. 如果订单已处理,直接返回成功 if (order.status === 'paid') { ctx.body = 'SUCCESS'; // 告诉滴滴支付已处理 return; } // 4. 处理支付成功逻辑(使用事务) if (trade_status === 'TRADE_SUCCESS') { await db.transaction(async (t) => { // 更新订单状态 await t.updateOrderStatus(order.id, 'paid'); // 其他业务逻辑(如发消息通知等) }); } // 5. 返回处理结果 ctx.body = 'SUCCESS'; // 必须返回SUCCESS避免重复回调 }); ``` **关键注意事项**: - **对账机制**:每日通过滴滴提供的对账接口核对订单,及时发现异常订单。 - **订单超时**:设置订单支付有效期(如30分钟),超时自动关闭订单,避免用户重复支付。 - **客户端防重**:在支付按钮点击后禁用按钮,防止用户多次点击。 通过以上方法,可有效避免重复扣款问题。 §§相关问题§§ 1. 如何实现滴滴支付回调接口的签名验证? 2. UniApp中如何防止用户多次点击支付按钮? 3. 滴滴支付订单超时关闭的具体实现方式? </think> ### UniApp对接滴滴支付避免重复扣款的方法 在UniApp对接滴滴支付时,避免重复扣款的核心是**实现支付请求的幂等性控制**和**建立完善的状态校验机制**。以下是具体解决方案: #### 一、技术实现方案 1. **订单唯一标识机制** 每次发起支付请求前,在服务端生成**全局唯一订单号**(参考滴滴支付要求的`out_trade_no`参数): ```javascript // 服务端生成订单号示例 (Node.js) const generateOrderNo = () => { return `DIDI${Date.now()}${Math.floor(Math.random() * 10000)}`; } ``` 2. **客户端幂等性控制** 在UniApp端添加支付状态锁,防止用户重复点击: ```javascript let isPaying = false; // 全局支付状态锁 function startPayment() { if(isPaying) return; // 已有支付进行中 isPaying = true; uni.showLoading({ title: '支付处理中' }); // 调用支付接口 dd.pay({ orderStr: orderInfo, success: (res) => { handlePaymentResult(res); isPaying = false; }, fail: (err) => { console.error('支付失败', err); isPaying = false; uni.hideLoading(); } }); } ``` 3. **服务端订单状态校验(核心)** 在回调接口中实现状态机验证: ```java // Java服务端示例 @PostMapping("/didi-pay-callback") public String handleCallback(@RequestBody Map<String, String> params) { String orderNo = params.get("out_trade_no"); // 1. 验证签名(省略) // 2. 查询订单当前状态 Order order = orderService.getByOrderNo(orderNo); if(order == null) { return "FAIL"; // 订单不存在 } // 状态校验:防止重复处理 if(OrderStatus.PAID.equals(order.getStatus())) { return "SUCCESS"; // 幂等返回成功 } // 3. 处理支付成功逻辑 orderService.updateOrderStatus(orderNo, OrderStatus.PAID); return "SUCCESS"; } ``` #### 二、系统架构层面的保障 1. **三方对账机制** $$ \text{每日定时任务} \rightarrow \text{拉取滴滴支付账单} \rightarrow \text{比对本地订单} \rightarrow \text{修复状态异常} $$ 2. **订单生命周期管理** | 状态 | 处理逻辑 | 超时时间 | |---|---|---| | 已创建 | 允许支付 | 15分钟 | | 支付中 | 禁止重复发起 | - | | 已支付 | 直接返回结果 | - | | 已关闭 | 需重新创建订单 | - | 3. **异常处理方案** - **网络超时场景**: 使用异步查询接口确认订单状态: ```javascript // UniApp端查询支付结果 uni.request({ url: '/api/check-payment', data: { orderNo }, success: (res) => { if(res.data.paid) { // 已支付处理 } else { // 重新发起支付 } } }); ``` - **重复回调场景**: 在回调接口记录处理日志: ```sql CREATE TABLE payment_log ( id BIGINT AUTO_INCREMENT, order_no VARCHAR(64) UNIQUE, -- 唯一约束防重 callback_time DATETIME, PRIMARY KEY(id) ); ``` #### 三、滴滴支付特有规范 1. **必须实现的参数** | 参数名 | 是否必填 | 说明 | |---|---|---| | `out_trade_no` | 是 | 商户唯一订单号 | | `nonce_str` | 是 | 随机字符串 | | `sign_type` | 是 | 签名类型(MD5/HMAC-SHA256) | 2. **推荐的安全实践** - 订单号生成规则:`${商户ID}${日期}${流水号}` - 支付令牌有效期:不超过2小时 - 回调验证:严格验证`sign`签名参数[^1] > **重要提示**:测试阶段使用滴滴**沙箱环境**(`https://open-sandbox.didiglobal.com`),正式环境需开通企业商户权限[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值