fix: 收藏 toggle 用原生 SQL 绕过逻辑删除,彻底解决重新收藏冲突
This commit is contained in:
@@ -3,13 +3,35 @@ package com.emotion.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.emotion.entity.EventFavorite;
|
import com.emotion.entity.EventFavorite;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 人生事件收藏Mapper接口
|
* 人生事件收藏 Mapper
|
||||||
*
|
*
|
||||||
* @author huazhongmin
|
* @author huazhongmin
|
||||||
* @date 2026-07-19
|
* @date 2026-07-19
|
||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface EventFavoriteMapper extends BaseMapper<EventFavorite> {
|
public interface EventFavoriteMapper extends BaseMapper<EventFavorite> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户对某事件的收藏记录(包含已逻辑删除的记录,绕过 @TableLogic 自动过滤)
|
||||||
|
* 用于 toggle 时判断是否存在历史记录,避免重新收藏时产生重复记录
|
||||||
|
*/
|
||||||
|
@Select("SELECT * FROM t_event_favorite WHERE user_id = #{userId} AND event_id = #{eventId} LIMIT 1")
|
||||||
|
EventFavorite selectAnyByUserAndEvent(@Param("userId") String userId, @Param("eventId") String eventId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物理删除记录(绕过 @TableLogic 的逻辑删除)
|
||||||
|
*/
|
||||||
|
@Update("DELETE FROM t_event_favorite WHERE id = #{id}")
|
||||||
|
int physicalDeleteById(@Param("id") String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复逻辑删除的记录为已收藏状态
|
||||||
|
*/
|
||||||
|
@Update("UPDATE t_event_favorite SET is_deleted = 0, update_time = NOW() WHERE id = #{id}")
|
||||||
|
int restoreById(@Param("id") String id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package com.emotion.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.emotion.entity.ScriptFavorite;
|
import com.emotion.entity.ScriptFavorite;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 剧本收藏Mapper接口
|
* 剧本收藏Mapper接口
|
||||||
@@ -12,4 +15,23 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ScriptFavoriteMapper extends BaseMapper<ScriptFavorite> {
|
public interface ScriptFavoriteMapper extends BaseMapper<ScriptFavorite> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户对某剧本的收藏记录(包含已逻辑删除的记录,绕过 @TableLogic 自动过滤)
|
||||||
|
* 用于 toggle 时判断是否存在历史记录,避免 unique key 冲突
|
||||||
|
*/
|
||||||
|
@Select("SELECT * FROM t_script_favorite WHERE user_id = #{userId} AND script_id = #{scriptId} LIMIT 1")
|
||||||
|
ScriptFavorite selectAnyByUserAndScript(@Param("userId") String userId, @Param("scriptId") String scriptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物理删除记录(绕过 @TableLogic 的逻辑删除)
|
||||||
|
*/
|
||||||
|
@Update("DELETE FROM t_script_favorite WHERE id = #{id}")
|
||||||
|
int physicalDeleteById(@Param("id") String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复逻辑删除的记录为已收藏状态
|
||||||
|
*/
|
||||||
|
@Update("UPDATE t_script_favorite SET is_deleted = 0, update_time = NOW() WHERE id = #{id}")
|
||||||
|
int restoreById(@Param("id") String id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,23 +56,17 @@ public class EventFavoriteServiceImpl extends ServiceImpl<EventFavoriteMapper, E
|
|||||||
throw new BusinessException("事件不存在或无权限访问");
|
throw new BusinessException("事件不存在或无权限访问");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询时忽略逻辑删除标记,避免 unique key 冲突导致无法重新收藏
|
// 查询时绕过 @TableLogic 自动过滤,包含已逻辑删除的记录
|
||||||
LambdaQueryWrapper<EventFavorite> w = new LambdaQueryWrapper<>();
|
// 避免重新收藏时产生重复记录
|
||||||
w.eq(EventFavorite::getUserId, userId)
|
EventFavorite existing = baseMapper.selectAnyByUserAndEvent(userId, eventId);
|
||||||
.eq(EventFavorite::getEventId, eventId);
|
|
||||||
|
|
||||||
EventFavorite existing = this.getOne(w);
|
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
if (existing.getIsDeleted() != null && existing.getIsDeleted() == 0) {
|
if (existing.getIsDeleted() != null && existing.getIsDeleted() == 0) {
|
||||||
// 已收藏 -> 物理删除(取消收藏)
|
// 已收藏 -> 物理删除(取消收藏)
|
||||||
this.removeById(existing.getId());
|
baseMapper.physicalDeleteById(existing.getId());
|
||||||
r.setIsFavorited(false);
|
r.setIsFavorited(false);
|
||||||
} else {
|
} else {
|
||||||
// 历史逻辑删除记录 -> 恢复为已收藏
|
// 历史逻辑删除记录 -> 恢复为已收藏
|
||||||
this.lambdaUpdate()
|
baseMapper.restoreById(existing.getId());
|
||||||
.set(EventFavorite::getIsDeleted, 0)
|
|
||||||
.eq(EventFavorite::getId, existing.getId())
|
|
||||||
.update();
|
|
||||||
r.setIsFavorited(true);
|
r.setIsFavorited(true);
|
||||||
if (existing.getCreateTime() != null) {
|
if (existing.getCreateTime() != null) {
|
||||||
r.setFavoriteTime(existing.getCreateTime().format(FMT));
|
r.setFavoriteTime(existing.getCreateTime().format(FMT));
|
||||||
|
|||||||
@@ -56,23 +56,17 @@ public class ScriptFavoriteServiceImpl extends ServiceImpl<ScriptFavoriteMapper,
|
|||||||
throw new BusinessException("剧本不存在或无权限访问");
|
throw new BusinessException("剧本不存在或无权限访问");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询时忽略逻辑删除标记,避免 unique key 冲突导致无法重新收藏
|
// 查询时绕过 @TableLogic 自动过滤,包含已逻辑删除的记录
|
||||||
LambdaQueryWrapper<ScriptFavorite> w = new LambdaQueryWrapper<>();
|
// 避免 unique key 冲突导致无法重新收藏
|
||||||
w.eq(ScriptFavorite::getUserId, userId)
|
ScriptFavorite existing = baseMapper.selectAnyByUserAndScript(userId, scriptId);
|
||||||
.eq(ScriptFavorite::getScriptId, scriptId);
|
|
||||||
|
|
||||||
ScriptFavorite existing = this.getOne(w);
|
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
if (existing.getIsDeleted() != null && existing.getIsDeleted() == 0) {
|
if (existing.getIsDeleted() != null && existing.getIsDeleted() == 0) {
|
||||||
// 已收藏 -> 物理删除(取消收藏)
|
// 已收藏 -> 物理删除(取消收藏)
|
||||||
this.removeById(existing.getId());
|
baseMapper.physicalDeleteById(existing.getId());
|
||||||
r.setIsFavorited(false);
|
r.setIsFavorited(false);
|
||||||
} else {
|
} else {
|
||||||
// 历史逻辑删除记录 -> 恢复为已收藏
|
// 历史逻辑删除记录 -> 恢复为已收藏
|
||||||
this.lambdaUpdate()
|
baseMapper.restoreById(existing.getId());
|
||||||
.set(ScriptFavorite::getIsDeleted, 0)
|
|
||||||
.eq(ScriptFavorite::getId, existing.getId())
|
|
||||||
.update();
|
|
||||||
r.setIsFavorited(true);
|
r.setIsFavorited(true);
|
||||||
if (existing.getCreateTime() != null) {
|
if (existing.getCreateTime() != null) {
|
||||||
r.setFavoriteTime(existing.getCreateTime().format(FMT));
|
r.setFavoriteTime(existing.getCreateTime().format(FMT));
|
||||||
|
|||||||
Reference in New Issue
Block a user