Python 数据库操作

mysql模块

(import mysql.connector)
安装驱动:pip install mysql-connector

实例
import mysql.connector
conn = mysql.connector.connect(user='root', password='123456', database='test') #连接数据库
cursor = conn.cursor()
#相当于建立一个接口,以后就往这里面输入数据库语句进行操作
cursor.execute('select * from user')
#执行sql查询语句,但注意这里查询的结果必须要取走以后才能再次进行操作(包括增删改),即下面那一句得执行
values = cursor.fetchall()
print(values)
#此时就返回查询结果,是一个列表,每行内容单独用元组保存,比如:[('a', 'v', 'c'), ('aaa', '111', 'dawson')]
cursor.execute('create table userd (id varchar(20) primary key, name varchar(20))') #新建表
cursor.close() #结束后关闭数据库连接,返回True说明关闭成功   

pymysql模块

(自带模块)
使用方式:(按执行顺序)

(1)创建连接
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="123456", db="test")   
(2)创建游标

(即操作对象)

cursor = conn.cursor()
(3)设置类型

默认游标是元组类型,可以设置为别的,这里游标设置为字典类型(可选):

cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)   
(4)执行SQL
effect_row = cursor.execute("select * from user") #会返回收影响行数
(5)获取数据
row_1 = cursor.fetchone() #获取剩余结果的第一行数据
row_2 = cursor.fetchmany(3) # 获取剩余结果前n行数据
row_3 = cursor.fetchall() # 获取剩余结果所有数据
(6)控制位置移动

因为读取/操作数据后游标位置会变,比如取了第一行数据,剩下能看的数据就只有第二行以后的了,所以需要控制位置移动:

cursor.scroll(1,mode='relative')
#相对当前位置移动,比如1就是跳过一条,-1就是回到上一条
cursor.scroll(2,mode='absolute')
#相对绝对位置移动,比如0就是回到第一条,但不能通过-1到最后一条,通过查看源码可以得知范围为0-length
(7)提交操作

一个操作结束后需要进行提交,不然无法保存新建或者修改的数据等新的操作:

conn.commit()
(8)关闭游标
cursor.close()
(9)关闭连接
conn.close()
(10)数据回滚(可选)
db.rollback()
完整示例
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='test')  #建立连接
cursor = conn.cursor()  #创建游标
effect_row = cursor.execute("select * from userd") #会返回收影响行数
print(effect_row)   #这里收到3条数据

result = cursor.fetchall()      #获取所有数据
print("result:", result)
result2 = cursor.fetchall()     #游标此时在最后,所以内容为空
print("result2:", result2)
cursor.scroll(-1,mode='relative') #跳回上一条,这里就是最后一条
result3 = cursor.fetchall()
print("result3:", result3)
cursor.scroll(0,mode='absolute') #跳回第一条
result4 = cursor.fetchall()
print("result4:", result4)

conn.commit()       #结束时提交、关闭三连发
cursor.close()
conn.close()


结果:
3
result: (('1', 'a'), ('2', 'b'), ('3', 'c'))
result2: ()
result3: (('3', 'c'),)
result4: (('1', 'a'), ('2', 'b'), ('3', 'c'))
更多参考

https://www.cnblogs.com/wt11/p/6141225.html

Mongodb

(基于分布式的非关系型数据库,即没有固定表结构,可以通过键值对方式存储数据,而不是像mysql那种关系型数据库一样有固定的表结构,只能按规定的来存数据,可以去官网下载安装)
关系型数据库和非关系型数据库区别可参考:https://blog.csdn.net/qq_31536117/article/details/78179646

安装配置

可参考:https://blog.csdn.net/winstonlau/article/details/79439223
配置数据库存储路径:
创建好数据库文件夹后,命令行输入:mongod --dbpath 文件夹路径
进入客户端:
在命令行输入mongo(配好path路径以后),就会进入mongo的shell
配置环境:
打开管理员权限命令行,定位到mongodbbin目录下,输入:

