数据字段保证唯一性

2023-09-22 09:51:27

数据字段保证唯一性

我们日常开发中,常见这么一个需求,要求一个code,一个name,需要保证code不重复,而code是用户输入的,常见的就比如一些字典等。

这个的我们常见的几种做法的话。

唯一键

要么就是直接以code作为主键,这样的话,伪代码基本就是

  @Transactional(rollbackFor = Exception.class)
       public void add(String code,String name){
              try{
                     mydao.insert(code,name);
              }catch (Exception e){
                     throw myException("code不能重复")
              }
       }

基本就是以code为唯一键,当出入出现重复性错误的话,捕获后抛出自己封装的异常。

这个当然可以,但是如果不让你加唯一键的话,你怎么做。

先查后插

经常见的做法的话,就是

 @Transactional(rollbackFor = Exception.class)
       public void add(String code,String name){
             //操作1,先查询数据库有没有
                 int count= mydao.select(code);
             if(count >0){
                    throw myException("code不能重复");
             }
             //操作2,插入数据库
             mydao.insert(code,name);
       }

看似逻辑没问题,但是如果并发高点,就会导致数据库中存在两条以上code一样的数据。

可是为什么呢。

我们来模拟下,事务1和事务2同时执行,code是一致的。

这个时候,事务1的操作1执行,发现满足条件。

事务2的操作1也执行,因为事务1还没提交,自然也没查到数据,满足插入条件。

这个时候,事务1和事务2的操作2都可以插入,自然就插入两条code一致的数据,就满足不了唯一性了。

数据库锁

我们可以用数据库的锁来解决。

  @Transactional(rollbackFor = Exception.class)
       public void add(String code,String name){
             //操作1,先查询数据库有没有 
              //select code from mytable where code =code for update
                 int count= mydao.selectforupdate(code);
             if(count >0){
                    throw myException("code不能重复");
             }
             //操作2,插入数据库
             mydao.insert(code,name);
       }

for update仅适用于InnoDB,且必须在事务块(BEGIN/COMMIT)中才能生效。在进行事务操作时,通过“for update”语句,MySQL会对查询结果集中每行数据都添加排他锁,其他线程对该记录的更新与删除操作都会阻塞。排他锁包含行锁、表锁。

这个的话,就需要注意的是,查询走的是索引还是全表扫描,要将深入的话,基本要讲到索引加锁机制了,我们就简单理解为,如果code走的索引,就行锁,不走就全表。

这样事务1和事务2同时执行,事务1执行操作1,发现加锁成功,事务2执行操作1的时候,发现加锁失败,那事务2就挂起了,只能等事务1执行提交事务后才能成功。

这样就保证唯一性。

但是这个缺点比较大的是,因为code如果是数据库中没有的code,往往会导致加锁的范围比较大。导致接口并发比较低。

分布式锁

我们可以用分布式锁来代替数据库锁。

     @Transactional(rollbackFor = Exception.class)
       public void add(String code,String name){
              //操作1,用code加锁,用阻塞式加锁,5s后加锁还失败就返回失败
             boolean success = myLock.trylock(code,5);
             if(!success){
                    throw myException("请重试");
             }
             try{
                    //数据库查询code
                    int count =mydao.selectBycode(code);
                    if(count >0){
                           throw myException("code不能重复");
                    }
                    //操作2,插入数据库
                    mydao.insert(code,name);
             }finally {
                    myLock.unLock(code);
             }
           
       }

用分布式锁通过code加锁,这样的话,不同code的插入不影响,同一个code同时插入的时候,只会有一个插入code执行。

注意还是要数据库查一下,加锁只是保证没有多个同一个code同时插入。不能保证数据库就没有code。

还有就是分布式锁的基本操作,try{}包一下后最终解锁。

总结

简答的话,数据库的唯一索引就好。但是唯一的业务逻辑比较烦的时候,考虑一下分布式锁。

更多推荐

数据不平衡GPT调研

数据不平衡判别式和生成式的区别是什么判别式模型(DiscriminativeModels)生成式模型(GenerativeModels)对比对于AE或者VAE这种生成式模型,其实更关注数据本身,那这种有什么好处?那对于判别式模型,它更关注什么呢?它存在什么样的弊端?比如可能落入局部最优,无法进行优化啥的展开讲讲这个判别

