From 7194126a4cf7d02cf93dbea12c0dcb4febf140ef Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Fri, 26 Jun 2026 13:49:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(push):=20=E4=BF=AE=E5=A4=8D=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=8D=A2=E7=BB=91=E9=A9=B1=E9=80=90=E6=97=B6=20NonUni?= =?UTF-8?q?queResultException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit findByAppKeyAndDeviceId / findByAppKeyAndToken 改为返回 List, 避免 DB 中存在多条同 appKey+deviceId 记录时 Hibernate 抛出 NonUniqueResultException(HTTP 500)。 驱逐逻辑改为 stream + forEach,将所有旧用户记录一并清除。 Co-Authored-By: Claude Sonnet 4.6 --- .../push/repository/DeviceTokenRepository.java | 8 ++++---- .../java/com/xuqm/push/service/PushDispatcher.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java b/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java index 898f4a6..7ccd495 100644 --- a/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java +++ b/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java @@ -19,8 +19,8 @@ public interface DeviceTokenRepository extends JpaRepository findByAppKeyAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(String appKey, String userId); void deleteByAppKeyAndUserIdAndVendor(String appKey, String userId, DeviceTokenEntity.Vendor vendor); void deleteByAppKeyAndUserIdAndDeviceId(String appKey, String userId, String deviceId); - // Find device by appKey+deviceId regardless of userId (for cross-user eviction) - Optional findByAppKeyAndDeviceId(String appKey, String deviceId); - // Find device by appKey+token regardless of userId (token rotation detection) - Optional findByAppKeyAndToken(String appKey, String token); + // Find all entries for this device across all users (for cross-user eviction) + List findByAppKeyAndDeviceId(String appKey, String deviceId); + // Find all entries for this token across all users (token rotation detection) + List findByAppKeyAndToken(String appKey, String token); } diff --git a/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java b/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java index bb15aa9..cfa36a2 100644 --- a/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java +++ b/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java @@ -247,18 +247,18 @@ public class PushDispatcher { String romVersion) { String resolvedDeviceId = normalizeDeviceId(deviceId, vendor, token); - // Evict previous owner: if this device (by deviceId OR token) is registered to another user, remove it - tokenRepository.findByAppKeyAndDeviceId(appKey, resolvedDeviceId) + // Evict all other users who hold this device (by deviceId) or this token + tokenRepository.findByAppKeyAndDeviceId(appKey, resolvedDeviceId).stream() .filter(prev -> !userId.equals(prev.getUserId())) - .ifPresent(prev -> { - log.info("Device {} re-registered by new user={}, evicting previous user={}", resolvedDeviceId, userId, prev.getUserId()); + .forEach(prev -> { + log.info("Device {} re-registered by user={}, evicting previous user={}", resolvedDeviceId, userId, prev.getUserId()); recordLog(prev, DeviceLoginLogEntity.EventType.UNREGISTER); tokenRepository.delete(prev); }); - tokenRepository.findByAppKeyAndToken(appKey, token) + tokenRepository.findByAppKeyAndToken(appKey, token).stream() .filter(prev -> !userId.equals(prev.getUserId())) - .ifPresent(prev -> { - log.info("Token re-registered by new user={}, evicting previous user={} deviceId={}", userId, prev.getUserId(), prev.getDeviceId()); + .forEach(prev -> { + log.info("Token re-registered by user={}, evicting previous user={} deviceId={}", userId, prev.getUserId(), prev.getDeviceId()); recordLog(prev, DeviceLoginLogEntity.EventType.UNREGISTER); tokenRepository.delete(prev); });