mongod __bind__ip 0.0.0.0 --logpath E:\Mongodb\Server\4.0\log\mongod.log --logappend --dbpath E:\Mongodb\Server\4.0\data\db --port 27017 --serviceName "MongoDB" --serviceDisplayName "MongoDB" --install

上面意思依次是绑定ip、log文件路径、数据库路径、端口、服务器名称
可视化工具:
下载Robomongo
python相关操作模块:

pip install pymongo
操作示例
import pymongo
>>> client = pymongo.MongoClient('localhost') #建立一个连接
# client = pymongo.MongoClient('localhost', username="admin", password="123456")
# 需要密码的连接方式
>>> db = client['newtestdb'] #创建一个数据库newtestdb
>>> db['table'].insert({'name':'aaa'}) #创建一个数据库表table,并插入一个字典
>>> db['table'].find_one() #查找一条数据
{'_id': ObjectId('5b3d76daab406029e01944f6'), 'name': 'aaa'}
>>> db['table'].find_one({'name':'aaa'}) #查找指定数据
{'_id': ObjectId('5b3d76daab406029e01944f6'), 'name': 'aaa'}

更多pymongo操作参考
https://www.cnblogs.com/nixingguo/p/7260604.html

事务使用

需要mongodb版本4.0+,并且配置副本集才能够使用事务机制

事务配置参考:https://www.jianshu.com/p/117b43f88769
pymongo事务操作参考:https://www.cnblogs.com/82nlf-xlqb/p/11771530.html

事务封装

事务环境配置完成以后,还需要在指定session当中执行,示例如下:

import pymongo
client = pymongo.MongoClient('localhost', 27017)
session = client.start_session()
col = client["test"]["aaa"]

# 事务开始
session.start_transaction()    
try:
    col.insert_one({"world":1}, session=session)
    raise
    col.insert_one({"hello":1}, session=session)
except Exception as e:
    session.abort_transaction()
else:
    session.commit_transaction()
finally:
    session.end_session()

可以看出事务的代码当中需要开启事务,并且所有相关的事务语句还要指定session执行,语法过于繁琐。因此我们可以结合with管理和装饰器进行封装如下:

import pymongo

config = {
    "host": "localhost",
    "port": 27017,
}

client = pymongo.MongoClient(**config)

class MongoOperatorDeco(object):
    """
    pymongo事务操作封装类,传入操作的对象和session,自动添加session事务操作
    """
    def __init__(self, o, session):
        self.o = o
        self.session = session
        
    def __getattr__(self, name):
        attr = self.o.__getattribute__(name)
        return self.mongo_session_deco(attr)

    def mongo_session_deco(self, func):
        """
        装饰器封装,添加事务操作参数
        """
        def mongo_session_deco_fun(*arg, transaction=True, **args):
            if transaction:
                args["session"] = self.session
            return func(*arg, **args)
        return mongo_session_deco_fun


class MongoSessionContext(object):
    """
    pymongo事务context管理器,通过with语句简单管理session事务操作
    """
    def __init__(self):
        super().__init__()
    
    def __enter__(self):
        """
        进入context,返回当前事务session
        """
        self.session = client.start_session()
        self.session.start_transaction()
        return self.session

    def __exit__(self, exc_type, exc_value, traceback):
        """
        context内顺序执行完毕后将提交事务,若抛出异常则进行回滚,最终关闭session
        """
        if not exc_type:
            self.session.commit_transaction()
        else:
            self.session.abort_transaction()
        self.session.end_session()


if __name__ == "__main__":
    with MongoSessionContext() as session:
        # 在封装的context中执行事务语句
        col = MongoOperatorDeco(client["test"]["aaa"], session)
        # 通过装饰器包装当前操作对象,操作时自动添加session
        col.insert_one({"world":1})
        col.insert_one({"world":2}, transaction=False)
        # 这句不参与事务,因此不论后面语句是否出错,都会执行成功
        col.insert_one({"world":3})
        # raise
        # 报错,参与事务的语句都不会执行成功

可以看出经过封装以后,事务代码就和之前编写的操作语句类似了

mongodbengine

该模块封装了对mongodb的ORM操作,举例:

from mongoengine import *

