redis与mysql的数据一致性问题(事务一致性)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: redis与mysql的数据一致性问题(事务一致性)

redis与mysql的数据一致性问题(事务一致性)

案例:考虑一个在线购物应用,其中有一个购物车服务,购物车信息存储在MySQL中,同时为了提高性能,购物车中的商品数量也被缓存到了Redis。用户在购物车中添加商品时,需要保证购物车数量在MySQL和Redis中的更新是原子性的,以避免不一致的情况。

# Python代码示例 - 添加商品到购物车的逻辑
import redis
import MySQLdb
def add_to_cart(user_id, product_id, quantity):
    redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)
    mysql_conn = MySQLdb.connect(host='localhost', user='user', password='password', db='ecommerce')
    cursor = mysql_conn.cursor()
    try:
        # 开始MySQL事务
        mysql_conn.begin()
        # 从MySQL中获取购物车中的商品数量
        cursor.execute(f'SELECT quantity FROM shopping_carts WHERE user_id={user_id} AND product_id={product_id}')
        result = cursor.fetchone()
        if result:
            # 商品已存在,更新数量
            new_quantity = result[0] + quantity
            cursor.execute(f'UPDATE shopping_carts SET quantity={new_quantity} WHERE user_id={user_id} AND product_id={product_id}')
        else:
            # 商品不存在,插入新记录
            cursor.execute(f'INSERT INTO shopping_carts (user_id, product_id, quantity) VALUES ({user_id}, {product_id}, {quantity})')
        # 提交MySQL事务
        mysql_conn.commit()
        # 更新Redis中购物车缓存
        redis_client.hset(f'user:{user_id}:cart', product_id, quantity)
    except Exception as e:
        # 发生异常,回滚MySQL事务
        mysql_conn.rollback()
        print(f"Error: {e}")
    finally:
        cursor.close()
        mysql_conn.close()

解决方案:

  1. 使用MySQL事务确保原子性:
    在MySQL中执行购物车更新操作时,将相关操作包裹在事务中,以确保它们的原子性。如果任何一个操作失败,整个事务将被回滚,防止不一致的数据状态。
  2. 使用Redis的WATCH和MULTI命令实现乐观锁:
    使用Redis的WATCH和MULTI命令,通过乐观锁的方式确保Redis中购物车缓存的原子性更新。如果在执行事务前发现被监视的键(购物车缓存键)被其他客户端修改,则事务会被取消。
# Python代码示例 - 使用Redis的WATCH和MULTI命令实现乐观锁
import redis
def add_to_cart_atomic(user_id, product_id, quantity):
    redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)
    mysql_conn = MySQLdb.connect(host='localhost', user='user', password='password', db='ecommerce')
    cursor = mysql_conn.cursor()
    try:
        # 使用WATCH监视购物车缓存键
        with redis_client.pipeline() as pipe:
            while True:
                try:
                    # 开启Redis事务
                    pipe.watch(f'user:{user_id}:cart')
                    # 获取当前购物车中商品的数量
                    current_quantity = int(pipe.hget(f'user:{user_id}:cart', product_id) or 0)
                    # 开始Redis事务
                    pipe.multi()
                    # 计算新的商品数量
                    new_quantity = current_quantity + quantity
                    # 更新购物车缓存
                    pipe.hset(f'user:{user_id}:cart', product_id, new_quantity)
                    # 执行Redis事务
                    pipe.execute()
                    # 开始MySQL事务
                    mysql_conn.begin()
                    # 更新MySQL中购物车数量
                    cursor.execute(f'INSERT INTO shopping_carts (user_id, product_id, quantity) VALUES ({user_id}, {product_id}, {quantity}) ON DUPLICATE KEY UPDATE quantity=quantity+{quantity}')
                    # 提交MySQL事务
                    mysql_conn.commit()
                    break
                except redis.WatchError:
                    # 被监视的键被其他客户端修改,重新尝试
                    continue
    except Exception as e:
        # 发生异常,回滚MySQL事务
        mysql_conn.rollback()
        print(f"Error: {e}")
    finally:
        cursor.close()
        mysql_conn.close()
相关文章
|
1月前
|
监控 NoSQL 关系型数据库
Redis:事务(Transactions)
Redis事务支持将多个命令打包执行,但与MySQL不同,它不保证原子性、一致性、持久性和隔离性。Redis事务的核心在于“打包”命令,避免其他客户端插队,通过MULTI、EXEC、DISCARD等命令实现。此外,Redis提供WATCH和UNWATCH机制,用于监控键变化,实现类似“乐观锁”的功能,提升并发操作的安全性。
|
1月前
|
SQL 关系型数据库 MySQL
MySQL锁机制:并发控制与事务隔离
本文深入解析了MySQL的锁机制与事务隔离级别,涵盖锁类型、兼容性、死锁处理及性能优化策略,助你掌握高并发场景下的数据库并发控制核心技巧。
|
2月前
|
存储 监控 Oracle
MySQL事务
MySQL事务具有ACID特性,包括原子性、一致性、隔离性和持久性。其默认隔离级别为可重复读,通过MVCC和间隙锁解决幻读问题,确保事务间数据的一致性和并发性。
MySQL事务
|
3月前
|
关系型数据库 应用服务中间件 nginx
Docker一键安装中间件(RocketMq、Nginx、MySql、Minio、Jenkins、Redis)
本系列脚本提供RocketMQ、Nginx、MySQL、MinIO、Jenkins和Redis的Docker一键安装与配置方案,适用于快速部署微服务基础环境。
|
14天前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
158 5
|
13天前
|
关系型数据库 MySQL 数据库
【赵渝强老师】MySQL的事务隔离级别
数据库并发访问时易引发数据不一致问题。如客户端读取到未提交的事务数据,可能导致“脏读”。MySQL通过四种事务隔离级别(读未提交、读已提交、可重复读、可序列化)控制并发行为,默认为“可重复读”,以平衡性能与数据一致性。
153 0
|
1月前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
|
5月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
1月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
129 1
Redis专题-实战篇二-商户查询缓存
|
20天前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。

推荐镜像

更多