python学习笔记之数据库表的读写操作

一、executemany()函数

        建立数据库mariadb_learn,并且在userinfor表里面写入20个用户的账号和密码信息。代码如下

import pymysql
#随机生成20条用户数据; 列表里面嵌套元组;
list_infor = [('user'+str(num),'00000')for num in range(1,21)]
dbconfig = {
        'host'    :'localhost',
        'user'    : 'root',
        'passwd'  : '123456',
        'db'      :'mariadb_learn'
    }


# 1. 连接数据库连接
conn = pymysql.connect(**dbconfig)

# 2. 创建游标, 给数据库发送sql指令
cur = conn.cursor()
try:

    insert_sqli = 'insert into userinfor values(%s,%s)'
    cur.executemany(insert_sqli,list_infor)
except Exception as Error:
    print('sql exrcutemany failed:',Error)
else:
    print('sql executeamny success!')

# 4. 提交sql语句, 作用于数据库;
conn.commit()
# 5. 先关闭游标
cur.close()
# 6. 关闭数据库连接
conn.close()

输出

sql executeamny success!

          

再次使用executemany()函数将前5到15条用户信息的密码更改为123456。  

import pymysql
dbconfig = {
        'host'    :'localhost',
        'user'    : 'root',
        'passwd'  : '123456',
        'db'      :'mariadb_learn'
    }
#随机生成20条用户数据; 列表里面嵌套元组;
list_infor = [('user'+str(num),'00000')for num in range(1,21)]
update_infor = [userinfor[0] for userinfor in list_infor[4:15]]
#1.数据库连接
conn = pymysql.connect(**dbconfig)

#2.创建游标,用于给数据库发送sql指令
cur = conn.cursor()

#3.执行sql语句  : 一次性插入多条信息
try:

    update_sqli = 'update userinfor set passwd = "13324" where username = %s'

    cur.executemany(update_sqli, update_infor)
except Exception as Error:
    print('sql update failed',Error)
else:
    print('sql update success')

#4 . 提交sql语句,作用于数据库
conn.commit()
#5.关闭游标
cur.close()
#6.关闭数据库
conn.close()

输出:

sql update success
    

二、fetchone()、fetchall()、fetchmany()

       当我们使用fetchone()、fetchaall()、fetchmany()三个函数去查看表的内容时、我们表的游标跟随查看的位置进行移动,这一点有点类似于我们文件读写时候的一个指针,这个指针来确定当前读写文件内容的位置。

       fetchall()函数用于读取表格的一行,以元组的形式返回当前行的信息,游标进入下一行。

       fetchmany()函数用于读取指定的表的行数,以嵌套元组的形式返回,指定行的信息。

       fetchall()函数用于读写当前游标所在位置到白结尾的所有行,以嵌套元组的形式返回所有的信息。

   scroll(value, mode='relative')    #mode的默认值是 'relative'  代表游标相对于当前位置移动value行
                                  #mode也可以取值为'absolute' 代表游标移动到表的第value行

       scroll()函数用于读取表内容时移动游标的位置。


import pymysql
dbconfig = {
        'host'    :'localhost',
        'user'    : 'root',
        'passwd'  : '123456',
        'db'      :'mariadb_learn'
    }
# 1. 连接数据库连接
conn = pymysql.connect(**dbconfig)
# 2. 创建游标, 给数据库发送sql指令
cur = conn.cursor()

# 3. 执行sql语句: 查看数据
cur.execute('select * from userinfor;')
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchmany(5))
cur.scroll(0,'absolute')
print(cur.fetchall())
cur.close()
conn.close()

输出:

('user1', '00000')
('user2', '00000')
(('user3', '00000'), ('user4', '00000'), ('user5', '13324'), ('user6', '13324'), ('user7', '13324'))
(('user1', '00000'), ('user2', '00000'), ('user3', '00000'), ('user4', '00000'), ('user5', '13324'), ('user6', '13324'), ('user7', '13324'), ('user8', '13324'), ('user9', '13324'), ('user10', '13324'), ('user11', '13324'), ('user12', '13324'), ('user13', '13324'), ('user14', '13324'), ('user15', '13324'), ('user16', '00000'), ('user17', '00000'), ('user18', '00000'), ('user19', '00000'), ('user20', '00000'))

三、练习

       读取userinfor表中的内容将其写到指定的文件中
import pymysql
dbconfig = {
        'host'    :'localhost',
        'user'    : 'root',
        'passwd'  : '123456',
        'db'      :'mariadb_learn'
    }
