ホームページ  >  記事  >  データベース  >  PythonでMySQLを操作する方法

PythonでMySQLを操作する方法

WBOY
WBOY転載
2023-05-30 16:31:141838ブラウズ

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 フレームワーク

SQLAchemy


  • 2.1 PyMySQL モジュール

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

2.1.1 PyMySQL のインストール

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

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) を使用してカーソル位置を移動できます。 #cursor.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 モジュールのプレースホルダは疑問符 (?) になっているようです。 。したがって、他のデータベースを使用する場合は、ドキュメントを注意深く読むことをお勧めします。

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


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

#3.1 DBUtils モジュール

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

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


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


    #すべてのスレッドで共有するために、接続プールへの接続のバッチを作成します (推奨)

  • 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 サイトの他の関連記事を参照してください。

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