Skip to main content

python-pymysql

This skill should be used when the user asks to "connect to MySQL with PyMySQL", "use PyMySQL in Python", "query a MySQL database with Python", "set up PyMySQL", or needs guidance on PyMySQL best practices, transactions, parameterized queries, or cursor types.

Source facts

Repository
the-perfect-developer/the-perfect-opencode
Last source activity
March 5, 2026 at 15:33
Detected SKILL.md language
English
Stars
12
Forks
2

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
python-pymysql
description
This skill should be used when the user asks to "connect to MySQL with PyMySQL", "use PyMySQL in Python", "query a MySQL database with Python", "set up PyMySQL", or needs guidance on PyMySQL best practices, transactions, parameterized queries, or cursor types.
# PyMySQL Best Practices PyMySQL is a pure-Python MySQL client library implementing the DB-API 2.0 specification (PEP 249). It supports MySQL >= 5.7 and MariaDB >= 10.3 on Python >= 3.7. ## Installation ```bash pip install PyMySQL # For SHA-256 / caching_sha2_password authentication: pip install "PyMySQL[rsa]" ``` ## Establishing a Connection Use `pymysql.connect()` as the entry point. Always specify `charset='utf8mb4'` and use context managers to guarantee cleanup. ```python import pymysql import pymysql.cursors connection = pymysql.connect( host="localhost", user="app_user", password="secret", database="mydb", charset="utf8mb4", cursorclass=pymysql.cursors.DictCursor, connect_timeout=10, read_timeout=30, write_timeout=30, autocommit=False, # explicit transaction control (recommended) ) ``` ### Key Connection Parameters | Parameter | Default | Notes | |---|---|---| | `charset` | `''` | Always set `utf8mb4` for full Unicode support | | `cursorclass` | `Cursor` | Use `DictCursor` for dict rows; `SSCursor` for large result sets | | `autocommit` | `False` | Keep `False`; commit/rollback explicitly | | `connect_timeout` | `10` | Seconds before connection attempt fails | | `read_timeout` | `None` | Set to prevent hung reads | | `write_timeout` | `None` | Set to prevent hung writes | | `ssl_ca` | `None` | Path to CA cert for TLS connections | ## Context Manager Usage Connections and cursors implement the context manager protocol. Use `with` blocks to ensure proper resource cleanup. ```python # Connection as context manager — commits on success, rolls back on exception with pymysql.connect(**db_config) as connection: with connection.cursor() as cursor: cursor.execute("SELECT id, email FROM users WHERE active = %s", (1,)) rows = cursor.fetchall() ``` > **Note**: Using `with connection:` handles transaction commit/rollback but does **not** close the connection. Call `connection.close()` explicitly or manage it via a pool. ## Parameterized Queries (SQL Injection Prevention) Always pass values as the second argument to `execute()`. Never use string formatting or concatenation to build SQL. ```python # Correct — parameterized cursor.execute( "INSERT INTO orders (user_id, amount) VALUES (%s, %s)", (user_id, amount), ) # Named placeholders with dict cursor.execute( "SELECT * FROM products WHERE category = %(cat)s AND price < %(max_price)s", {"cat": "electronics", "max_price": 500}, ) # WRONG — never do this cursor.execute(f"SELECT * FROM users WHERE name = '{name}'") # SQL injection risk ``` Use `cursor.mogrify(query, args)` to preview the interpolated query string during debugging. ## Cursor Types | Cursor Class | Returns | Buffered | Use Case | |---|---|---|---| | `Cursor` | tuple | Yes | Default; small-to-medium result sets | | `DictCursor` | dict | Yes | When column-name access is needed | | `SSCursor` | tuple | No | Large result sets; memory-constrained | | `SSDictCursor` | dict | No | Large result sets with dict access | Pass `cursorclass` at connection time (global default) or per-cursor: ```python # Per-cursor override with connection.cursor(pymysql.cursors.DictCursor) as cursor: cursor.execute("SELECT * FROM users") rows = cursor.fetchall() # list of dicts ``` For large tables, prefer `SSCursor` and iterate without calling `fetchall()`: ```python with connection.cursor(pymysql.cursors.SSCursor) as cursor: cursor.execute("SELECT * FROM large_table") for row in cursor: # streams row-by-row process(row) ``` ## Transaction Management PyMySQL defaults to `autocommit=False`. Explicitly commit successful work and roll back on errors. ```python try: with connection.cursor() as cursor: cursor.execute( "UPDATE accounts SET balance = balance - %s WHERE id = %s", (amount, from_id), ) cursor.execute( "UPDATE accounts SET balance = balance + %s WHERE id = %s", (amount, to_id), ) connection.commit() except Exception: connection.rollback() raise ``` Call `connection.begin()` to start a transaction block explicitly when needed. ## Bulk Inserts with `executemany()` Use `executemany()` for inserting multiple rows. PyMySQL batches the statements up to `Cursor.max_stmt_length` (1 MB) for efficiency. ```python records = [ ("alice@example.com", "hash1"), ("bob@example.com", "hash2"), ] with connection.cursor() as cursor: cursor.execute("TRUNCATE TABLE staging_users") cursor.executemany( "INSERT INTO users (email, password_hash) VALUES (%s, %s)", records, ) connection.commit() ``` ## Fetching Rows | Method | Returns | Notes | |---|---|---| | `fetchone()` | single row or `None` | Efficient for single-row lookups | | `fetchmany(size)` | list of rows | Page through results | | `fetchall()` | list of all rows | Avoid on large result sets | ```python cursor.execute("SELECT id, name FROM users WHERE id = %s", (user_id,)) row = cursor.fetchone() if row is None: raise ValueError(f"User {user_id} not found") ``` ## Error Handling Catch PyMySQL exceptions from `pymysql.err`: ```python import pymysql.err try: with connection.cursor() as cursor: cursor.execute(sql, args) connection.commit() except pymysql.err.IntegrityError as exc: connection.rollback() # duplicate key, foreign key violation, etc. raise except pymysql.err.OperationalError as exc: # connection dropped, timeout, server gone away raise except pymysql.err.ProgrammingError as exc: # bad SQL syntax, wrong number of params raise ``` Key exception classes: - `pymysql.err.IntegrityError` — constraint violations (duplicate key, FK) - `pymysql.err.OperationalError` — connection / server errors - `pymysql.err.ProgrammingError` — SQL syntax errors, wrong param count - `pymysql.err.DataError` — invalid data for column type - `pymysql.err.DatabaseError` — base class for all DB errors ## Connection Health Check Use `connection.ping(reconnect=True)` to check liveness before executing queries in long-lived connections (e.g., background workers): ```python connection.ping(reconnect=True) with connection.cursor() as cursor: cursor.execute(query) ``` ## Reading Config from `my.cnf` Avoid hardcoding credentials. Use `read_default_file` to read from a MySQL option file: ```python connection = pymysql.connect( read_default_file="~/.my.cnf", read_default_group="client", database="mydb", charset="utf8mb4", cursorclass=pymysql.cursors.DictCursor, ) ``` `~/.my.cnf` example: ```ini [client] host = db.internal user = app_user password = secret ``` ## Quick Reference ```python import pymysql import pymysql.cursors # Connect conn = pymysql.connect( host="localhost", user="u", password="p", database="db", charset="utf8mb4", cursorclass=pymysql.cursors.DictCursor, ) # Query with conn.cursor() as cur: cur.execute("SELECT * FROM t WHERE id = %s", (1,)) row = cur.fetchone() # Write + commit with conn.cursor() as cur: cur.execute("INSERT INTO t (col) VALUES (%s)", ("val",)) conn.commit() # Bulk insert with conn.cursor() as cur: cur.executemany("INSERT INTO t (a, b) VALUES (%s, %s)", rows) conn.commit() conn.close() ``` ## Additional Resources For detailed patterns and advanced usage, consult: - **`references/connection-patterns.md`** — Connection pooling, SSL/TLS configuration, timeout tuning, `my.cnf` patterns - **`references/cursor-guide.md`** — Cursor type selection, streaming large result sets, stored procedures, `mogrify` debugging
View on GitHub