ホームページ  >  記事  >  バックエンド開発  >  完成度高すぎ! Pythonを使ってMySQLを操作するチュートリアル集!

完成度高すぎ! Pythonを使ってMySQLを操作するチュートリアル集!

WBOY
WBOY転載
2023-04-14 08:40:021796ブラウズ

完成度高すぎ! Pythonを使ってMySQLを操作するチュートリアル集!

1. Python オペレーティング データベースの概要

Python の標準データベース インターフェイスは Python DB-API であり、開発者にデータベース アプリケーション プログラミング インターフェイスを提供します。 Python データベース インターフェイスは多くのデータベースをサポートしています。プロジェクトに適したデータベースを選択できます:

  • GadFly
  • mSQL
  • MySQL
  • PostgreSQL
  • Microsoft SQL Server 2000
  • Informix
  • Interbase
  • Oracle
  • Sybase…

Python データベース インターフェイスと API にアクセスして、サポートされているデータベースの詳細なリストを表示できます。

データベースごとに異なる DB API モジュールをダウンロードする必要があります。たとえば、Oracle データベースと MySQL データにアクセスする必要がある場合は、Oracle および MySQL データベース モジュールをダウンロードする必要があります。

DB-API は仕様であり、基礎となるさまざまなデータベース システムやさまざまなデータベース インターフェイス プログラムへの一貫したアクセスを提供するために、一連の必要なオブジェクトとデータベース アクセス メソッドを定義します。

Python の DB-API は、ほとんどのデータベースのインターフェースを実装しており、これを使用して各データベースに接続すると、各データベースを同様に操作できます。

Python DB-API の使用プロセス:

  • API モジュールを紹介します。
  • データベースへの接続を取得します。
  • SQL ステートメントとストアド プロシージャを実行します。
  • データベース接続を閉じます。

2. Python は MySQL モジュールを操作します

Python は主に 2 つの方法で MySQL を操作します:

DB モジュール (ネイティブ SQL) )

  • PyMySQL (python2.x/3.x をサポート)
  • MySQLdb (現在 python2.x のみをサポート)
##ORM Framework

    SQLAchemy

2.1 PyMySQL モジュール


この記事では主に PyMySQL モジュール、MySQLdb について紹介します。同様の方法で使用されます


2.1.1 PyMySQL のインストール

PyMySQL は Python で書かれた MySQL ドライバーであり、これを使用して MySQL データベースを操作できます。 Python 言語。


pip install PyMySQL

2.2 基本的な使い方


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import pymysql
# 创建连接
conn = pymysql.connect(host="127.0.0.1", port=3306, user='zff', passwd='zff123', db='zff', charset='utf8mb4')
# 创建游标(查询数据返回为元组格式)
# cursor = conn.cursor()
# 创建游标(查询数据返回为字典格式)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 1. 执行SQL,返回受影响的行数
effect_row1 = cursor.execute("select * from USER")
# 2. 执行SQL,返回受影响的行数,一次插入多行数据
effect_row2 = cursor.executemany("insert into USER (NAME) values(%s)", [("jack"), ("boom"), ("lucy")])# 3
# 查询所有数据,返回数据为元组格式
result = cursor.fetchall()
# 增/删/改均需要进行commit提交,进行保存
conn.commit()
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
print(result)
"""
[{'id': 6, 'name': 'boom'}, {'id': 5, 'name': 'jack'}, {'id': 7, 'name': 'lucy'}, {'id': 4, 'name': 'tome'}, {'id': 3, 'name': 'zff'}, {'id': 1, 'name': 'zhaofengfeng'}, {'id': 2, 'name': 'zhaofengfeng02'}]
"""

2.3 自動インクリメントIDで最新作成データを取得


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import pymysql
# 创建连接
conn = pymysql.connect(host="127.0.0.1", port=3306, user='zff', passwd='zff123', db='zff', charset='utf8mb4')
# 创建游标(查询数据返回为元组格式)
cursor = conn.cursor()
# 获取新创建数据自增ID
effect_row = cursor.executemany("insert into USER (NAME)values(%s)", [("eric")])
# 增删改均需要进行commit提交
conn.commit()
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
new_id = cursor.lastrowid
print(new_id)
"""
8
"""

2.4 クエリ操作


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import pymysql
# 创建连接
conn = pymysql.connect(host="127.0.0.1", port=3306, user='zff', passwd='zff123', db='zff', charset='utf8mb4')
# 创建游标
cursor = conn.cursor()
cursor.execute("select * from USER")
# 获取第一行数据
row_1 = cursor.fetchone()
# 获取前n行数据
row_2 = cursor.fetchmany(3)
#
# # 获取所有数据
row_3 = cursor.fetchall()
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
print(row_1)
print(row_2)
print(row_3)