android 存储新特性

分区存储本页内容应用访问限制将分区存储与FUSE搭配使用FUSE和SDCardFSFUSE性能微调减轻与FUSE相关的性能影响隐私优势远超性能劣势MediaProvider和FUSE更新分区存储会限制应用访问外部存储空间。在Android11或更高版本中,以API30或更高版本为目标平台的应用必须使用分区存储。之前,在

性能测试监控指标及分析调优 | 京东云技术团队一、哪些因素会成为系统的瓶颈?

1.什么是MAF和MEF?MEF和MEF微软官方介绍:ManagedExtensibilityFramework(MEF)-.NETFramework|MicrosoftLearnMEF是轻量化的插件框架,MAF是复杂的插件框架。因为MAF有进程隔离和程序域隔离可选。我需要插件进程隔离同时快速传递数据,最后选择了MAF

【FAQ】安防视频监控平台EasyNVR无法控制云台,该如何解决?

TSINGSEE青犀视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入,并能对接入的视频流进行处理与多端分发,包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。在智慧安防等视频监控场景中,EasyNVR可提供视频实时监控直播、云端录像、云存储、录像检索与回看、

vue3如何导入使用自定义yaml配置文件

要在Vue3中导入和使用自定义的YAML配置文件,你可以按照以下步骤进行操作:安装所需的依赖:首先,确保你的项目中已经安装了vue和vue-router。你还需要使用js-yaml库来解析YAML文件,可以使用以下命令进行安装:npminstalljs-yaml创建YAML文件:在你的项目中创建一个YAML文件,用于存

Linux 软件包管理器-yum使用

文章目录前言一、yum使用1、什么是软件包2、yum源3、yumlist指令4、yuminstall指令5、yumremove指令二、git的使用1、gitee中仓库的创建2、仓库的克隆3、提交代码到远程仓库4、提交时可能遇到的问题5、.gitignore文件6、删除文件前言一、yum使用1、什么是软件包在Linux下

SLAM从入门到精通(消息传递)

【声明:版权所有,欢迎转载,请勿用于商业用途。联系信箱:feixiaoxing@163.com】前面我们只是编写了一个publisher节点,以及一个subscribe节点。有了这两个节点,它们之间就可以通信了。在实际生产中,我们除了简单的通信之外,要传递的数据可能还有很多。这个时候,我们就要构建一个消息体。这个消息体

C# 流Stream详解(3)——FileStream源码

【FileStream】构造函数如果创建一个FileStream,常见的参数例如路径Path、操作方式FileMode、权限FileAccess。这里说下FileShare和SafeFileHandle。我们知道在读取文件时,通常会有两个诉求:一是如何更快的读取文件内容;二是如何减少读取文件的消耗。常见的加快读取文件的

在ubuntu20.04中创建虚拟机:Oracle VirtualBox - 7中安装Windows-10(64bit)

问题描述之前一直在用ubuntu20.04,但是今天遇到一个需求:需要判定.exe文件是否可以正常运行,这样一来可能就需要一个虚拟机来佐助了,当然也搜了一些其他的处理办法,但是我大概看了一下,并不能满足我的需求。如果有需要请看:linux下如何完美运行exe文件?https://www.zhihu.com/questi

C#实现异步方式

在异步程序中,程序代码不需要严格按照编写时的顺序执行为了改善代码性能,有时候需要在一个新的线程中运行一部分代码有时候无需创建新的线程,但为了更好的利用单个线程的能力,需要改变代码的执行顺序也就是说:异步编程赋予代码非顺序执行的能力,让程序能够在部分耗时操作的同时,干其他的事情一、通过委托实现异步如果委托对象在调用列表中

【LeetCode-困难题】239. 滑动窗口最大值

文章目录题目方法一:单调双端队列题目方法一:单调双端队列if(deque.peekFirst()==nums[i-k])deque.removeFirst();这一步很关键,当队首元素(最大元素)是滑动窗口后要被抛弃的元素时,他就不能再是最大值了,就必须去掉,如果队首元素(最大元素)不是滑动窗口被抛弃的元素,则继续充当

热文推荐