场景:
同一个问题,每个用户只能有一个回答
解决方案1:
回答问题(新增回答记录)之前,根据 问题ID 和 用户ID 查询用户是否已经回答指定问题,如果已经有回答则提示用户不能重复回答。
分析:如果前端同时发起多个一模一样的请求(不能相信前端的任何操作),那么数据还是会重复插入。先查后插入的思路在并发下总会存在这样的问题。pass 掉!
解决方案2:
数据库表建立 问题ID 和 用户ID 的组合唯一索引,在程序中捕获 DuplicateKeyException 异常,如果捕获到该异常,则为唯一键冲突,提示用户不能重复回答(当然,也得保证不是由其它唯一索引引起的异常)
分析:该方法在能确保在数据库中数据的唯一性,一般足够了。但是在本次场景中,删除是逻辑位标记删除,也就是说其实表中还是会操作同样的 问题ID 和 用户ID 有多条数据的结果,只不过有效的(没有标记为删除的)结果只有一条,这个时候用唯一索引就不适合了,只能寻求其它方法。
解决方案3:
使用 not exists 条件语句。根据语句执行的返回值判断是否成功。如果返回值为 0,说明没有执行插入操作,即数据库中已经有了重复的数据。
不要忘记限制条数为1 ( 后面的 limit 1 ),否则还是会插入多条重复的数据。
insert into t_answer (ID, QUESTION_ID, CREATE_USER_ID, CREATE_TIME)
select
#{id,jdbcType=VARCHAR}, #{questionId,jdbcType=VARCHAR},
#{createUserId,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}
from dual where not exists
(
select id from t_answer where
create_user_id = #{createUserId,jdbcType=VARCHAR}
and question_id = #{questionId,jdbcType=VARCHAR}
and DELETE_TAG = 0
) limit 1
以上是在 mybaties 中的用法,作为参考,实际使用中也可以自己去拼接。其中 DELETE_TAG 即为删除标识,为 0 表示有效数据,为 1 表示已删除数据。
网友评论