class Company(Document):
    '''公司表,有公司名和规模属性'''
    choice =  (('s', 'small'),
               ('m', 'middle'),
               ('l', 'large'))
    name = StringField(max_length=50, required=True)
    size = StringField(choices=choice, required=True)

class Work(EmbeddedDocument):
    '''工作嵌入表,和普通的表不太一样,其不会作为一个表单独存在,而是嵌入在别的表内部,有工作名称和薪资'''
    name = StringField(max_length=50, required=True)
    salary = FloatField(required=True)

class People(Document):
    '''个人信息表'''
    choice =  (('F', 'female'),
               ('M', 'male'),)
    name = StringField(max_length=100, required=True, unique=True)
    age = IntField(required=True)
    gender = StringField(choices=choice, required=True)
    work = ListField(EmbeddedDocumentField(Work), required=True)
    # 一个人可以身兼多职,而多个职位存放在一个list里,list当中每个工作是一个嵌入字段,即list里存放的是一堆对象
    company = ReferenceField(Company, required=True)
    # 引用字段,存放的是在Company表里对应的唯一id
    note = DictField(required=True)
    # 跟EmbeddedDocumentField差不多,但是DictField没有定义结构,因此字段没有限制

if __name__ == '__main__':
    connect(db='test', host='localhost', port=27017)
    # connect(db='test', host='localhost', port=27017, username="admin", password="123456", authentication_source='admin')
    # 需要密码的验证方式
    company_a = Company(name='middle company', size='m')
    company_a.save()
    # 因为是单独存表,如果引用字段要引用时,必须是表里存在的数据,所以这里需要先保存
    work_a = Work(name='w-a', salary=10000)
    work_b = Work(name='w-b', salary=5000)
    work_c = Work(name='w-c', salary=3000)
    # 因为是嵌入表,直接在嵌入的表里再存即可
    note_a = {"describe": "...", "other": "nothing"}
    people_a = People(name='aaa', age=30, gender='M', company=company_a ,work=[work_a, work_b, work_c], note=note_a)
    people_a.save()

    # 查询数据,在数据库可以看到在People表和Company表里添加了数据
    # 但并没有新建一个Work表,Work的数据在People的一个字段当中
    result = People.objects.filter(name='aaa').first()
    for work in result.work:
        print(work.name, work.salary)
    print(result.company.name)
    print(result.to_mongo())
    # 内容转字典格式,后面还能调用to_dict()方法转成字典类型

更多使用参考:
https://www.cnblogs.com/wefeng/p/11503102.html
https://www.jb51.net/article/64861.htm

注:

orm效率问题参考:http://xiaorui.cc/archives/2048

mongdbengine序列化/反序列化-marshmallow_mongoengine

该模块需要基于版本小于3的marshmallow,安装命令:

pip install marshmallow==2.13.6 marshmallow_mongoengine

代码示例:

from mongoengine import *
from marshmallow_mongoengine import ModelSchema, fields


# ---------------------------------
# 定义模型
class Company(Document):
    name = StringField(max_length=50, required=True)
    size = StringField(required=True)

    def __str__(self):
        return str({"name": self.name, "size": self.size})


class Work(EmbeddedDocument):
    name = StringField(max_length=50, required=True)
    salary = FloatField(required=True)


class People(Document):
    name = StringField(max_length=100, required=True, unique=True)
    age = IntField(required=True)
    gender = StringField(required=True)
    work = ListField(EmbeddedDocumentField(Work), required=True)
    company = ReferenceField(Company, required=True)


# ---------------------------------
# 定义序列化类
class CompanySchema(ModelSchema):
    name = fields.String()
    # 定义序列化的字段,不定义默认序列化全部字段
    class Meta:
        model = Company
    # 绑定model


class PeopleSchema(ModelSchema):
    company = fields.Nested(CompanySchema)
    # 对于引用字段使用Nested,否则序列化后只是一个objectId而不是完整的数据
    class Meta:
        model = People