⚠️ データを取得するときは、順番に進みます。


    カーソルのように、cursor.scroll(num,mode) を使用してカーソル位置を移動できます。 scroll(1,mode ='relative') #現在位置を基準にして移動

  • #cursor.scroll(2,mode='absolute')#絶対位置を基準にして移動

  • 2.5 SQL インジェクションの防止

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import pymysql
# 创建连接
conn = pymysql.connect(host="127.0.0.1", port=3306, user='zff', passwd='zff123', db='zff', charset='utf8mb4')
# 创建游标
cursor = conn.cursor()
# 存在sql注入情况(不要用格式化字符串的方式拼接SQL)
sql = "insert into USER (NAME) values('%s')" % ('zhangsan',)
effect_row = cursor.execute(sql)
# 正确方式一
# execute函数接受一个元组/列表作为SQL参数,元素个数只能有1个
sql = "insert into USER (NAME) values(%s)"
effect_row1 = cursor.execute(sql, ['wang6'])
effect_row2 = cursor.execute(sql, ('wang7',))
# 正确方式二
sql = "insert into USER (NAME) values(%(name)s)"
effect_row1 = cursor.execute(sql, {'name': 'wudalang'})
# 写入插入多行数据
effect_row2 = cursor.executemany("insert into USER (NAME) values(%s)", [('ermazi'), ('dianxiaoer')])
# 提交
conn.commit()
# 关闭游标
cursor.close()
# 关闭连接
conn.close()

これにより、SQL 操作がより安全になります。さらに詳細なドキュメントが必要な場合は、PyMySQL ドキュメントを参照してください。ただし、これらの SQL データベースの実装は同じではないようで、PyMySQL のパラメータ プレースホルダは %s などの C フォーマッタを使用しますが、Python 付属の sqlite3 モジュールのプレースホルダは疑問符 (?) になっているようです。 。したがって、他のデータベースを使用する場合は、ドキュメントを注意深く読むことをお勧めします。 PyMySQL のドキュメントへようこそ


3. データベース接続プール


上記の方法には問題があります。シングルスレッドの状況では満足できます。プログラムには次の必要があります。接続の作成と解放を頻繁に行う必要があります。データベースでの操作が完了した後、プログラム/スクリプトはマルチスレッドでどのような問題を引き起こしますか?現時点では、この問題を解決するにはデータベース接続プールを使用する必要があります!


3.1 DBUtils モジュール


DBUtils は、データベース接続プーリングを実装するために使用される Python のモジュールです。


この接続プールには 2 つの接続モードがあります:


スレッドごとに接続を作成します。スレッドが close メソッドを呼び出しても、スレッドは閉じられません。独自のスレッドで再び使用できるように、接続を接続プールに戻すだけです。スレッドが終了すると、接続は自動的に閉じられます。

  • すべてのスレッドで共有して使用する接続プールへの接続のバッチを作成します (推奨)

  • 3.2 モード 1

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
from DBUtils.PersistentDB import PersistentDB
import pymysql
POOL = PersistentDB(
 creator=pymysql,# 使用链接数据库的模块
 maxusage=None,# 一个链接最多被重复使用的次数,None表示无限制
 setsession=[],# 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
 ping=0,
 # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
 closeable=False,
 # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
 threadlocal=None,# 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
 host='127.0.0.1',
 port=3306,
 user='zff',
 password='zff123',
 database='zff',
 charset='utf8',
)
def func():
 conn = POOL.connection(shareable=False)
 cursor = conn.cursor()
 cursor.execute('select * from USER')
 result = cursor.fetchall()
 cursor.close()
 conn.close()
 return result
result = func()
print(result)

3.2 モード 2

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import time
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
POOL = PooledDB(
 creator=pymysql,# 使用链接数据库的模块
 maxconnections=6,# 连接池允许的最大连接数,0和None表示不限制连接数
 mincached=2,# 初始化时,链接池中至少创建的空闲的链接,0表示不创建
 maxcached=5,# 链接池中最多闲置的链接,0和None不限制
 maxshared=3,
 # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
 blocking=True,# 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
 maxusage=None,# 一个链接最多被重复使用的次数,None表示无限制
 setsession=[],# 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
 ping=0,
 # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
 host='127.0.0.1',
 port=3306,
 user='zff',
 password='zff123',
 database='zff',
 charset='utf8'
)
def func():
 # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常
 # 否则
 # 则优先去初始化时创建的链接中获取链接 SteadyDBConnection。
 # 然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。
 # 如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。
 # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。
 conn = POOL.connection()
 # print('连接被拿走了', conn._con)
 # print('池子里目前有', POOL._idle_cache, 'rn')
 cursor = conn.cursor()
 cursor.execute('select * from USER')
 result = cursor.fetchall()
 conn.close()
 return result
