精华内容
下载资源
问答
  • 2020-07-31 21:51:42

    参考 : https://blog.csdn.net/Lxinccode/article/details/107580753

    前提 : 数据库存在自增主键id

    定义变量

        processCount : 进程数量

        processIndex : 进程序号(从0开始)

        threadCount : 每个进程内线程数量

        threadIndex : 进程内线程序号(从0开始)

    思路

    每个进程内部for循环创建线程,创建的方法是调用其他Service的方法,该方法上有@Async注解,意思为每次调用创建一个新的线程执行该方法,方法内部是一个while(true)的方法,一直抽取数据及处理数据,处理完会删除数据。

    实现

    1.for循环创建线程

    for (int i = 0; i < threadCount; i++)
    	testService.handle();

    说明 : handle方法上加了@Async注解

    2.方法内部抽取数据逻辑

    查询数据的SQL有两个条件,and的关系

    1. id mod threadCount = threadIndex
    2. id mod processCount*threadCount = (mod(id,processCount)+threadIndex*processCount)

    这两个条件加上可以保证每个进程内的每个线程抽取的数据都不重复 

     

     

     

    END。

    更多相关内容
  • 多线程条件下插入Mysql数据库,根据时间戳判断处理数据 mybatis的写法 insert into table_name ( colume1,f_updated_at) values (#{colume1},#{updateAt}) ON DUPLICATE KEY UPDATE colume1 = IF(f_updated_at IS ...

    多线程条件下插入Mysql数据库,根据时间戳判断处理数据

    mybatis的写法

    insert into table_name ( colume1,f_updated_at) values (#{colume1},#{updateAt})
    ON DUPLICATE KEY UPDATE colume1 = IF(f_updated_at IS NULL OR VALUES(f_updated_at) > f_updated_at, VALUES(colume1), colume1)
    

    主要通过修改时间去判断是否满足入库条件。否则不触发修改。
    前提是要有unique Key
    多线程主要就是

     public static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    
        static {
            executor.setCorePoolSize(10);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(100000);
            executor.setThreadNamePrefix("hkex-async-slaOrder-");
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            executor.initialize();
        }
    
     CompletableFuture
                    .runAsync(() -> insert(msg), executor);//执行多线程任务
                  
    
    展开全文
  • 文章目录基础概念原因分析解决方案多线程插入解决:多线程更新解决 基础概念 幂等性 : 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。 简单来说:幂等就是一个操作,不论...

    基础概念

    幂等性 : 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
    简单来说:幂等就是一个操作,不论执行多少次,产生的效果和返回的结果都是一样的。
    幂等性操作:
    1、查询操作:查询一次和查询多次,在数据不变的情况下,查询结果是一样的。select是天然的幂等操作;

    2、删除操作:删除操作也是幂等的,删除一次和多次删除都是把数据删除。(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个) ;
    3.插入操作:插入情况下默认主键唯一,所以多次插入同一个数据不是幂等的
    4.更新操作: 这里分两种情况:

    1、update t set money=100  where id=1
    2、update t set money=money+100  where id=1
    

    第一种则是幂等的,第二种则是不幂等的

    总结:
    幂等与你是不是分布式高并发还有JavaEE都没有关系。关键是你的操作是不是幂等的。
    要做到幂等性,从接口设计上来说不设计任何非幂等的操作即可。譬如说需求是:当用户点击赞同时,将答案的赞同数量+1。改为:当用户点击赞同时,确保答案赞同表中存在一条记录,用户、答案。赞同数量由答案赞同表统计出来。在设计系统时,是首要考虑的问题,尤其是在像支付宝,银行,互联网金融公司等涉及的都是钱的系统,既要高效,数据也要准确,所以不能出现多扣款,多打款等问题,这样会很难处理,用户体验也不好。

    这里可参考我的另一篇文章:
    幂等问题 8种方案解决重复提交

    原因分析

    如下这种操作很常见:

    if(用户不存在)
    {
        xxxxx
        存储用户到数据库
    }
    else
    {
        重复推送,不采取任何措施
    }
    

    这个操作还没有执行完毕,第二条拥有相同数据的线程已经进入并通过了if的检验,导致数据库存储了两条相同的数据。这就是是多线程的并发导致了程序的判断逻辑失效。

    解决方案

    单机模式下,简单采用sync即可,这里讨论分布式情景下避免重复插入问题
    这里主要说下数据库解决多线程,其余方案可参考上文中提到的:

    幂等问题 8种方案解决重复提交

    多线程插入解决:

    1、 insert时带有where条件的写法(类似于索引)
    1.1 、插入单条记录

    普通的 INSERT INTO 插入:
    INSERT INTO card(cardno, cardnum) VALUES('1111', '100');

    对于普通的 INSERT 插入,如果想要保证不插入重复记录,我们只有对某个字段创建唯一约束实现(比如:cardno卡号不能重复);
    如果要保证多个字段不会重复,可以考虑联合唯一索引!
    创建索引后程序处理:

    if (该cardno在数据库表中存在) {  
        update();  
    } else {   
        try {  
             insert();  
             //违反唯一性约束会报异常:InvocationTargetException 
             } catch (InvocationTargetException e) {  
             //如果重复插入已经有数据,则进行更新
             update();  
         }   
    }  
    

    这里还有个问题,就是如果表中记录逻辑删除的时候采用唯一索引会出现BUG

    重点在这里
    那有没有不创建唯一约束,仅通过 INSERT INTO 一条语句实现的方案呢?

    答案:有的, INSERT INTO IF EXISTS 具体语法如下:
    INSERT INTO table(field1, field2, fieldn) SELECT 'field1', 'field2', 'fieldn' FROM DUAL WHERE NOT EXISTS(SELECT field FROM table WHERE field = ?)
    其中的 DUAL 是一个临时表,不需要物理创建,这么用即可。

    针对上面的card示例的改造如下:
    INSERT INTO card(cardno, cardnum) SELECT '111', '100' FROM DUAL WHERE NOT EXISTS(SELECT cardno FROM card WHERE cardno = '111')
    1.2、插入多条记录

    INSERT INTO user  (id, no,add_time,remark)
    select * from (
    SELECT 1 id, 1 no, NOW() add_time,'1,2,3,1,2' remark FROM DUAL
    UNION ALL
    SELECT 1 no, 2 no, NOW() add_time,'1,2,3,1,2' remark FROM DUAL
    UNION ALL
    SELECT 1 no, 3 no, NOW() add_time,'1,2,3,1,2' remark FROM DUAL
    ) a where not exists (select no from user b where a.no = b.no)
    

    上述是实现user表的no字段不重复,插入三条记录。
    另外,附上mybatis批量写入no字段不重复的实现语句。

    INSERT INTO user (id, no,add_time,result)
    select * from (
    <foreach collection="list" item="obj" separator=" UNION ALL " >
    SELECT #{obj.id} id, #{obj.no} no, #{obj.addTime} add_time,#{obj.result} result FROM DUAL
    </foreach>
    ) a where not exists (select no from user b where a.no = b.no)
    

    多线程更新解决

    1、update使用 乐观锁 version版本法
    情景:
     比如两个用户同时购买一件商品,库存只有1件了!在数据库层面实际操作应该是库存进行减2操作,但是由于高并发的情况,第一个用户购买完成进行数据读取当前库存并进行减1操作,由于这个操作没有完全执行完成,这样就会出现商品超卖!

    select goods_num,version from goods where goods_name = "小本子";
    update goods set goods_num = goods_num -1,version =查询的version值自增 where goods_name ="小本子" and version=查询出来的version;
    

    为什么加个version字段就满足了呢,因为数据库本身特性的帮忙,update语句执行的时候,如果更新的时候update语句不走索引就会将表锁住保证了一个时刻只有一个线程能进入更新,等这次更新释放锁以后才会执行下一次的update操作,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据,这样就能保证了程序的安全性。
    这种在大数据量和高并发下效率依赖数据库硬件能力,可针对非核心业务
    2.使用select … for update 悲观锁
    这种和 synchronized 锁住先查再insert or update一样,但要避免死锁,效率也较差,针对单体 请求并发不大 可以推荐使用

    获取数据的时候加锁获取:select * from table_xxx where id='xxx' for update;
    注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的;悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用;
    这种在大数据量和高并发下效率依赖数据库硬件能力,可针对非核心业务

    参考文章:
    https://www.cnblogs.com/ganhaiqiang-20130831/articles/4478472.html
    https://www.cnblogs.com/lihuanliu/p/6764048.html

    幂等性解决:
    https://www.cnblogs.com/baizhanshi/p/10449306.html
    https://www.cnblogs.com/aspirant/p/11628654.html

    展开全文
  • 下面小编就为大家带来一篇多线程死锁的产生以及如何避免死锁方法(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 多线程 取数据必须不重复的方案

    千次阅读 2018-10-16 15:06:15
    最近一直在处理数据上传和采集的问题, 因为写在asp.net 里面的web服务默认就是多线程的, 一个请求就是一个线程… 所以多线程之间为了不读取重复的数据, 就成了问题. 数据必须严格不重复, 同样的数据绝对不能处理2次...

    最近一直在处理数据上传和采集的问题, 因为写在asp.net 里面的web服务默认就是多线程的, 一个请求就是一个线程… 所以多线程之间为了不读取重复的数据, 就成了问题.

    数据必须严格不重复, 同样的数据绝对不能处理2次…
    多线程就更不能出现重复读取的现象了.

    自己现在也用的是另外一套非常蹩脚的方法, . 把数据取出来然后在内存里面通过lock(object)的形式实现数据不重复处理的办法. 但是这又牵扯到数据的取出和更新, 也比较麻烦. 虽然实现了, 但是后续的修改和变更逻辑极其复杂.

    后来再百度上又看了一遍找到了我认为最完美的方法,其它的我感觉都不怎么优美.
    文章是下面这个.

    找到了一种专门针对sqlserver的. 可以通过先更新同时通过deleted表(就像是在触发器中使用一样)取出的方式,来保证每条记录只会被读取一次。

    
    declare @Rowid table(rowid int);
    BEGIN
     set rowcount 100; --一次读取的行数
     --先将要读取的记录状态更新
     update Sms set [status]= 1  output deleted.ID into @Rowid Where [status] = 0;
     --读取刚更新状态的记录
     select  * from Sms where ID in (select Rowid from @Rowid);
    END
    

    但是这种只是针对sqlserver的, 所以在这个的基础上, 我设计改进了另外一种通用的方法.
    同样是发短信为例,
    逻辑过程如下

    1. 开启事务, 保证update语句互不影响,
    2. update top 100 Sms set status=@ThreadId where status = 0 ;
    3. select  * from Sms where status = @ThreadId;
    4. 提交事务
    

    如果不想影响status的状态, 可以改成

    1. 开启事务, 保证update语句互不影响,
    2. update top 100 Sms set processer = @ThreadId where status = 0 ;
    3. select  * from Sms where status = 0 and processer = @ThreadId;
    4. 提交事务
    

    这样就可以在这个请求中, 确保取到的数据,没有被其它线程取到. 因为每个线程的ThreadId肯定是不一样的.

    当然这个逻辑也可以升级一下把ThreadId 改成其它的某个有规则的能够区分不同的任务的编号, 如果是分布式任务, 可以考虑前面再加个机器号.

    或者把这个@ThreadId改成 orcale中的 sequence

    如果是多线程只有一个程序在运行的话, 可以把这个数值通过单列模式在静态变量里面取数据.
    每次任务执行前取一个 任务ID 当作@ThreadId.

    我实际在用的代码

    BBZQ表中加了3个字段

    字段名类型说明
    W_JOBIDstring任务ID,主要用它来分割不同的任务
    W_PROCESSTIMEdate处理时间, 主要用在处理失败的或者未处理的, 超时10分钟后会强行再次被获取
    ISUPLOADint是否已上传,上传成功后会更新此字段
        private static int _JobId = 0;
        public string GetJobId()
        {
            lock (SynCacheObject)
            {
                _JobId = _JobId + 1;
                return "JOB"+DateTime.Now.ToString("yyyyMMddHHmmssfff_")+_JobId;
            }
        }
    public List<DataChangeLog> GetCHGAndWSWJobs()
            {
                //ReturnLogs rlog = new  ReturnLogs();
                 
                    var jobid = GetJobId(); //这里通过lock 锁定取得唯一的编号
                    //AND(W_JOBID is null OR  W_PROCESSTIME < SYSDATE - 10 / 1440)-- 超时10分钟处理失败的或者未处理的的也会强行再次被获取,因为处理的部分有防止重复执行的功能, 所以可以重复执行
                    //order by EXECUTEDATE asc   如果不按照事件发生时间排序,反审核之后又审核的的数据可能会被删掉
                    //with temptable as (**) 临时表的写法是因为orcale 在 update 语句中 子查询不支持orderby  所以用了临时表.
                    var sql = @"update BBZQ set W_JOBID = :JobId, W_PROCESSTIME=SYSDATE where JGID=2 AND XH in (
                                    with temptable as(
    				                        select XH
    				                        from BBZQ 
    				                        where ROWNUM < 200
    				                        AND ( W_JOBID is null OR  W_PROCESSTIME < SYSDATE - 10/1440 )
    				                        AND ISUPLOAD = 0 
    				                        AND EXECUTEDATE > SYSDATE - 30 
    				                        AND STATUS in(15, 16)   
    				                        AND  JGID=2
    				                        order by EXECUTEDATE asc
    		                        ) 
                                    select XH from temptable
                                )";
    
                    var i =  DB.Execute(sql, new { JobId = jobid });
                    if (i==0) //如果没有更新到数据也就直接返回了, 无需再次查询
                    {
                        return null;
                    }
                    sql = @" SELECT *
                            FROM  BBZQ
                            WHERE W_JOBID = :JobId
                            ORDER BY EXECUTEDATE asc";
                    //   throw new Exception(sql);
                    return   DB.Query<DataChangeLog>(sql, new { JobId = jobid }).ToList();
                     
            }
    
    展开全文
  • java 多线程 出现数据重复调用问题线程操作过程描述:1、线程查询数据库表(table1)数据,并遍历修改记录状态(防止出现数据重复调用)。(此操作加入了同步锁)2、调用接口,获取返回的状态。3、把数据插入到数据库...
  • 如果type=system,表示后台线程,用来限制mysql自己的线程,比如Innodb purge thread,innodb read thread等等。 vcpu 代表cpu的逻辑核数,这里0-1代表前两个核被绑定到这个RG。可以用lscpu,top等列出自己的CPU相关...
  • Qt数据库连接池-多线程连接数据库

    千次阅读 热门讨论 2021-01-05 17:21:56
    之前在Qt上使用数据库,而Qt上一个连接只能在一个线程上使用,所以就写了一个数据库连接池,现在上传一下自己的源码,还是比较简单的使用。注释比较清晰,就不单独说了,直接上源码。 一、头文件 #ifndef ...
  • 主要介绍了MySql三种避免重复插入数据的方法,帮助大家更好的理解和使用MySQL数据库,感兴趣的朋友可以了解下
  • Mysql 表字段修改 并发情况下避免重复一,场景二,问题三,解决方案 一,场景  个用户同时修改用户名时,存在用户名相同的情况,而由于业务需要,用户名是不允许相同的,需要避免重复。 二,问题  sql语句举例...
  • 10线程同时操作,频繁出现插入同样数据的问题。虽然在插入数据的时候使用了: insert inti tablename(fields….) select @t1,@t2,@t3 from tablename where not exists (select id from tablename where t1=@t1,t2=@...
  • 一家文学网站向我系统推多线程低并发推送数据,我这边观察日志和数据库,发现有一个作者被存储了2次到数据库中。按照程序的编写逻辑,重复的数据是会被判断出来不被存储的。2.原因分析 由于网络原因,客户可能连续推...
  • 使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线、电量不足等情况下,这就需要使用到断点...
  • 每日一更,最近的问题真是一个接一个,真的让人头大,昨天遇到一个多线程的问题问题描述一下: 有一个线程的问题,就是假如 我有一个文件,然后这个文件有很多条数据,假如有两个字段,一个学号一个钱,(我的需求是...
  • 多线程锁定同一资源会造成死锁 线程池中的任务使用当前线程池也可能出现死锁 参考连接: https://blog.csdn.net/qq_35064774/article/details/51793656 情况一: 死锁是两个或多个线程互相等待对方所有用的资源...
  • Java多线程:解决高并发环境下数据插入重复问题

    万次阅读 热门讨论 2016-11-23 17:56:53
    一家文学网站向我系统推多线程低并发推送数据,我这边观察日志和数据库,发现有一个作者被存储了2次到数据库中。按照程序的编写逻辑,重复的数据是会被判断出来不被存储的。 2.原因分析 由于网络原因,客户可能...
  • 对于第一种重复,比较容易解决,只需在查询语句中使用distinct关键字去重,几乎所有数据库系统都支持distinct操作。发生这种重复的原因主要是表设计不周,通过给表增加主键或唯一索引列即可避免。 select distinct *...
  • # 查询数据库当前事务隔离级别 mysql> select @@global.transaction_isolation,@@transaction_isolation; +--------------------------------+-------------------------+ | @@global.transaction_isolation | @@...
  • 数据库有一字段:orderNo,orderNo的规则:20170327000001、20170327000002依次往后累加。。。并发时怎么避免存入重复
  • Java多线程超详解

    万次阅读 多人点赞 2019-06-11 01:00:30
    随着计算机的配置越来越高,我们需要将进程进一步优化,细分为线程,充分提高图形化界面的多线程的开发。这就要求对线程的掌握很彻底。 那么话不多说,今天本帅将记录自己线程的学习。 线程的相关API //获取当前...
  • 数据库插入失败引出的多线程问题

    千次阅读 2016-06-29 15:38:35
    昨天遇到一个奇葩问题, 一组不重复的数据在插入数据库的时候 数据 a 出现unique failed , 但是插入成功 数据 b 没有报错, 但是插入失败 并且发现for循环内都遍历不到数据b , 但是for循环外是可以打印到它...
  • 基于 Zookeeper 纯 Java 实现,调度与执行同样是分离的,调度端可以控制、监控任务执行状态,可以让任务能够被动态的分配到个主机的 JVM 中的不同线程组中并行执行,保证任务能够不重复、不遗漏的执行。...
  • 所有的方法都先不考虑性能问题,也不考虑业务,只看逻辑上能否达到去重复插入,因为第一,如果唯一性是必须要保证的,那么只能在先实现了,再去考虑优化;第二,如果能通过调整业务来规避,那我后面说的都是废话了...
  • 通过前三篇博文的学习,已经编码实现多线程下载功能的核心代码,通过多个线程之间的管理和调度来处理下载任务,...多线程下载添加数据库支持 greenDao开源库自动生成数据库相关代码 完善网络请求接口中的进度更新功能
  • 多线程并发取值重复问题

    千次阅读 2016-09-11 21:08:42
    取用时分秒+毫秒级别未能避免多线程并发取数时报错public synchronized static String getBatchDate(){ String serialNo = DateUtil.getDateFormat(new Date(), "yyyyMMddHHmmss"); return serialNo; }...
  • 数据库的脏读、不可重复读、幻读都和事务的隔离性有关。所以先了解一下事务的4大特性。 事务的4大特性(ACID):原子性(Atomicity):事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么全部不执行,...
  • Java基础之单例模式在多线程环境下的安全问题 目录: 单线程下的单例模式 多线程下的单例模式 单例模式volatile分析 1. 单线程下的单例模式 1. 单线程下单例模式代码 public class SingletonDemo {...
  • java 多线程 面试题整理(更新......)

    千次阅读 2021-11-30 16:23:06
    3、什么是同步执行和异步执行4、Java中实现多线程有几种方法?(较难)(1)继承Thread类(2)实现runable接口(3)实现Callable接口(创建FutureTask(Callable)对象)5、Future接口,Callable接口,FutureTask实现类的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 129,748
精华内容 51,899
关键字:

多线程数据库避免重复

友情链接: lose.zip