补充用户默认酒店唯一约束
This commit is contained in:
@@ -10,6 +10,7 @@ import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
@@ -75,10 +76,10 @@ public class MybatisPlatformHotelRepository implements PlatformHotelRepository {
|
||||
|
||||
@Override
|
||||
public void ensureUserHotel(Long userId, String hotelId, boolean defaultHotel) {
|
||||
PlatformUserHotelEntity existing = userHotelMapper.selectOne(Wrappers.<PlatformUserHotelEntity>lambdaQuery()
|
||||
.eq(PlatformUserHotelEntity::getUserId, userId)
|
||||
.eq(PlatformUserHotelEntity::getHotelId, hotelId)
|
||||
.last("LIMIT 1"));
|
||||
if (defaultHotel) {
|
||||
clearOtherDefaultHotels(userId, hotelId);
|
||||
}
|
||||
PlatformUserHotelEntity existing = findUserHotel(userId, hotelId).orElse(null);
|
||||
if (existing != null) {
|
||||
if (defaultHotel && !Boolean.TRUE.equals(existing.getDefaultHotel())) {
|
||||
existing.setDefaultHotel(true);
|
||||
@@ -91,7 +92,39 @@ public class MybatisPlatformHotelRepository implements PlatformHotelRepository {
|
||||
relation.setHotelId(hotelId);
|
||||
relation.setDefaultHotel(defaultHotel);
|
||||
relation.setCreatedAt(nowUtc());
|
||||
userHotelMapper.insert(relation);
|
||||
try {
|
||||
userHotelMapper.insert(relation);
|
||||
} catch (DuplicateKeyException ignored) {
|
||||
// 多实例并发初始化时唯一索引已经保证授权关系存在,重复插入后只需补齐默认酒店状态。
|
||||
findUserHotel(userId, hotelId).ifPresent(concurrentExisting -> {
|
||||
if (defaultHotel && !Boolean.TRUE.equals(concurrentExisting.getDefaultHotel())) {
|
||||
concurrentExisting.setDefaultHotel(true);
|
||||
userHotelMapper.updateById(concurrentExisting);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单个用户酒店授权关系,用于写入前检查和并发重复插入后的状态补齐。
|
||||
*/
|
||||
private Optional<PlatformUserHotelEntity> findUserHotel(Long userId, String hotelId) {
|
||||
return Optional.ofNullable(userHotelMapper.selectOne(Wrappers.<PlatformUserHotelEntity>lambdaQuery()
|
||||
.eq(PlatformUserHotelEntity::getUserId, userId)
|
||||
.eq(PlatformUserHotelEntity::getHotelId, hotelId)
|
||||
.last("LIMIT 1")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理同一用户其他默认酒店标记,保证普通用户默认酒店在写入逻辑上保持唯一。
|
||||
*/
|
||||
private void clearOtherDefaultHotels(Long userId, String hotelId) {
|
||||
PlatformUserHotelEntity update = new PlatformUserHotelEntity();
|
||||
update.setDefaultHotel(false);
|
||||
userHotelMapper.update(update, Wrappers.<PlatformUserHotelEntity>lambdaUpdate()
|
||||
.eq(PlatformUserHotelEntity::getUserId, userId)
|
||||
.ne(PlatformUserHotelEntity::getHotelId, hotelId)
|
||||
.eq(PlatformUserHotelEntity::getDefaultHotel, true));
|
||||
}
|
||||
|
||||
private LocalDateTime nowUtc() {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
-- M003 登录权限底座:数据库级约束普通用户只能有一个默认酒店。
|
||||
-- 上线前如已有脏数据,同一用户多个默认酒店时保留 id 最大的一条,其余改为非默认。
|
||||
UPDATE platform_user_hotel
|
||||
SET default_hotel = 0
|
||||
WHERE default_hotel = 1
|
||||
AND id NOT IN (
|
||||
SELECT keep_id
|
||||
FROM (
|
||||
SELECT MAX(id) AS keep_id
|
||||
FROM platform_user_hotel
|
||||
WHERE default_hotel = 1
|
||||
GROUP BY user_id
|
||||
) kept_defaults
|
||||
);
|
||||
|
||||
-- default_hotel_user_id 是默认酒店唯一约束辅助字段,default_hotel=1 时等于用户 ID,否则为空。
|
||||
ALTER TABLE platform_user_hotel
|
||||
ADD COLUMN default_hotel_user_id BIGINT GENERATED ALWAYS AS (
|
||||
CASE WHEN default_hotel = 1 THEN user_id ELSE NULL END
|
||||
);
|
||||
|
||||
-- MySQL 唯一索引允许多个 NULL,因此只会限制同一用户最多一条 default_hotel=1。
|
||||
CREATE UNIQUE INDEX uk_platform_user_hotel_one_default
|
||||
ON platform_user_hotel (default_hotel_user_id);
|
||||
Reference in New Issue
Block a user