zoukankan      html  css  js  c++  java
  • Python 基于python+mysql浅谈redis缓存设计与数据库关联数据处理

    基于python+mysql浅谈redis缓存设计与数据库关联数据处理

     

    by:授客  QQ:1033553122

     

    测试环境

    redis-3.0.7

     

    CentOS 6.5-x86_64

     

    python 3.3.2

     

    基于Python操作Redis

    1、创建示例数据库表
    
    CREATE TABLE tb_signin_rank(
    
    id INT,
    
    user_name VARCHAR(10) COMMENT '用户名',
    
    signin_num INT COMMENT '签到次数',
    
    signin_time DATETIME COMMENT '签到时间',
    
    gold_coin INT COMMENT '金币' 
    
    );
    
     
    
    初始化数据
    
    INSERT INTO tb_signin_rank 
    
    VALUES(1, 'shouke', 0, NULL, 0),
    
    (2, 'chuangke', 0, NULL, 0),
    
    (3, 'ishouke', 0, NULL, 0),
    
    (4, 'keshou', 0, NULL, 0),
    
    (5, 'shouke', 0, NULL, 0);
    
     
    
     
    
    2、redis缓存键值设计
    
    key               value
    
    表名:主键值:列名   列值
    
     
    
    或者如下,通过为不同列之间建立较为紧密的关联
    
    key                        value
    
    表名:主键值:列值1:列名2   列值2
    
     
    
     
    
     
    
    示例:把id1的人的签到次数(假设为5)存储到redis中则可如下操作:
    
    set('tb_signin_rank:1:signin_num', 5)
    
     
    
    这样做的好处是,类似数据库一样,通过主键便可获取其它值。
    
     
    
    示例:把id和用户名关联
    
    set('tb_signin_rank:shouke:id', 1)
    
     
    
    这样,通过用户名就可以查询出关联的id了:uid = r.get("tb_signin_rank:%s:id" % username)
    
     
    
     
    
    3、redis关联数据库的数据处理
    
     
    
    不要求强一致实时性的读请求,都由redis处理
    
    要求强一致实时性的读请求,由数据库处理
    
    通常包含以下两种处理模式:
    
    模式1
    
    如图,先判断是否存在缓存(通常是根据key),如果存在则从缓存读取,否则从数据库读取并更新缓存。
    

    
    

    适用场景:对数据实时性要求不高,更新比较不频繁,比如签到排行榜
     
    
    模式2
    
    如下图,先写入redis然后,利用守护进程等方式,定时写入到数据库
    
    
    模式3
    
    如下图,先写入数据库,然后再更新到缓存
    
     

    
    
    适用场景:数据量较大,更新较为频繁
    
    
    
     
    
    说明:
    
    模式2和模式3的区别在于,前者把redis当作数据库用,通过写入redis后马上返回程序,然后定时把数据写入数据库,这也大大提高了访问速度。这种方式不足的是,这种对redis的可靠性依赖性太强
    
     
    
    4、案例
    
    ./dbconfig.conf配置
    
    [TESTDB]
    
    host = 192.168.1.103
    
    port = 3306
    
    user = testacc
    
    passwd = test1234
    
    db = testdb
    
    charset = utf8
    
     
    
    #!/usr/bin/env python
    
    # -*- coding:utf-8 -*-
    
     
    
    __author__ = 'shouke'
    
     
    
    import configparser
    
    import sys
    
    import mysql.connector
    
    import redis
    
     
    
    if __name__ == '__main__':
    
        pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)
    
        r = redis.Redis(connection_pool=pool)
    
        # r.expire('tb_signin_rank:id:signin_num', 20)
    
     
    
        config = configparser.ConfigParser()
    
     
    
        # 从配置文件中读取数据库服务器IP、域名,端口
    
        config.read('./dbconfig.conf')
    
        host = config['TESTDB']['host']
    
        port = config['TESTDB']['port']
    
        user = config['TESTDB']['user']
    
        passwd = config['TESTDB']['passwd']
    
        db_name = config['TESTDB']['db']
    
        charset = config['TESTDB']['charset']
    
     
    
        try:
    
            dbconn = mysql.connector.connect(host=host, port=port, user=user, password=passwd, database=db_name, charset=charset)
    
        except Exception as e:
    
            print('初始化数据连接失败:%s' % e)
    
            sys.exit()
    
     
    
        # 执行签到
    
        try:
    
            db_cursor = dbconn.cursor()
    
            for id in range(1, 6):
    
                db_cursor.execute('UPDATE tb_signin_rank SET signin_num = signin_num + 1, signin_time = NOW(), gold_coin = gold_coin + (1 + RAND()*9) WHERE id = %s',(id,))
    
                db_cursor.execute('commit')
    
            # 更新缓存
    
            r.zincrby("tb_signin_rank:id:signin_num", id, 1)
    
        except Exception as e:
    
            print('执行数据库更新操作失败:%s' % e)
    
            db_cursor.execute('rollback')
    
            db_cursor.close()
    
            exit()
    
     
    
        # 展示用户签到次数
    
        for id in range(1, 6):
    
            result = r.zscore('tb_signin_rank:id:signin_num', id)
    
            if not result: # 不存在缓存,从数据库读取
    
                print('----从数据库读取用户签到次数----')
    
                try:
    
                    db_cursor = dbconn.cursor()
    
                    db_cursor.execute('SELECT signin_num FROM tb_signin_rank WHERE id = %s', (id,))
    
                    result = db_cursor.fetchone()[0]
    
                    # 更新到缓存
    
                    r.zadd('tb_signin_rank:id:signin_num', id, result)
    
                except Exception as e:
    
                    print('执行数据库查询操作失败:%s' % e)
    
                    db_cursor.close()
    
            else: # 存在缓存,从缓存读取
    
                print('----从缓存读取用户签到次数----')
    
                result = int(result)
    
     
    
            print('sigin_num of user[id=%s]: %s' % (id, result))
    
     
    
     
    
        # 展示签到排行榜
    
        result = r.zrevrange('tb_signin_rank:id:signin_num', 0, 10)
    
        print('签到排行榜:', result)

    Python <wbr>基于python+mysql浅谈redis缓存设计与数据库关联数据处理 
    
    
     
    
    参考连接:
    
    http://www.cnblogs.com/qq78292959/archive/2013/02/05/2892735.html
    

     

  • 相关阅读:
    [LeetCode] Implement Queue using Stacks 用栈来实现队列
    [LeetCode] Power of Two 判断2的次方数
    [LeetCode] 230. Kth Smallest Element in a BST 二叉搜索树中的第K小的元素
    cvReleaseImage 释放内存出错
    FlyCapture2 fc2Image OpenCV IplImage Conversion 两种图像格式之间的转换
    FlyCapture2 Qt5 MinGW Configuration
    [LeetCode] 14. Longest Common Prefix 最长共同前缀
    [LeetCode] 19. Remove Nth Node From End of List 移除链表倒数第N个节点
    [LeetCode] 229. Majority Element II 求大多数之二
    [LeetCode] 23. Merge k Sorted Lists 合并k个有序链表
  • 原文地址:https://www.cnblogs.com/shouke/p/10157756.html
Copyright © 2011-2022 走看看