基于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
示例:把id為1的人的簽到次數(假設為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)
參考連接配接:
http://www.cnblogs.com/qq78292959/archive/2013/02/05/2892735.html
作者:授客
QQ:1033553122
全國軟體測試QQ交流群:7156436
Git位址:https://gitee.com/ishouke
友情提示:限于時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額随意,您的支援将是我繼續創作的源動力,打賞後如有任何疑問,請聯系我!!!
微信打賞
支付寶打賞 全國軟體測試交流QQ群