# 1. 连接数据库连接
conn = pymysql.connect(**dbconfig)
# 2. 创建游标, 给数据库发送sql指令
cur = conn.cursor()
# 3. 执行sql语句: 查看数据
cur.execute('select * from userinfor;')
try:
    with open('/tmp/userinfor','w') as file_it:
        for row_infor in cur.fetchall():
            file_it.write(':'.join(row_infor)+'\n')
except Exception as Error:
    print(Error)
else:
    print("success")
finally:
    cur.close()
    conn.close()
        

四、description属性

       description用于获取表头信息,将表头信息以嵌套元组的形式返回,类似于数据库中的命名desc

import pymysql
dbconfig = {
        'host'    :'localhost',
        'user'    : 'root',
        'passwd'  : '123456',
        'db'      :'mariadb_learn'
    }
# 1. 连接数据库连接
conn = pymysql.connect(**dbconfig)
# 2. 创建游标, 给数据库发送sql指令
cur = conn.cursor()
# 3. 执行sql语句: 查看数据
cur.execute('select * from userinfor;')
print(cur.description)
cur.close()
conn.close()

输出:

(('username', 253, None, 10, 10, 0, True), ('passwd', 253, None, 10, 10, 0, True))

五、对数据库使用with上下文管理器  

conn = pymysql.connect(
        'host'    ='localhost',
        'user'    = 'root',
        'passwd'  = '123456',
        'db'      ='mariadb_learn')
with conn: cur = conn.cursor()       使用with上下文管理器,可以有助于我们简化代码,将关闭游标和关闭数据库连接的工作交给解释器自己去完成。

六、存储图片到数据库中。  

       我们在/tmp/images/下面放了几幅图片,现在需要将该目录下的所有文件后缀为.jpg结尾的图片存入数据库mariadb_learn中的images表中。
import pymysql
import os
dbconfig = {
    'host': 'localhost',
    'user': 'root',
    'passwd': '123456',
    'db': 'mariadb_learn'}

#第归扫描得到指定文件目录下的所有文件,#所有的.jpg图片的文件名存入列表
def SearchAbsPath(dirname):
    dirname = os.path.abspath(dirname)
    filenames = list()
    for root, dirs, files in os.walk(dirname, topdown=False):  # 扫描一层目录
        for name in files:
            filenames.append(root + os.path.sep + name)  # 每一个文件的绝对路径放入列表
    images = [image_file for image_file in filenames if image_file.endswith('.jpg')]
    return images
# 将所有的图片存入到数据库中
def insert_images(**kwargs):
    # 1. 连接数据库连接
    conn = pymysql.connect(**kwargs)
    # 2. 创建游标,给数据库发送sql指令
    cur = conn.cursor()
    def create_connt():
        try:
            cur.execute('create table images('
                        'id int primary key auto_increment , '
                        'imgName varchar(50),'
                        'imgData mediumblob);')

            # id int primary key auto_increment 这一列的表头信息为id 整形数,即图片的id,
            #  primary key :作为该表的主键, auto_increment : id 可由系统随机生成
            # imgName   图片的名字
            # imgData mediumblob 存储的图片,imgData 为表头,mediumblob以二进制中等大小文件形式存储。
        except Exception as Eorr:
            raise Eorr
        else:
            print('table create sucess!')
    create_connt()
    try:
        insert_sqli = 'insert into images (imgName, imgData) values(%s, %s);'
        for images in SearchAbsPath('/tmp/images/'):
            file_it = open(images, 'rb')
            img_data = file_it.read()
            file_it.close()
            cur.execute(insert_sqli,(images,img_data))
    except Exception as Eorr:
        raise Eorr
    else:
        print("插入图片信息成功!")
    finally:
        conn.commit()
        cur.close()
        conn.close()
insert_images(**dbconfig)

七、数据库中图片的读取。

import pymysql
import os
def decode(s):
    return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]])
dbconfig = {'host'  : 'localhost',
            'user'  : 'root',
            'passwd': '123456',
            'db'    : 'mariadb_learn'}