result = func()
print(result)

⚠️ pymysql、MySQLdb などのスレッドセーフ値が 1 であるため、このモードでは接続プール内のスレッドがすべてのスレッドで共有されるため、スレッドセーフです。接続プールがない場合、pymysqlを使用してデータベースに接続する場合、シングルスレッドのアプリケーションでは問題ありませんが、マルチスレッドのアプリケーションではロックが必要となり、一度ロックされると必然的に接続がキューアップされます。リクエストが多いとパフォーマンスが低下し、パフォーマンスが低下します。


3.3 ロックあり

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import pymysql
import threading
from threading import RLock
LOCK = RLock()
CONN = pymysql.connect(host='127.0.0.1',
port=3306,
user='zff',
password='zff123',
database='zff',
charset='utf8')
def task(arg):
 with LOCK:
 cursor = CONN.cursor()
 cursor.execute('select * from USER ')
 result = cursor.fetchall()
 cursor.close()
 print(result)
for i in range(10):
 t = threading.Thread(target=task, args=(i,))
 t.start()

3.4 ロックなし (エラーレポート)

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2018/5/13
import pymysql
import threading
CONN = pymysql.connect(host='127.0.0.1',
port=3306,
user='zff',
password='zff123',
database='zff',
charset='utf8')
def task(arg):
 cursor = CONN.cursor()
 cursor.execute('select * from USER ')
 # cursor.execute('select sleep(10)')
 result = cursor.fetchall()
 cursor.close()
 print(result)
for i in range(10):
 t = threading.Thread(target=task, args=(i,))
 t.start()

このとき、接続ステータスはデータベース: 'Threads%' のようなステータスを表示;


4. データベース接続プールを pYSql

# cat sql_helper.py
import pymysql
import threading
from DBUtils.PooledDB import PooledDB, SharedDBConnection
POOL = PooledDB(
 creator=pymysql,# 使用链接数据库的模块
 maxconnections=20,# 连接池允许的最大连接数,0和None表示不限制连接数
 mincached=2,# 初始化时,链接池中至少创建的空闲的链接,0表示不创建
 maxcached=5,# 链接池中最多闲置的链接,0和None不限制
 #maxshared=3,# 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
 blocking=True,# 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
 maxusage=None,# 一个链接最多被重复使用的次数,None表示无限制
 setsession=[],# 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
 ping=0,
 # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
 host='192.168.11.38',
 port=3306,
 user='root',
 passwd='apNXgF6RDitFtDQx',
 db='m2day03db',
 charset='utf8'
)
def connect():
 # 创建连接
 # conn = pymysql.connect(host='192.168.11.38', port=3306, user='root', passwd='apNXgF6RDitFtDQx', db='m2day03db')
 conn = POOL.connection()
 # 创建游标
 cursor = conn.cursor(pymysql.cursors.DictCursor)
 return conn,cursor
def close(conn,cursor):
 # 关闭游标
 cursor.close()
 # 关闭连接
 conn.close()
def fetch_one(sql,args):
 conn,cursor = connect()
 # 执行SQL,并返回收影响行数
 effect_row = cursor.execute(sql,args)
 result = cursor.fetchone()
 close(conn,cursor)
 return result
def fetch_all(sql,args):
 conn, cursor = connect()
 # 执行SQL,并返回收影响行数
 cursor.execute(sql,args)
 result = cursor.fetchall()
 close(conn, cursor)
 return result
def insert(sql,args):
 """
 创建数据
 :param sql: 含有占位符的SQL
 :return:
 """
 conn, cursor = connect()
 # 执行SQL,并返回收影响行数
 effect_row = cursor.execute(sql,args)
 conn.commit()
 close(conn, cursor)
def delete(sql,args):
 """
 创建数据
 :param sql: 含有占位符的SQL
 :return:
 """
 conn, cursor = connect()
 # 执行SQL,并返回收影响行数
 effect_row = cursor.execute(sql,args)
 conn.commit()
 close(conn, cursor)
 return effect_row
def update(sql,args):
 conn, cursor = connect()
 # 执行SQL,并返回收影响行数
 effect_row = cursor.execute(sql, args)
 conn.commit()
 close(conn, cursor)
 return effect_row

と組み合わせて使用​​しますPS: 静的メソッドを使用してカプセル化できます使いやすいクラスに統合

以上が完成度高すぎ! Pythonを使ってMySQLを操作するチュートリアル集!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。