背景

近期公司项目中加了一个积分机制,用户登录签到会获取登录积分,但会出现一种现象就是用户登录时会增加双倍积分,然后生成两个积分记录。此为问题 

问题分析

项目采用微服务架构,下图为积分机制流程

 
worker通过分析日志记录从而判断用户当天积分是否增加,进而进行积分增加增添记录或者无操作。
两个worker对积分数据库进行同时写入,造成积分双倍增加的情况,那问题找到了,就是对数据库并发写入的问题。
解决方法,加锁 

  • 共享锁

    • 定义:共享锁就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。
    • 举例:比如有一个房间,你和你的女朋友都有要是可以进入这个房间,这就是共享锁,这个房间是你跟你的女朋友共享的 
  • 互斥锁 
    • 定义:互斥锁,也称作独占锁,排它锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。
    • 举例:就比如蹲厕所吧,同一时间一个茅坑由你一个人独占,这就叫做独占锁,互斥锁,其他人是不可以用的(当然,特殊情况除外)
  • 乐观锁

    • 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
  • 悲观锁 
    • 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

当然,这次解决问题采用的是悲观锁,互斥锁 
 

SQLAlchemy

项目是采用SQLAlchemy对mysql进行操作,题目是SQLAlchemy引发的思考,当然就少不了SQLAlchemy这个主角。SQLAlchemy 提供 with_for_update 函数 进行 锁的操作 .
  1. session.Query(User).with_for_update().first()
  2. session.Query(User).with_for_update(read=True).first()

完整形式为:

  1. with_for_update(read=False, nowait=False, of=None)
  1. read
  2. 是标识加互斥锁还是共享锁. 当为 True 时, for share 的语句, 是共享锁. 多个事务可以获取共享锁, 互斥锁只能一个事务获取. "多个地方"都希望是"这段时间我获取的数据不能被修改, 我也不会改", 那么只能使用共享锁.
  3. nowait
  4. 其它事务碰到锁, 是否不等待直接"报错".
  5. of
  6. 指明上锁的表, 如果不指明, 则查询中涉及的所有表(行)都会加锁.

补充

在用SQLAlchemy对数据库操作的过程中出现这样一个现象,当在session.query()时,如果之前有session.add()操作,即使尚未进行commit操作,在query时也会查询到这个尚未真正插入数据库的对象。这个有待探究 ,后续补充
 
 
 
 

SQLAlchemy并发写入引发的思考的更多相关文章

  1. 【原创】记一次MySQL大表高并发写入引发CPU飙升的排障过程

    目录 一.故障现象... 1 二.初步分析... 2 三.排障过程... 2 1.排查是否QPS或insert并发请求上升导致问题发生... 2 2.排查是否锁资源等待或block导致了insert变 ...

  2. 曲演杂坛--一条DELETE引发的思考

    原文:曲演杂坛--一条DELETE引发的思考 场景介绍: 我们有一张表,专门用来生成自增ID供业务使用,表结构如下: CREATE TABLE TB001 ( ID ,) PRIMARY KEY, D ...

  3. Go select 死锁引发的思考

    Go select 死锁引发的思考 https://mp.weixin.qq.com/s/Ov1FvLsLfSaY8GNzfjfMbg一文引发的延续思考 上文总结 总结一 package main i ...

  4. 用读写锁三句代码解决多线程并发写入文件 z

    C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...

  5. Spring之LoadTimeWeaver——一个需求引发的思考---转

    原文地址:http://www.myexception.cn/software-architecture-design/602651.html Spring之LoadTimeWeaver——一个需求引 ...

  6. C#使用读写锁三行代码简单解决多线程并发写入文件时线程同步的问题

    (补充:初始化FileStream时使用包含文件共享属性(System.IO.FileShare)的构造函数比使用自定义线程锁更为安全和高效,更多内容可点击参阅) 在开发程序的过程中,难免少不了写入错 ...

  7. 由SecureCRT引发的思考和学习

    由SecureCRT引发的思考和学习 http://mp.weixin.qq.com/s?__biz=MzAxOTAzMDEwMA==&mid=2652500597&idx=1& ...

  8. 解决一道leetcode算法题的曲折过程及引发的思考

    写在前面 本题实际解题过程是 从 40秒 --> 24秒 -->1.5秒 --> 715ms --> 320ms --> 48ms --> 36ms --> ...

  9. leveldb - 并发写入处理

    在并发写入的时候,leveldb巧妙地利用一个时间窗口做batch写入,这部分代码值得一读: Status DBImpl::Write(const WriteOptions& options, ...

随机推荐

  1. 为什么说Java中只有值传递----说服自己

    在开始深入讲解之前,有必要纠正一下大家以前的那些错误看法了.如果你有以下想法,那么你有必要好好阅读本文. 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递.如果是个引用,就 ...

  2. kukubeadm 1.6.1 + docker1.2.6 安装问题

    kubeadm init --apiserver-advertise-address=192.168.20.229 --pod-network-cidr=10.244.0.0/16 kubelet: ...

  3. EF Core 入门

    官方文档地址 https://docs.microsoft.com/zh-cn/aspnet/?view=aspnetcore-2.2#pivot=core EF Core 使用 1. 创建数据库上下 ...

  4. salt常用命令(一)

    查看模块包含哪些函数 salt 'node' sys.list_functions test 查看函数的用法 salt 'node' sys.doc test.echo 使用模块中的函数 salt ' ...

  5. springboot项目打war包pom设置

    <build> <finalName>PayManager</finalName><!--打包后的名字PayManager.war--> <plu ...

  6. [图解tensorflow源码] Graph 图模块 —— Graph Loading

  7. 流程一直处于Running状态,应该怎么停止?

    流程一直处于Running状态,应该怎么停止? 概述 我们有遇到这种情况:可能由于某些原因,流程发起后一直处于Running状态,然后我们想Stop掉这些出问题的流程,这个时候你在Workspace里 ...

  8. NRF52832 能烧写代码 但是不运行 ,是因为没有烧写协议栈

    仿真进入的状态 , MOVES R0.R0 请烧写  协议栈 ,自行百度!

  9. pH计

    pH计 测量原理 pH计主要用于测量液体中的氢离子浓度.准确地说是测量氢离子活性,得出酸性.中性还是碱性的数值,在自来水.河水.饮料.食品.污水.医疗和化工等领域广泛地使用工业用液体分析仪. pH计原 ...

  10. 中国气象网 气象数据开放平台 API用法 (Android)

    因为要做个天气应用.须要找个天气的API.上网上搜了下都是那几个,并且基本都过时了.百度有个天气API,只是貌似仅仅能提供当天的.网上提到的中国气象接口的文章,大都用的时旧API,有的被封了,有的永远 ...