def DownLoad_Image_from_db(download_dir='/tmp/download/',**kwargs):
    """
    :param download_dir: 从数据库中读取的图片的保存到本地的目录 
    :param kwargs:     数据连接的参数 
    :return: 
    """
    conn = pymysql.connect(**kwargs)
    cur = conn.cursor()
    cur.execute('select * from images')
    while True:
        # 使用fetchone 可以保证内存不会因为一次性读取的图片内存过大,而导致内存崩溃
        row = cur.fetchone()
        #row是三个元素的元组分别是id,imgName、imgData
        if row != None:        
            with open(download_dir+os.path.split(row[1])[1],'wb') as fileit_img:
                fileit_img.write(row[2])
                pass
        else:
            break
    cur.close()
    conn.close()
DownLoad_Image_from_db(**dbconfig)

八、用户和访问权限的操作。

        如果我们拥有所有权限,那么我们可以使用远程登录某台主机上的数据库,比如:  

   mysql -h 192.168.3.25 -uroot -p123456 

       以root用户的身份使用密码123456 区远程登录192.168.3.25这台主机的数据库,如果我们登录成功,就会拥有root的全部权限。但是为了数据安全,我们不会让别人去使用root用户的身份去远程连接登陆我们的数据库,经常是创建一些普通用户,然后对该用户的权限进行限制后,交于别人远程登录数据库。

      进入数据库中,执行下面语句可以进行用户建立:
#创建一个密码为123456的userone用户,只能在本地对数据库进行访问。
create user userone@localhost identfiend by '123456'

#创建一个密码为123456的userone用户,只能在ip为192.163.3.15的主机上访问我的数据库
create user [email protected] identfied by '123456' 

#创建一个密码为123456的userone用户,可以在所有的ip上访问我的数据库。
create user userone@'%' identified by '123456'

#创建无密码的userone用户,可以在所有的ip上访问我的数据库。
create user userone@'%'
       用户授权
grant <权限> on <数据库>.<表> to <用户>@<ip> 

#让userone用户在本地连接数据库时,
#对mariadb_learn数据库中的userinfor
#表拥有insert,update、delete、select、create权限
grant (insert,update,delete,select,create) on mariadb_learn.userinfor to userone@localhost; 

    当我们设定了用户的权限后,需要重读授权表。

 flush privileges;   #重读用户授权表
 how grants for userone@localhost;   #查看userone用户的授权表。
 revoke delete,update on mariadb_learn.* from userinfor@localhost;   #删除用户的指定权限。
 drop user userone@localhost   #删除userone用户。   

九、对数据库进行备份。

        数据库备份
·    #对mariadb_learn数据库进行备份.
     mysqldump -uroot -p mariadb_learn > mariadb_learn.dump

     #对mariadb_learn数据库中进行不要数据的备份
     mysqldump -uroot -p123456 --no-data mariadb_learn > `date +%Y_%m_%d`_mariadb_learn.dump

     对所有的数据库进行备份
     mysqldump -uroot -p123456 --all-databases > mariadb_learn.dump
        数据库依靠备份恢复  
    #1、新建数据库
    mysql -uroot -p123456 create mariadb_learn2
    #2、恢复
    mysql -uroot -p 123456 mariadb_learn2 < mariadb_learn.dump

十、多台mysql主机的远程备份。

        
import os

import time

from mysqlInfo import mysql_list

BACKUP_DIR = '/mnt/BACKUP/'

if not os.path.exists(BACKUP_DIR):
    os.mkdir(BACKUP_DIR)
    print("%s create success!" % (BACKUP_DIR))
else:
    try:
        for host in mysql_list:
            # date = os.popen('date +%Y_%m_%d')
            shell_sen = "mysqldump -h %s -u%s -p%s %s >%s"
            host_ip = host['host']
            user = host['user']
            passwd = host['passwd']
            db = host['db']
            backup_filename = BACKUP_DIR + '%s_%s.dump' %(host_ip, db)
            print(backup_filename)
            print(shell_sen % (host_ip, user, passwd, db, backup_filename))
            os.system(shell_sen % (host_ip, user, passwd, db, backup_filename))
            print("backup %s host" %(host_ip))
    except Exception as e:
        print(e)
    else:
        print('sucess')

        os.system(str)  是的字符命令在shell环境中进行运行。

