15.20数据库(20):基于MVC+MySQL+Redis架构的用户登录系统

@概述

  • 在Web开发中,【MySQL核心数据+Redis高速缓存】是一种常见的数据解决方案;
  • 本例结合MVC架构(数据-视图-控制)结合MySQL+Redis数据解决方案实现用户登录控制;
  • 基本业务逻辑:用户首次登录时从MySQL中读取用户信息,并缓存在Redis中,后续登录信息的读取全部优先读取Redis缓存;
  • github仓库地址:https://github.com/ouyangsuo/UserManagingSystem

@Model层:用户模型类

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

@Model层:用户数据访问类

# User类的数据库访问对象
# 封装了对User数据的增删改查
# Dao=Database Access Object 数据库访问对象

class UserDao:

    # 定义常量:表名、字段...
    TABLENAME = "t_usr"
    COL_USERNAME = "username"
    COL_PASSWORD = "password"

    # 创建User表
    @classmethod
    def createTable(cls):
        # 不存在用户表则创建用户表
        sql='''
        create table if not EXISTS t_usr(
          id INTEGER PRIMARY KEY auto_increment,
          username varchar(20) unique not null,
          password varchar(20) not null
        );
        '''

        # 调用数据库工具的原生sql接口
        MysqlUtil.execute(sql)
        pass

    '''
    增删改查全部调用数据库工具的增删改查方法(API)
    '''

    # 插入一条User数据
    @classmethod
    def insert(cls, user):
        dataDict = {}
        dataDict[cls.COL_USERNAME] = user.username
        dataDict[cls.COL_PASSWORD] = user.password
        MysqlUtil.insert(cls.TABLENAME,dataDict)
        pass

    # 删除一条User数据
    @classmethod
    def delete(cls, user):
        pass

    # 修改一条User数据
    # user=要修改的对象,targetDict=新的属性值字典
    @classmethod
    def update(cls, user, targetDict):
        pass

    # 查询User数据是否存在
    @classmethod
    def query(cls, user):
        dataDict = {
            cls.COL_USERNAME:user.username,
            cls.COL_PASSWORD:user.password
        }
        ret = MysqlUtil.query(cls.TABLENAME,dataDict)
        if ret:
            return User(ret[0][1],ret[0][2])

@View层:程序入口模块

from demos.W8.day1.UserManage.controller.urls import init, login,index

if __name__ == '__main__':
    # 模拟访问主页,调用调度器的主页方法
    index()

@Controller层:调度器模块

from demos.W8.day1.UserManage.model.models import User, UserDao
from demos.W8.day1.UserManage.utils.db_util import RedisUtil

# 登录方法
def login(user):

    '''查看Redis缓存中是否有用户数据'''

    # 如果缓存中没有用户名,就访问MySQL数据库
    if not RedisUtil.exists(user.username):
        print("get user from mysql...")

        # 通过UserDao向MySQL查询用户是否存在,返回用户信息
        theUser = UserDao.query(user)

        # MySQL用户存在,登录成功并缓存到Redis
        if theUser:

            print("mysql:login ok")
            # 如果查到数据,缓存到redis
            RedisUtil.set(theUser.username,theUser.password)

        # MySQL中不存在该用户,登录失败
        else:
            print("mysql:wrong username or password")

    # 缓存中有用户名,且密码匹配,登录成功
    elif RedisUtil.get(user.username) == user.password:
        print("redis:login ok")

    # 密码不匹配,登录失败
    else:
        print(RedisUtil.get(user.username))
        print("redis:wrong username or password")

# 数据初始化方法
def init():
    # 建表和插入数据
    # UserDao.createTable()
    # user1 = User("bill", "123456")
    # user2 = User("jobs", "123456")
    # user3 = User("jackma", "123456")
    # UserDao.insert(user1)
    # UserDao.insert(user2)
    # UserDao.insert(user3)

    # 连接redis数据库
    RedisUtil.connect()

# 访问主页
def index():
    # 初始化数据,建立Redis数据库连接
    init()

    # 接收用户输入
    username, password = input("please enter username and password:").split(",")
    user = User(username, password)

    # 调用登录逻辑
    login(user)
    print('GAME OVER')

@MySQL工具类封装

class MysqlUtil:
    '''
    ·通过表名和条件字典(列名-值)进行数据的增删改查
    ·根据表名和条件字典拼装SQL语句并执行
    ·随用随连,用完就断开
    '''

    # 删除记录
    # tablename=表名
    # dataDict=要插入的数据
    @classmethod
    def insert(cls, tablename, dataDict):
        cls.connect()
        # CRUD...

        colnames =''
        values=''
        for k,v in dataDict.items():
            colnames += (k+",")
            values += ("'"+v+"',")

        # 去掉最后一个逗号
        colnames =colnames[:-1]
        values =values[:-1]

        # insert into t_usr(username,password) values('xxx','xxx');
        sql = 'insert into %s(%s) values(%s);' % (tablename, colnames, values)
        print(sql)
        cls.cursor.execute(sql)
        cls.conn.commit()

        cls.disconnect()

    # 删除记录
    # tablename=要删除的表
    # selectionDict=删除条件
    @classmethod
    def delete(cls, tablename, selectionDict):
        cls.connect()
        # CRUD...
        cls.disconnect()

    # 修改表数据
    # selectionDict = 要修改的数据条件
    # dataDict = 要修改为的数据
    @classmethod
    def update(cls, tablename, selectionDict,dataDict):
        cls.connect()
        # CRUD...
        cls.disconnect()

    # 删除记录
    # tablename=表名
    # selectionDict=查询条件
    @classmethod
    def query(cls, tablename, selectionDict):
        cls.connect()

        # CRUD...
        # 构造where子句
        whereClause = ''
        for k,v in selectionDict.items():
            whereClause += (k+"='"+v+"' and ")
        whereClause = whereClause[:-5]
        # select * from t_usr where username='xxx' and password='xxxx';
        sql = "select * from %s where %s;"%(tablename,whereClause)
        print(sql)
        affected = cls.cursor.execute(sql)
        if affected == 0:
            return None

        ret = cls.cursor.fetchall()
        print(affected,ret)

        cls.disconnect()
        return ret

    # 执行传入的原生SQL语句
    @classmethod
    def execute(cls, sql):
        cls.connect()
        cls.cursor.execute(sql)
        cls.disconnect()
        pass

    # 连接数据库,并生成全局可用的连接对象和查询游标
    @classmethod
    def connect(cls):
        cls.conn = pymysql.connect(
            host='localhost', port=3306, user='root', password="123456", database='homework'
        )
        cls.cursor = cls.conn.cursor()

    # 关闭全局游标,断开全局连接
    @classmethod
    def disconnect(cls):
        cls.cursor.close()
        cls.conn.close()

@Redis工具类封装

class RedisUtil:

    # 判断键是否存在
    @classmethod
    def exists(cls, key):
        return cls.client.exists(key)

    # 获取键对应的值
    @classmethod
    def get(cls, key):
        return cls.client.get(key).decode("utf-8")

    # 存储键值
    @classmethod
    def set(cls, key, value):
        cls.client.setex(key, value, 30)

    # 全局连接方法
    connected = False
    @classmethod
    def connect(cls):

        # 创建全局的Redis客户端
        if not cls.connected:
            cls.client = redis.Redis(
                host='localhost', port=6379, db=15, password='123456'
            )
            cls.connected = True

你可能感兴趣的:(数据库与优化,Python,语言程序设计)