• Python进阶----pymysql的安装与使用,mysql数据库的备份和恢复,mysql的事务和锁


    Python进阶----pymysql的安装与使用,mysql数据库的备份和恢复,mysql的事务和锁

    一丶安装

    pip install PyMySQL

    二丶pymysql连接数据库

    ### 语法:
        import pymysql							# 导入py模块
    
        conn= pymysql.connect("数据库ip","用户","密码","数据库" ) # 打开数据库连接
        cursor.execute("SELECT VERSION()")                    # 使用 execute() 方法执行 SQL 查询
        data = cursor.fetchone()                              # 使用 fetchone() 方法获取单条数据
        print ("Database version : %s " % data)
        conn.close()                                            # 关闭数据库连接
    
    ### 返回列表包着字典形式数据   
    cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
    
    ### 返回列表包着元组形式数据   
    cur = conn.cursor()
    

    三丶pymysql创建表操作

    import pymysql
     
    # 打开数据库连接
    db = pymysql.connect("localhost","testuser","test123","TESTDB" )
     
    # 使用 cursor() 方法创建一个游标对象 cursor
    cursor = db.cursor()
     
    # 使用 execute() 方法执行 SQL,如果表存在则删除
    cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
     
    # 使用预处理语句创建表
    sql = """CREATE TABLE EMPLOYEE (
             FIRST_NAME  CHAR(20) NOT NULL,
             LAST_NAME  CHAR(20),
             AGE INT,  
             SEX CHAR(1),
             INCOME FLOAT )"""
     
    cursor.execute(sql)
     
    # 关闭数据库连接
    db.close()
    

    四丶数据操作

    增: 推荐使用execute拼接sql

    ### 方式一:
        import pymysql
    
        # 打开数据库连接
        db = pymysql.connect("localhost","testuser","test123","TESTDB" )
    
        # 使用cursor()方法获取操作游标 
        cursor = db.cursor()
    
        # SQL 插入语句
        sql = """INSERT INTO EMPLOYEE(FIRST_NAME,
                 LAST_NAME, AGE, SEX, INCOME)
                 VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""
        try:
           cursor.execute(sql) # 执行sql语句
           db.commit()         # 提交到数据库执行
        except:
           db.rollback()       # 如果发生错误则回滚
    
        # 关闭数据库连接
        db.close()
    
    
    
    ### 方式二  : %s 代替字段,使用execute拼接sql语句
    	
        import pymysql
    
        # 打开数据库连接
        db = pymysql.connect("localhost","testuser","test123","TESTDB" )
    
        # 使用cursor()方法获取操作游标 
        cursor = db.cursor()
    
        # SQL 插入语句
        sql = "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME) VALUES (%s, %s,  %s,  %s,  %s )" %
               
        try:
    
           cursor.execute(sql,(*('Mac', 'Mohan', 20, 'M', 2000),))  # 执行sql语句
           db.commit()          # 执行sql语句
        except:
           db.rollback()        # 发生错误时回滚
    
        # 关闭数据库连接
        db.close()
    

    import pymysql
     
    # 打开数据库连接
    db = pymysql.connect("localhost","testuser","test123","TESTDB" )
     
    # 使用cursor()方法获取操作游标 
    cursor = db.cursor()
     
    # SQL 删除语句
    sql = "DELETE FROM EMPLOYEE WHERE AGE > %s" % (20)
    try
       cursor.execute(sql)  # 执行SQL语句
       db.commit()          # 提交修改
    except
       db.rollback()        # 发生错误时回滚# 关闭连接
    db.close()
    

    import pymysql
     
    # 打开数据库连接
    db = pymysql.connect("localhost","testuser","test123","TESTDB" )
     
    # 使用cursor()方法获取操作游标 
    cursor = db.cursor()
     
    # SQL 更新语句
    sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = '%c'" % ('M')
    try:
       cursor.execute(sql)  # 执行SQL语句
       db.commit()          # 提交到数据库执行
    except
       db.rollback()        # 发生错误时回滚
     
    # 关闭数据库连接
    db.close()
    

    查询

    ​   ​   fetchone(): 获取一条记录

    ​   ​   fetchmany(): 获取多条记录

    ​​   ​   fetchall(): 接收全部返回的结果行

    ​   ​   rowcount: 并返回执行execute()方法后影响的行数

    import pymysql
    
    # 创建连接对象
    conn = pymysql.Connect('127.0.0.1', 'root', '123', 'day40', 3306)
    
    ## 创建  数据库游标对象
    cur = conn.cursor()
    
    sql = 'select * from book'
    
    # 执行sql
    cur.execute(sql)
    
    # 查询结果
    res1 = cur.fetchone()  # 查询一条  以元组的形式返回数据
    res2 = cur.fetchmany(2)  # 查询多条
    res3 = cur.fetchall()  # 查询全部
    
    print(res1)     # 控制台打印结果
    print(res2)
    print(res3)
    
    # 关闭连接
    cur.close()
    conn.close()
    
    

    五丶数据库的数据备份

    语法:

    ​​   ​   mysqldump -h 服务器 -u用户名 -p密码 数据库名 >备份文件名.sql

    # 数据库表备份
    	# 单库备份
    	mysqldump -uroot -p123 --databases db1 > db1.sql #(路径+文件名) 
    	# 单表备份
    	mysqldump -uroot -p123 db1 table1 > 数据库-表.sql #(路径+表文件名) 
    	
    	# 多库备份
    	mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql
    	# 多表备份
    	mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql
    
    # 备份所有库
    mysqldump -uroot -p123 --all-databases > all.sql 
    
    ### 数据恢复
    	#方法一:
        [root@egon backup]# mysql -uroot -p123 < /backup/all.sql
        
        #方法二: 先创建一个名字一样的库, source导入sql语句
        mysql> use db1;
        mysql> SET SQL_LOG_BIN=0;   #关闭二进制日志,只对当前session生效
        mysql> source /root/db1.sq
    

    六丶开启事务和锁

    begin;		#开启事务
    select * from 表 where id=1 for update ; # 查询id为1的值,  for update表示添加行级别锁
    update 表 set name='abc' where id=1;	    # 完成更新
    commit; 	#提交事务
    

    七丶事务

    什么是事务?

    # 事务是指包含多个微小逻辑单元的一组操作,只要其中的一个逻辑失败了,那么一组操作就全部失败. 不存在一半成功,一半不成功的状况.
    

    事务有什么用?

    # 事务在平常的CRUD中或许不太常用, 但当我们有一种需求,要求,一组操作中.必须全部成功才执行,才算完成任务. 只要有一个出了错,那么所有的任务都将回到最初的状况,恢复原样.如:银行的转账
    

    事务怎么用?

    1. 新建一个数据库 bank , 并且创建一张表 account , 用于存储用户的姓名 和 存款。
    
    2. 打开命令行,进入 mysql 终端
    
    3. 先使用 show variables  like '%commit%'; 来查看当前数据库的事务自动提交设置。
    
    4. 修改事务的自动提交 为 OFF , 也就是关闭自动提交,我们想手动提交,看看数据的变化。
    		
    		set autocommit = OFF ;   此处 off 小写也OK ,不区分大小写, 当然也可以写 0  , OFF 对应的是 0 , ON 对应的是 1;
    
    5. 对某个用户的存款进行修改。 接着在 命令行下查看数据,发现数据已经变化, 但是转到 GUI 下看,并没有任何变化。 这是因为我们没有提交数据。
    	在命令行看到的都是假象而已。 
    
    6. 在命令行下 输入 commit ;   来提交事务。 这时候,GUI 上面就显示出来最终的结果了。
    

    事务的ACID

    # 原子性Atomicity
    	事务中的逻辑d要全部执行 , 不可分割.
    # 一致性Consistency
    	指事务执行前和执行后,数据的完整性保持一致
    # 隔离性Isolation
    	指一个事物在执行的过程中不应该受其他事务的影响
    # 持久性Durability
    	事务执行结束(提交或回滚),数据都应持久化到数据中
    

    事务的安全问题

    ### 安全问题
    	### 读问题
    		# 脏读 : 一个事务,读到了另一个事务的还未提交的数据
    		# 不可重复读 : 一个事物 读到了另一个事物提交的数据,导致多次查询结果不一致
    		# 幻读 : 一个事物读到了另一个事物已提交的且插入的数据,导致多次查询结果不一致
    	
        
        ### 写问题
        	# 丢失更新
        		''
        			丢失更新: 指一个事物去修改数据库, 另一个事务也修改数据库,最后的那个事务.不管是提交还是回滚,都会造成前面一个事物的数据更新丢失
        		''
        	# 解决 丢失更新的方法:(悲观锁 和 乐观锁)	
        		# 悲观锁
    	指事务在一开始就认为丢失更新一定会发生, 这是一件很悲观的事情。 具体操作步骤如下:
    
    	# 1. 所有事务在执行操作前,先查询一次数据, 查询语句如下:
    
    		select * from student  for update  ;           后面的for update 其实是数据库锁机制 、 一种排他锁。
    
    	# 2. 哪个事务先执行这个语句, 哪个事务就持有了这把锁, 可以查询出来数据, 后面的事务再执行这条语句,不会有任何数据显示,就只能等着。 
    
    	# 3. 一直等到前面的那个事务提交数据后, 后面的事务数据才会出来,那么才可以往下接着操作。 
    
    
    ### 总结: 这有点像男生去上卫生间似的, 如果谁先来,谁就可以进去蹲着, 后面来的人,得等着。 只有里面的人出来了,才能进去。 这其实就是 java 中的同步的概念            
                
        		# 乐观锁
    	# 乐观锁是指,从来不会觉得丢失更新会发生。那么它的具体做法是什么呢? 
    
    	# 要求程序员在数据库中添加字段,然后在后续更新的时候,对该字段进行判定比对, 如果一致才允许更新。例子如下:
    
    	# 1. 数据库表中,额外添加了一个version字段, 用于记录版本, 默认从0 开始, 只要有针对表中数据进行修改的,那么version就+1.
    
    	# 2. 开启A事务, 然后开启B事务 。 
    
    	# 3. A 先执行数据库表操作。 因为以前都没有人修改过。 所以是允许A事务修改数据库的,但是修改完毕,就把version的值变成  1 了 。
    
    	# 4. B事务, 这时候如果想执行修改,那么是不允许修改的。 因为B事务以前是没有查询过数据库内容的,所以它认为数据库版本还是0 。 但是数据库的版本经过A修改,已经是1了。
    		所以这时候不允许修改, 要求其重新查询 。
    
    	# 5. B重新查询后, 将会得到version 为 1的数据,这份数据就是之前A 事务修改的数据了, B 在进行修改,也是在A的基础上修改的。 所以就不会有丢失更新的情况出现了。
    
    
    ### 总结: 乐观锁的机制 ,其实是通过比对版本或者比对字段的方式来实现的, 这与大家在未来的学习中,或者在工作中,使用到的版本控制软件【SVN , GIT】机制是一样的。       
    

    事务的隔离级别

    # 读未提交
    Read Uncommited【读未提交】
    
    指的是 : 一个事务可以读取到另一个事务还未提交的数据。 这就会引发 “脏读” 读取到的是数据库内存中的数据,而并非真正磁盘上的数据。
    
    例子: 
    
    	1. 开启一个命令行窗口A, 开始事务,然后查询表中记录。  设置当前窗口的事务隔离级别为 读未提交  命令如下:
    
    			set session transaction isolation level read uncommitted;
    
    	2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交
    
    	3. 在A窗口重新执行查询, 会看到B窗口没有提交的数据。 
    
    # 读已提交
    Read Commited 【读已提交】
    
    与前面的读未提交刚好相反,这个隔离级别是 ,只能读取到其他事务已经提交的数据,那些没有提交的数据是读不出来的。但是这会造成一个问题是: 前后读取到的结果不一样。 发生了不可重复!!!, 所谓的不可重复读,就是不能执行多次读取,否则出现结果不一 。 例子如下:
    
    	
    	1. 开启一个命令行窗口A, 开始事务,然后查询表中记录。  设置当前窗口的事务隔离级别为 读未提交  命令如下:
    
    			set session transaction isolation level read committed;
    
    	2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交 
    
    	
    
    	3. 在A窗口重新执行查询, 是不会看到B窗口刚才执行sql 语句的结果,因为它还没有提交。
    
    	4. 在B窗口执行提交。
    
    	5. 在A窗口中执行查看, 这时候才会看到B窗口已经修改的结果。
    
    	6. 但是这会造成一个问题是: 在A窗口中, 第一次查看数据和第二次查看数据,结果不一样。
    
    # 重复度
    Repeatable Read 【重复读】 -  MySql 默认的隔离级别就是这个。
    
    该隔离级别, 可以让事务在自己的会话中重复读取数据,并且不会出现结果不一样的状况,即使其他事务已经提交了,也依然还是显示以前的数据。
    
    	1. 开启一个命令行窗口A, 开始事务,然后查询表中记录。  设置当前窗口的事务隔离级别为 读未提交  命令如下:
    
    			set session transaction isolation level read committed;
    
    	2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交 
    
    	
    
    	3. 在A窗口重新执行查询, 是不会看到B窗口刚才执行sql 语句的结果,因为它还没有提交。
    
    	4. 在B窗口执行提交。
    
    	5. 在A窗口中执行查看, 这时候查询结果,和以前的查询结果一致。不会发生改变。
    
     
    
    # 可串行化
    Serializable 【可串行化】 
    
    该事务级别是最高级的事务级别了。比前面几种都要强大一点,也就是前面几种的问题【脏读、不可重复读、幻读】都能够解决。但是有一些缺点。
    
    	1. 开启一个命令行窗口A, 开始事务,然后查询表中记录。  设置当前窗口的事务隔离级别为 读未提交  命令如下:
    
    			set session transaction isolation level read serializable;
    
    	2. 另外在打开一个窗口B, 也开启事务, 然后执行 sql 语句, 但是不提交 
    
    	
    
    	3. 在A窗口重新执行查询, 会卡主,没有任何信息显示。 
    
    	4. 在B窗口执行提交。
    
    	5. 在A窗口中执行查看, 这时候才会显示结果。
    
    Serializable  可以防止上面的所有问题,但是都使用该隔离级别也会有些问题。 比如造成并发的性能问题。 其他的事务必须得等当前正在操作表的事务先提交,才能接着往下,否则只能一直在等着。
    
    

    八丶SQL注入

    # 只存在于原生SQL语句中的问题
    
    import pymysql
    
    conn=pymysql.Connect('127.0.0.1','root','123','day43',3306)
    cur=conn.cursor(cursor=pymysql.cursors.DictCursor) # 返回字典
    # cur=conn.cursor() # 返回元组
    # sql 注入~~
    user="al大撒旦ex' or 1=1 ;-- " # 方式一   sql注入 永真语法 恒1
    user="alex'  ;-- "          # 方式二   sql注入
    pwd='32131'
    # sql="select * from userinfo where name='alex' ; --and pwd='%s';"
    # sql="select * from userinfo where name='alexdsada' or 1=1 ; --and pwd='%s';"
    sql="select * from userinfo where name='%s' and pwd='%s';"%(user,pwd)
    cur.execute(sql)
    ret=cur.fetchall()
    print(ret)
    cur.close()
    conn.close()
    
  • 相关阅读:
    Delphi下遍历文件夹下所有文件的递归算法
    mysql + unidac 使用事务例子
    新建DataSnap REST Application
    ClientDataSet中的错误处理
    TSQLConnection的事务处理
    ClientDataSet的查找和过滤功能
    TField中的GetText和SetText
    ClientDataSet中撤消与恢复操作及执行细节
    ClientDataSet中动态添加计算字段并用计算字段显示记录的UpdateStatus
    ClientDataSet中动态添加计算字段
  • 原文地址:https://www.cnblogs.com/dengz/p/11335441.html
Copyright © 2020-2023  润新知