欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用redis处理并发写的工作总结

程序员文章站 2022-06-25 23:23:04
...

     公司运营部那边需要做一个营销活动-springrain活动,上午和team leader、同一组的同事和产品经理一同听取并讨论了活动的需求,以及一些细节性的东西。

      大致需求是这样的,由于保密的原因,这里只列出大概的需求。就是每一个阶段都有一个浇水的滴数,达到这个浇水的滴数,app上的小数就成长一个阶段,以此类推。一共有5个阶段。

      后面我和同事就开始进行数据库表的相关设计,以及涉及到提供给app前端的接口方法。这是每一次做后端接口的必要的工作步骤。api的接口方法,我和另一个同事进行了不同的分工,每人写几个接口方法,同时进行自测并和前端人员进行联调。

      在设计到给树浇水的这个接口的时候,同事一开始是对于每一个浇水的人,都直接进行数据库操作,保存每一个会员的浇水记录,接口很快就写完并发布了。后续进行测试的时候,发现了问题。同事写了一个python的脚本进行多线程并发去测试该接口,出来的结果出人意料的出错了,有丢失更新的问题。或者说是并发导致了数据被覆盖了。所以,对于存在并发的这种操作,我们想到的方法就是加锁,或者同步。

     加锁,这种操作我们一般分为业务加锁和数据库层面的锁。数据库层面的锁我们可以用悲观锁也可以用乐观锁,但通常这种问题我们不会再数据库层面进行处理。所以这种解决方案我们就忽略到,有对悲观锁和乐观锁不明白的童鞋,请自行google。

   这里我们说一下业务层面的加锁也就是通常的同步操作,对于java层面的同步一般对于并发的性能支持的不好,如果并发量比较大,会造成排队甚至丢失连接的情况。所以这种方案对于我们也不可行。最后讨论的结果是使用基于生产者-消费者的模式解决并发问题,是并发从并发变为同步操作,从多线程变单线程。

这里我只写一下伪代码:

public void save(){

      //组织数据
     //将数据放入到队列,返回
     jedisClient.lpop(xxxx)
}

 

    然后启动一个后台线程池从队列中取出需要保存的数据对象,进行数据库操作。类型的伪代码如下:

ScheduledExecutorService executor = Executors.newFixedThreadPool(6);
executorService.execute(new Runnable() {
            @Override
            public void run() {
              //数据库操作
       
            }
}

 从而解决上面的问题,这里面的队列是redis内部实现的一个简单的队列