if __name__ == "__main__":
    connect(db='test', host='localhost', port=27017)
    di_work = {"name": "engineer", "salary": 10000}
    di_company = {"name": "xxx", "size": "big"}

    unseries_company = CompanySchema().load(di_company).data
    # 反序列化成对象
    unseries_company.save()
    print(unseries_company)
    series_company = CompanySchema().dump(unseries_company).data
    # 序列化成字典
    di_people = {"name": "aaa", "age": 10, "gender": "male", "work": [di_work], "company": series_company}
    # di_people = {"name": "aaa", "age": 10, "gender": "male", "work": di_work, "company": unseries_company.id}
    # 如果没有使用Nested字段,则直接传入指定对象的objectId
    unseries_people = PeopleSchema().load(di_people).data
    # people反序列化
    unseries_people.save()
    series_people = PeopleSchema().dump(unseries_people).data
    # 序列化成字典
    print(series_people)

参考:https://blog.csdn.net/qq_41637554/article/details/82464186
https://blog.csdn.net/weixin_42042680/article/details/90206632

Redis

(也是一种非关系型数据库,通过键值对存数据,由于其特殊的功能,常用于分布式存储当中)

基本配置

下载地址:
https://github.com/MicrosoftArchive/redis/releases
可视化工具下载:
https://github.com/uglide/RedisDesktopManager/releases?after=0.9.0-alpha5
python相关操作模块:

pip install redis
操作示例
import redis
>>> r = redis.Redis('localhost', 6379) #连接数据库

String操作:

>>> r.set('name', 'aaa') #set插入单个数据
True
>>> r.get('name') #get获取单个数据
b'aaa'
>>> user = {'name':'dawson','pwd':'111'}
>>> r.mset(user) #mset插入多个键值对
True
>>> r.mget(user) #mget获取多个键值对,里面参数可以是列表、字典等
[b'111', b'dawson']
>>> r.mget('name','pwd')
[b'dawson', b'111']
>>> r.append('name', 'sad') #append往后面添加字符
9
>>> r.get('name')
b'dawsonsad'
>>> r.delete('name') #delete删除
1
>>> r.mget(user)
[b'111', None]

List操作:

>>> r.lpush('keyn', 'a', 'b', 'c') #lpush从左插入数据
3
>>> r.rpush('keyn', 'd', 'e') #rpush从右插入数据
5
>>> r.lrange('keyn', 0, -1) #lrange获取某个数据,从第0个到最后一个
[b'c', b'b', b'a', b'd', b'e']
>>> r.lpop('keyn') #lpop弹出最左边数据,rpop弹出最右
b'c'

Set操作:

>>> sets = ['a', 'b', 'c']
>>> r.sadd('set1', *sets)
#sadd插入到集合(不会重复),如果不加*,会将整个['a', 'b', 'c']传入
#即只有一个数据,加*就是分别传'a', 'b', 'c'三个数据,srem删除
3
>>> r.smembers('set1') #smembers获取集合数据
{b'a', b'b', b'c'}
>>> r.sadd('set2', *['a', 1, 2])
3
>>> r.sadd('set3', *['a', 3, 'b'])
3
>>> r.sinter('set1', 'set2', 'set3') #sinter返回几个集合之间的交集
{b'a'}
>>> r.sunion('set1', 'set2', 'set3') #sunion返回几个集合之间的并集
{b'3', b'a', b'b', b'c', b'2', b'1'}
>>> r.sismember('set1', 'a') #sismember判断是否是集合元素
True
>>> r.sismember('set1', 'h')
False

Hash操作:

>>> r.hset('news', 'title', 'one') #hset添加数据,这里给news的title赋值one
1
>>> r.hset('news', 'content', 'two') #这里给news的content赋值two
1
>>> r.hget('news', 'title') #hget获取数据,hdel删除
b'one'
>>> r.hmget('news', 'title', 'content') #hmget获取多个数据,hmset设置多个
[b'one', b'two']
>>> r.hkeys('news') #hkeys获取所有键
[b'title', b'content']
>>> r.hvals('news') #hvals获取所有值
[b'one', b'two']

更多使用参考:https://www.cnblogs.com/shenh/p/9176907.html

其他
windows下添加redis服务

输入以下命令:

redis-server --service-install redis.windows.conf --loglevel verbose  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343