十一、银行转账系统的简单实现。

       银行转账时,本质就是对数据库中的数据进行加减法,但是当我们在转账的中途突然断电了怎么办,这里就需要用到数据库的执行事务。

        事务机制可以保证数据的一致性。

        失误应该具有4个属性:原子性、一致性、隔离性、持久性。这四个数次那个通常称为ACID特性。

        *原子性(atomicity)。一个事物是一个可分割的工作单位,事物中包括的诸操作要么都做,要么都不做。

        *一致性(consistency)。事物必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

        *隔离性(isolation)。一个事物的执行不能被其他事物干扰。即一个事物内部的操作及使用的数据对并发的其他事物是隔

            离的,并发执行的各个事物之间不能相互干扰

        *持久性(durability)。持续性也称为持久性,只一个事务一旦提交,他对数据库中数据的改变就应该是永久性的。接下来

           的其他操作或故障不应该对其有任何影响。

Python DB API 2.0 的事务提供了两个方法 commit 或 rollback。

        对于支持事务的数据库, 在Python数据库编程中,当游标建立之时,就自动开始了一个隐形的数据库事务。commit()方法游标的所有更新操作,rollback()方法回滚当前游标的所有操作。每一个方法都开始了一个新的事务。

          

import pymysql
import sys


class TransferMoney(object):
    def __init__(self,conn):
        self.conn = conn

    def transfer(self,source_acctid,target_asstid,money):
        """
        转账函数
        :param source_acctid:
        :param target_asstid:
        :param money:
        :return:
        """
        try :
            self.check_acct_available(source_acctid)
            self.check_acct_available(target_asstid)
            self.has_enough_money(source_acctid,money)

            self.reduce_money(source_acctid,money)
            self.add_money(target_asstid,money)
            self.conn.commit()

        except Exception as Error:
            self.conn.rollback()  #数据库的方法,撤销前面对数据库的操作
            raise (Error)

    def check_acct_available(self,acctid):
        """
        检查账户是否存在
        :param acctid: 需要被检查的账户
        :return:
        """
        cur = self.conn.cursor()  #数据库游标建立
        try:
            select_sql = 'select * from account where accid = %s;'%(acctid)
            cur.execute(select_sql)
            print("execute aql :%s"%(select_sql))
            res = cur.fetchall()
            if len(res) != 1:
                raise Exception('账号%s不存在'%(acctid))
        except Exception as Error:
            raise (Error)
        finally:
            cur.close()

    def has_enough_money(self, acctid, money):
        """
        检查账户是否有足够的金钱
        :param acctid: 当前账户
        :param money:  需要判断的的金额
        :return:
        """
        cur = self.conn.cursor()
        try:
            select_sql = 'select money from account where accid = %s'%(acctid)
            cur.execute(select_sql)
            print('has_enough_money aql:%s'%(select_sql))
            res = cur.fetchall()
            if res:
                now_money = res[0][0]
                if now_money < int(money):
                    raise Exception('账户%s没有足够的钱,目前金额为%s',acctid,money)
        except Exception as Error:
           raise (Error)
        finally:
            cur.close()

    def reduce_money(self, acctid, money):
        """
        对账户的减去指定的金额
        :param acctid: 账户
        :param money: 减去的金额
        :return:
        """
        cur = self.conn.cursor()
        try:
            update_sqli = 'update account set money = money-%s where accid = %s'%(money,acctid)
            cur.execute(update_sqli)
            print('add_money sql:%s'%(update_sqli))
        except Exception as Error:
            raise (Error)
        finally:
            cur.close()

    def add_money(self, asstid, money):
        """
        指定账户增加相应的钱数
        :param asstid:  增加金额的账户
        :param money:   增加的金额
        :return:
        """
        cur = self.conn.cursor()
        try:
            update_sqli = 'update account set money = money+%s where accid = %s'%(money,asstid)
            cur.execute(update_sqli)
            print('add_money sql:%s'%(update_sqli))
        except Exception as Error:
            raise (Error)
        finally:
            cur.close()

def main():

    db_dict ={'host'    :'localhost',
              'user'    : 'root',
              'passwd'  : '123456',
              'db'      :'mariadb_learn'}
    conn = pymysql.connect(**db_dict)
    trans_money = TransferMoney(conn)
    source_acctid = sys.argv[1]
    target_acctid = sys.argv[2]
    money = sys.argv[3]
    try :
        trans_money.transfer(source_acctid,target_acctid,money)
    except Exception as Eorr:
        print (Eorr)

    finally:
        conn.close()

if __name__ == '__main__':
    main()

        数据库中的初始账号和钱数如下:

         

        在shell里面运行该文件上面源代码的文件,并加上参数,即621700账户向621701账户转账500元

        

       两个账户在数据库中的进而已经减少

        

猜你喜欢

转载自blog.csdn.net/m0_37717595/article/details/80571289