add
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
Binary file not shown.
@@ -0,0 +1,46 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
|
||||
from aiomysql import __version__
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
project = 'aiomysql'
|
||||
copyright = '2015,2016 Nikolay Novik'
|
||||
author = 'Nikolay Novik'
|
||||
|
||||
version = '.'.join(__version__.split('.')[:2])
|
||||
release = __version__
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx_copybutton',
|
||||
]
|
||||
|
||||
intersphinx_mapping = {
|
||||
'python': ('https://docs.python.org/3', None),
|
||||
}
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
language = 'en'
|
||||
|
||||
highlight_language = 'python3'
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
html_theme = 'furo'
|
||||
|
||||
htmlhelp_basename = 'aiomysqldoc'
|
||||
@@ -0,0 +1,206 @@
|
||||
.. _api:
|
||||
|
||||
:mod:`aiomysql` --- API Reference
|
||||
=================================
|
||||
|
||||
.. module:: aiomysql
|
||||
:synopsis: A library for accessing a MySQL database from the asyncio
|
||||
.. currentmodule:: aiomysql
|
||||
|
||||
.. _aiomysql-connection:
|
||||
|
||||
Connection
|
||||
==========
|
||||
|
||||
The library provides a way to connect to MySQL database with simple factory
|
||||
function :func:`aiomysql.connnect`. Use this function if you want just one
|
||||
connection to the database, consider connection pool for multiple connections.
|
||||
|
||||
Example::
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def test_example():
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='', db='mysql',
|
||||
loop=loop)
|
||||
|
||||
cur = await conn.cursor()
|
||||
await cur.execute("SELECT Host,User FROM user")
|
||||
print(cur.description)
|
||||
r = await cur.fetchall()
|
||||
print(r)
|
||||
await cur.close()
|
||||
conn.close()
|
||||
|
||||
loop.run_until_complete(test_example())
|
||||
|
||||
|
||||
.. function:: connect(host="localhost", user=None, password="",
|
||||
db=None, port=3306, unix_socket=None,
|
||||
charset='', sql_mode=None,
|
||||
read_default_file=None, conv=decoders, use_unicode=None,
|
||||
client_flag=0, cursorclass=Cursor, init_command=None,
|
||||
connect_timeout=None, read_default_group=None,
|
||||
autocommit=False, echo=False
|
||||
local_infile=False, loop=None, ssl=None, auth_plugin='',
|
||||
program_name='', server_public_key=None)
|
||||
|
||||
A :ref:`coroutine <coroutine>` that connects to MySQL.
|
||||
|
||||
The function accepts all parameters that :func:`pymysql.connect`
|
||||
does plus optional keyword-only *loop* and *timeout* parameters.
|
||||
|
||||
:param str host: host where the database server is located,
|
||||
default: `localhost`.
|
||||
:param str user: username to log in as.
|
||||
:param str password: password to use.
|
||||
:param str db: database to use, None to not use a particular one.
|
||||
:param int port: MySQL port to use, default is usually OK.
|
||||
:param str unix_socket: optionally, you can use a unix socket rather
|
||||
than TCP/IP.
|
||||
:param str charset: charset you want to use, for example 'utf8'.
|
||||
:param sql_mode: default sql-mode_ to use, like 'NO_BACKSLASH_ESCAPES'
|
||||
:param read_default_file: specifies my.cnf file to read these
|
||||
parameters from under the [client] section.
|
||||
:param conv: decoders dictionary to use instead of the default one.
|
||||
This is used to provide custom marshalling of types.
|
||||
See `pymysql.converters`.
|
||||
:param use_unicode: whether or not to default to unicode strings.
|
||||
:param client_flag: custom flags to send to MySQL. Find
|
||||
potential values in `pymysql.constants.CLIENT`. Refer to the
|
||||
`local_infile` parameter for enabling loading of local data.
|
||||
:param cursorclass: custom cursor class to use.
|
||||
:param str init_command: initial SQL statement to run when connection is
|
||||
established.
|
||||
:param connect_timeout: Timeout in seconds before throwing an exception
|
||||
when connecting.
|
||||
:param str read_default_group: Group to read from in the configuration
|
||||
file.
|
||||
:param autocommit: Autocommit mode. None means use server default.
|
||||
(default: ``False``)
|
||||
:param local_infile: Boolean to enable the use of `LOAD DATA LOCAL`
|
||||
command. This also enables the corresponding `client_flag`. aiomysql
|
||||
does not perform any validation of files requested by the server. Do
|
||||
not use this with untrusted servers. (default: ``False``)
|
||||
:param ssl: Optional SSL Context to force SSL
|
||||
:param auth_plugin: String to manually specify the authentication
|
||||
plugin to use, i.e you will want to use mysql_clear_password
|
||||
when using IAM authentication with Amazon RDS.
|
||||
(default: Server Default)
|
||||
:param program_name: Program name string to provide when
|
||||
handshaking with MySQL. (omitted by default)
|
||||
|
||||
.. versionchanged:: 1.0
|
||||
``sys.argv[0]`` is no longer passed by default
|
||||
:param server_public_key: SHA256 authenticaiton plugin public key value.
|
||||
:param loop: asyncio event loop instance or ``None`` for default one.
|
||||
:returns: :class:`Connection` instance.
|
||||
|
||||
|
||||
Representation of a socket with a mysql server. The proper way to get an
|
||||
instance of this class is to call :func:`aiomysql.connnect`.
|
||||
|
||||
Its insterface is almost the same as `pymysql.connection` except all methods
|
||||
are :ref:`coroutines <coroutine>`.
|
||||
|
||||
|
||||
The most important methods are:
|
||||
|
||||
.. method:: cursor(cursor=None)
|
||||
|
||||
A :ref:`coroutine <coroutine>` that creates a new cursor object
|
||||
using the connection.
|
||||
|
||||
By default, :class:`Cursor` is returned. It is possible to also give a
|
||||
custom cursor through the `cursor` parameter, but it needs to
|
||||
be a subclass of :class:`Cursor`
|
||||
|
||||
:param cursor: subclass of :class:`Cursor` or ``None`` for default
|
||||
cursor.
|
||||
:returns: :class:`Cursor` instance.
|
||||
|
||||
.. method:: close()
|
||||
|
||||
Immediately close the connection.
|
||||
|
||||
Close the connection now (rather than whenever `del` is executed).
|
||||
The connection will be unusable from this point forward.
|
||||
|
||||
.. method:: ensure_closed()
|
||||
|
||||
A :ref:`coroutine <coroutine>` ends quit command and then closes
|
||||
socket connection.
|
||||
|
||||
.. method:: autocommit(value)
|
||||
|
||||
A :ref:`coroutine <coroutine>` to enable/disable autocommit mode for
|
||||
current MySQL session.
|
||||
:param bool value: toggle atutocommit mode.
|
||||
|
||||
.. method:: get_autocommit()
|
||||
|
||||
Returns autocommit status for current MySQL sesstion.
|
||||
:returns bool: current autocommit status.
|
||||
|
||||
.. method:: begin()
|
||||
|
||||
A :ref:`coroutine <coroutine>` to begin transaction.
|
||||
|
||||
.. method:: commit()
|
||||
|
||||
Commit changes to stable storage :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: rollback()
|
||||
|
||||
Roll back the current transaction :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: select_db(db)
|
||||
|
||||
A :ref:`coroutine <coroutine>` to set current db.
|
||||
|
||||
:param str db: database name
|
||||
|
||||
.. attribute:: closed
|
||||
|
||||
The readonly property that returns ``True`` if connections is closed.
|
||||
|
||||
.. attribute:: host
|
||||
|
||||
MySQL server IP address or name.
|
||||
|
||||
.. attribute:: port
|
||||
|
||||
MySQL server TCP/IP port.
|
||||
|
||||
|
||||
.. attribute:: unix_socket
|
||||
|
||||
ySQL Unix socket file location.
|
||||
|
||||
.. attribute:: db
|
||||
|
||||
Current database name.
|
||||
|
||||
.. attribute:: user
|
||||
|
||||
User used while connecting to MySQL
|
||||
|
||||
.. attribute:: echo
|
||||
|
||||
Return echo mode status.
|
||||
|
||||
.. attribute:: encoding
|
||||
|
||||
Encoding employed for this connection.
|
||||
|
||||
|
||||
.. attribute:: charset
|
||||
|
||||
Returns the character set for current connection.
|
||||
|
||||
|
||||
.. _sql-mode: http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html
|
||||
@@ -0,0 +1,3 @@
|
||||
.. _aiomysql-contributing:
|
||||
|
||||
.. include:: ../CONTRIBUTING.rst
|
||||
@@ -0,0 +1,390 @@
|
||||
.. _aiomysql-cursors:
|
||||
|
||||
Cursor
|
||||
======
|
||||
|
||||
.. class:: Cursor
|
||||
|
||||
A cursor for connection.
|
||||
|
||||
Allows Python code to execute :term:`MySQL` command in a database
|
||||
session. Cursors are created by the :meth:`Connection.cursor`
|
||||
:ref:`coroutine <coroutine>`: they are bound to the connection for
|
||||
the entire lifetime and all the commands are executed in the context
|
||||
of the database session wrapped by the connection.
|
||||
|
||||
Cursors that are created from the same connection are not isolated,
|
||||
i.e., any changes done to the database by a cursor are immediately
|
||||
visible by the other cursors. Cursors created from different
|
||||
connections can or can not be isolated, depending on the
|
||||
connections’ isolation level.
|
||||
|
||||
.. code:: python
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def test_example():
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='mysql', loop=loop)
|
||||
|
||||
# create default cursor
|
||||
cursor = await conn.cursor()
|
||||
|
||||
# execute sql query
|
||||
await cursor.execute("SELECT Host, User FROM user")
|
||||
|
||||
# fetch all results
|
||||
r = await cursor.fetchall()
|
||||
|
||||
# detach cursor from connection
|
||||
await cursor.close()
|
||||
|
||||
# close connection
|
||||
conn.close()
|
||||
|
||||
loop.run_until_complete(test_example())
|
||||
|
||||
|
||||
Use :meth:`Connection.cursor()` for getting cursor for connection.
|
||||
|
||||
.. attribute:: connection
|
||||
|
||||
This read-only attribute return a reference to the :class:`Connection`
|
||||
object on which the cursor was created
|
||||
|
||||
.. attribute:: echo
|
||||
|
||||
Return echo mode status.
|
||||
|
||||
.. attribute:: description
|
||||
|
||||
This read-only attribute is a sequence of 7-item sequences.
|
||||
|
||||
Each of these sequences is a collections.namedtuple containing
|
||||
information describing one result column:
|
||||
|
||||
0. name: the name of the column returned.
|
||||
1. type_code: the type of the column.
|
||||
2. display_size: the actual length of the column in bytes.
|
||||
3. internal_size: the size in bytes of the column associated to
|
||||
this column on the server.
|
||||
4. precision: total number of significant digits in columns of
|
||||
type ``NUMERIC``. None for other types.
|
||||
5. scale: count of decimal digits in the fractional part in
|
||||
columns of type ``NUMERIC``. None for other types.
|
||||
6. null_ok: always None.
|
||||
|
||||
This attribute will be None for operations that do not
|
||||
return rows or if the cursor has not had an operation invoked
|
||||
via the :meth:`Cursor.execute()` method yet.
|
||||
|
||||
.. attribute:: rowcount
|
||||
|
||||
Returns the number of rows that has been produced of affected.
|
||||
|
||||
This read-only attribute specifies the number of rows that the
|
||||
last :meth:`Cursor.execute()` produced (for Data Query Language
|
||||
statements like SELECT) or affected (for Data Manipulation
|
||||
Language statements like ``UPDATE`` or ``INSERT``).
|
||||
|
||||
The attribute is -1 in case no :meth:`Cursor.execute()` has been
|
||||
performed on the cursor or the row count of the last operation if it
|
||||
can't be determined by the interface.
|
||||
|
||||
.. attribute:: rownumber
|
||||
|
||||
Row index. This read-only attribute provides the current 0-based index
|
||||
of the cursor in the result set or ``None`` if the index cannot be
|
||||
determined.
|
||||
|
||||
.. attribute:: arraysize
|
||||
|
||||
How many rows will be returned by :meth:`Cursor.fetchmany()` call.
|
||||
|
||||
This read/write attribute specifies the number of rows to
|
||||
fetch at a time with :meth:`Cursor.fetchmany()`. It defaults to
|
||||
1 meaning to fetch a single row at a time.
|
||||
|
||||
.. attribute:: lastrowid
|
||||
|
||||
This read-only property returns the value generated for an
|
||||
`AUTO_INCREMENT` column by the previous `INSERT` or `UPDATE` statement
|
||||
or None when there is no such value available. For example,
|
||||
if you perform an `INSERT` into a table that contains an
|
||||
`AUTO_INCREMENT` column, :attr:`Cursor.lastrowid` returns the
|
||||
`AUTO_INCREMENT` value for the new row.
|
||||
|
||||
.. attribute:: closed
|
||||
|
||||
The readonly property that returns ``True`` if connections was detached
|
||||
from current cursor
|
||||
|
||||
.. method:: close()
|
||||
|
||||
:ref:`Coroutine <coroutine>` to close the cursor now (rather than
|
||||
whenever ``del`` is executed). The cursor will be unusable from this
|
||||
point forward; closing a cursor just exhausts all remaining data.
|
||||
|
||||
.. method:: execute(query, args=None)
|
||||
|
||||
:ref:`Coroutine <coroutine>`, executes the given operation substituting
|
||||
any markers with the given parameters.
|
||||
|
||||
For example, getting all rows where id is 5::
|
||||
|
||||
await cursor.execute("SELECT * FROM t1 WHERE id=%s", (5,))
|
||||
|
||||
:param str query: sql statement
|
||||
:param list args: tuple or list of arguments for sql query
|
||||
:returns int: number of rows that has been produced of affected
|
||||
|
||||
.. method:: executemany(query, args)
|
||||
|
||||
The `executemany()` :ref:`coroutine <coroutine>` will execute the
|
||||
operation iterating over the list of parameters in seq_params.
|
||||
|
||||
Example: Inserting 3 new employees and their phone number::
|
||||
|
||||
data = [
|
||||
('Jane','555-001'),
|
||||
('Joe', '555-001'),
|
||||
('John', '555-003')
|
||||
]
|
||||
stmt = "INSERT INTO employees (name, phone)
|
||||
VALUES ('%s','%s')"
|
||||
await cursor.executemany(stmt, data)
|
||||
|
||||
`INSERT` statements are optimized by batching the data, that is
|
||||
using the MySQL multiple rows syntax.
|
||||
|
||||
:param str query: sql statement
|
||||
:param list args: tuple or list of arguments for sql query
|
||||
|
||||
.. method:: callproc(procname, args)
|
||||
|
||||
Execute stored procedure procname with args, this method is
|
||||
:ref:`coroutine <coroutine>`.
|
||||
|
||||
Compatibility warning: PEP-249 specifies that any modified
|
||||
parameters must be returned. This is currently impossible
|
||||
as they are only available by storing them in a server
|
||||
variable and then retrieved by a query. Since stored
|
||||
procedures return zero or more result sets, there is no
|
||||
reliable way to get at OUT or INOUT parameters via `callproc`.
|
||||
The server variables are named `@_procname_n`, where `procname`
|
||||
is the parameter above and n is the position of the parameter
|
||||
(from zero). Once all result sets generated by the procedure
|
||||
have been fetched, you can issue a `SELECT @_procname_0`, ...
|
||||
query using :meth:`Cursor.execute()` to get any OUT or INOUT values.
|
||||
Basic usage example::
|
||||
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='mysql', loop=self.loop)
|
||||
|
||||
cur = await conn.cursor()
|
||||
await cur.execute("""CREATE PROCEDURE myinc(p1 INT)
|
||||
BEGIN
|
||||
SELECT p1 + 1;
|
||||
END
|
||||
""")
|
||||
|
||||
await cur.callproc('myinc', [1])
|
||||
(ret, ) = await cur.fetchone()
|
||||
assert 2, ret
|
||||
|
||||
await cur.close()
|
||||
conn.close()
|
||||
|
||||
Compatibility warning: The act of calling a stored procedure
|
||||
itself creates an empty result set. This appears after any
|
||||
result sets generated by the procedure. This is non-standard
|
||||
behavior with respect to the DB-API. Be sure to use
|
||||
:meth:`Cursor.nextset()` to advance through all result sets; otherwise
|
||||
you may get disconnected.
|
||||
|
||||
:param str procname: name of procedure to execute on server
|
||||
:param args: sequence of parameters to use with procedure
|
||||
:returns: the original args.
|
||||
|
||||
.. method:: fetchone()
|
||||
|
||||
Fetch the next row :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: fetchmany(size=None)
|
||||
|
||||
:ref:`Coroutine <coroutine>` the next set of rows of a query result,
|
||||
returning a list of tuples. When no more rows are available, it
|
||||
returns an empty list.
|
||||
|
||||
The number of rows to fetch per call is specified by the parameter.
|
||||
If it is not given, the cursor's :attr:`Cursor.arraysize` determines
|
||||
the number of rows to be fetched. The method should try to fetch as
|
||||
many rows as indicated by the size parameter. If this is not possible
|
||||
due to the specified number of rows not being available, fewer rows
|
||||
may be returned ::
|
||||
|
||||
cursor = await connection.cursor()
|
||||
await cursor.execute("SELECT * FROM test;")
|
||||
r = cursor.fetchmany(2)
|
||||
print(r)
|
||||
# [(1, 100, "abc'def"), (2, None, 'dada')]
|
||||
r = await cursor.fetchmany(2)
|
||||
print(r)
|
||||
# [(3, 42, 'bar')]
|
||||
r = await cursor.fetchmany(2)
|
||||
print(r)
|
||||
# []
|
||||
|
||||
:param int size: number of rows to return
|
||||
:returns list: of fetched rows
|
||||
|
||||
.. method:: fetchall()
|
||||
|
||||
:ref:`Coroutine <coroutine>` returns all rows of a query result set::
|
||||
|
||||
await cursor.execute("SELECT * FROM test;")
|
||||
r = await cursor.fetchall()
|
||||
print(r)
|
||||
# [(1, 100, "abc'def"), (2, None, 'dada'), (3, 42, 'bar')]
|
||||
|
||||
:returns list: list of fetched rows
|
||||
|
||||
.. method:: scroll(value, mode='relative')
|
||||
|
||||
Scroll the cursor in the result set to a new position according
|
||||
to mode. This method is :ref:`coroutine <coroutine>`.
|
||||
|
||||
If mode is ``relative`` (default), value is taken as offset to the
|
||||
current position in the result set, if set to ``absolute``, value
|
||||
states an absolute target position. An IndexError should be raised in
|
||||
case a scroll operation would leave the result set. In this case,
|
||||
the cursor position is left undefined (ideal would be to
|
||||
not move the cursor at all).
|
||||
|
||||
.. note::
|
||||
|
||||
According to the :term:`DBAPI`, the exception raised for a cursor out
|
||||
of bound should have been :exc:`IndexError`. The best option is
|
||||
probably to catch both exceptions in your code::
|
||||
|
||||
try:
|
||||
await cur.scroll(1000 * 1000)
|
||||
except (ProgrammingError, IndexError), exc:
|
||||
deal_with_it(exc)
|
||||
|
||||
:param int value: move cursor to next position according to mode.
|
||||
:param str mode: scroll mode, possible modes: `relative` and `absolute`
|
||||
|
||||
|
||||
.. class:: DictCursor
|
||||
|
||||
A cursor which returns results as a dictionary. All methods and arguments
|
||||
same as :class:`Cursor`, see example::
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def test_example():
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='mysql', loop=loop)
|
||||
|
||||
# create dict cursor
|
||||
cursor = await conn.cursor(aiomysql.DictCursor)
|
||||
|
||||
# execute sql query
|
||||
await cursor.execute(
|
||||
"SELECT * from people where name='bob'")
|
||||
|
||||
# fetch all results
|
||||
r = await cursor.fetchone()
|
||||
print(r)
|
||||
# {'age': 20, 'DOB': datetime.datetime(1990, 2, 6, 23, 4, 56),
|
||||
# 'name': 'bob'}
|
||||
|
||||
loop.run_until_complete(test_example())
|
||||
|
||||
You can customize your dictionary, see example::
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
class AttrDict(dict):
|
||||
"""Dict that can get attribute by dot, and doesn't raise KeyError"""
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
class AttrDictCursor(aiomysql.DictCursor):
|
||||
dict_type = AttrDict
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def test_example():
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='mysql', loop=loop)
|
||||
|
||||
# create your dict cursor
|
||||
cursor = await conn.cursor(AttrDictCursor)
|
||||
|
||||
# execute sql query
|
||||
await cursor.execute(
|
||||
"SELECT * from people where name='bob'")
|
||||
|
||||
# fetch all results
|
||||
r = await cursor.fetchone()
|
||||
print(r)
|
||||
# {'age': 20, 'DOB': datetime.datetime(1990, 2, 6, 23, 4, 56),
|
||||
# 'name': 'bob'}
|
||||
print(r.age)
|
||||
# 20
|
||||
print(r.foo)
|
||||
# None
|
||||
|
||||
loop.run_until_complete(test_example())
|
||||
|
||||
|
||||
.. class:: SSCursor
|
||||
|
||||
Unbuffered Cursor, mainly useful for queries that return a lot of
|
||||
data, or for connections to remote servers over a slow network.
|
||||
|
||||
Instead of copying every row of data into a buffer, this will fetch
|
||||
rows as needed. The upside of this, is the client uses much less memory,
|
||||
and rows are returned much faster when traveling over a slow network,
|
||||
or if the result set is very big.
|
||||
|
||||
There are limitations, though. The MySQL protocol doesn't support
|
||||
returning the total number of rows, so the only way to tell how many rows
|
||||
there are is to iterate over every row returned. Also, it currently isn't
|
||||
possible to scroll backwards, as only the current row is held in memory.
|
||||
All methods are the same as in :class:`Cursor` but with different
|
||||
behaviour.
|
||||
|
||||
.. method:: fetchall()
|
||||
Same as :meth:`Cursor.fetchall` :ref:`coroutine <coroutine>`,
|
||||
useless for large queries, as all rows fetched one by one.
|
||||
|
||||
.. method:: fetchmany(size=None, mode='relative')
|
||||
Same as :meth:`Cursor.fetchall`, but each row fetched one by one.
|
||||
|
||||
.. method:: scroll(size=None)
|
||||
Same as :meth:`Cursor.scroll`, but move cursor on server side one by
|
||||
one. If you want to move 20 rows forward scroll will make 20 queries
|
||||
to move cursor. Currently only forward scrolling is supported.
|
||||
|
||||
|
||||
.. class:: SSDictCursor
|
||||
|
||||
An unbuffered cursor, which returns results as a dictionary.
|
||||
@@ -0,0 +1,38 @@
|
||||
Examples of aiomysql usage
|
||||
==========================
|
||||
|
||||
Below is a list of examples from `aiomysql/examples
|
||||
<https://github.com/aio-libs/aiomysql/tree/main/examples>`_
|
||||
|
||||
Every example is a correct tiny python program that demonstrates specific
|
||||
feature of library.
|
||||
|
||||
.. _aiomysql-examples-simple:
|
||||
|
||||
Low-level API
|
||||
-------------
|
||||
Basic example, fetch host and user information from internal table: user.
|
||||
|
||||
.. literalinclude:: ../examples/example.py
|
||||
|
||||
Example of stored procedure, which just increments input value.
|
||||
|
||||
.. literalinclude:: ../examples/example_callproc.py
|
||||
|
||||
Example of using `executemany` method:
|
||||
|
||||
.. literalinclude:: ../examples/example_executemany.py
|
||||
|
||||
Example of using transactions `rollback` and `commit` methods:
|
||||
|
||||
.. literalinclude:: ../examples/example_transaction.py
|
||||
|
||||
Example of using connection pool:
|
||||
|
||||
.. literalinclude:: ../examples/example_pool.py
|
||||
|
||||
|
||||
sqlalchemy usage
|
||||
----------------
|
||||
|
||||
.. literalinclude:: ../examples/example_simple_sa.py
|
||||
@@ -0,0 +1,58 @@
|
||||
.. _glossary:
|
||||
|
||||
|
||||
********
|
||||
Glossary
|
||||
********
|
||||
|
||||
.. if you add new entries, keep the alphabetical sorting!
|
||||
|
||||
.. glossary::
|
||||
|
||||
DBAPI
|
||||
|
||||
:pep:`249` -- Python Database API Specification v2.0
|
||||
|
||||
ipdb
|
||||
|
||||
ipdb exports functions to access the IPython debugger, which
|
||||
features tab completion, syntax highlighting, better tracebacks,
|
||||
better introspection with the same interface as the pdb module.
|
||||
|
||||
MySQL
|
||||
|
||||
A popular database server.
|
||||
|
||||
http://www.mysql.com/
|
||||
|
||||
pep8
|
||||
|
||||
Python style guide checker
|
||||
|
||||
*pep8* is a tool to check your Python code against some of the
|
||||
style conventions in :pep:`8` -- Style Guide for Python Code.
|
||||
|
||||
pyflakes
|
||||
|
||||
passive checker of Python programs
|
||||
|
||||
A simple program which checks Python source files for errors.
|
||||
|
||||
Pyflakes analyzes programs and detects various errors. It works
|
||||
by parsing the source file, not importing it, so it is safe to
|
||||
use on modules with side effects. It's also much faster.
|
||||
|
||||
https://pypi.python.org/pypi/pyflakes
|
||||
|
||||
PyMySQL
|
||||
|
||||
Pure-Python MySQL client library. The goal of PyMySQL is to be a drop-in
|
||||
replacement for MySQLdb and work on CPython, PyPy, IronPython and Jython.
|
||||
|
||||
https://github.com/PyMySQL/PyMySQL
|
||||
|
||||
sqlalchemy
|
||||
|
||||
The Python SQL Toolkit and Object Relational Mapper.
|
||||
|
||||
http://www.sqlalchemy.org/
|
||||
@@ -0,0 +1,144 @@
|
||||
.. _aiomysql-index:
|
||||
|
||||
.. aiomysql documentation master file, created by
|
||||
sphinx-quickstart on Sun Jun 11 16:24:33 2023.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to aiomysql's documentation!
|
||||
====================================
|
||||
|
||||
.. _GitHub: https://github.com/aio-libs/aiomysql
|
||||
.. _asyncio: http://docs.python.org/3.5/library/asyncio.html
|
||||
.. _aiopg: https://github.com/aio-libs/aiopg
|
||||
.. _Tornado-MySQL: https://github.com/PyMySQL/Tornado-MySQL
|
||||
.. _aio-libs: https://github.com/aio-libs
|
||||
|
||||
|
||||
**aiomysql** is a library for accessing a :term:`MySQL` database
|
||||
from the asyncio_ (PEP-3156/tulip) framework. It depends and reuses most parts
|
||||
of :term:`PyMySQL` . **aiomysql** tries to be like awesome aiopg_ library and preserve
|
||||
same api, look and feel.
|
||||
|
||||
Internally **aiomysql** is copy of PyMySQL, underlying io calls switched
|
||||
to async, basically ``await`` and ``async def coroutine`` added in
|
||||
proper places. :term:`sqlalchemy` support ported from aiopg_.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Implements *asyncio* :term:`DBAPI` *like* interface for
|
||||
:term:`MySQL`. It includes :ref:`aiomysql-connection`,
|
||||
:ref:`aiomysql-cursors` and :ref:`aiomysql-pool` objects.
|
||||
* Implements *optional* support for charming :term:`sqlalchemy`
|
||||
functional sql layer.
|
||||
|
||||
Basics
|
||||
------
|
||||
|
||||
**aiomysql** based on :term:`PyMySQL` , and provides same api, you just need
|
||||
to use ``await conn.f()`` instead of just call ``conn.f()`` for
|
||||
every method.
|
||||
|
||||
Properties are unchanged, so ``conn.prop`` is correct as well as
|
||||
``conn.prop = val``.
|
||||
|
||||
See example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
async def test_example():
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='', db='mysql',
|
||||
loop=loop)
|
||||
|
||||
cur = await conn.cursor()
|
||||
await cur.execute("SELECT Host,User FROM user")
|
||||
print(cur.description)
|
||||
r = await cur.fetchall()
|
||||
print(r)
|
||||
await cur.close()
|
||||
conn.close()
|
||||
|
||||
loop.run_until_complete(test_example())
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install aiomysql
|
||||
|
||||
.. note:: :mod:`aiomysql` requires :term:`PyMySQL` library.
|
||||
|
||||
|
||||
Also you probably want to use :mod:`aiomysql.sa`.
|
||||
|
||||
.. _aiomysql-install-sqlalchemy:
|
||||
|
||||
:mod:`aiomysql.sa` module is **optional** and requires
|
||||
:term:`sqlalchemy`. You can install *sqlalchemy* by running::
|
||||
|
||||
pip3 install sqlalchemy
|
||||
|
||||
Source code
|
||||
-----------
|
||||
|
||||
The project is hosted on GitHub_
|
||||
|
||||
Please feel free to file an issue on `bug tracker
|
||||
<https://github.com/aio-libs/aiomysql/issues>`_ if you have found a bug
|
||||
or have some suggestion for library improvement.
|
||||
|
||||
The library uses `GitHub Actions
|
||||
<https://github.com/aio-libs/aiomysql/actions>`_ for Continuous Integration
|
||||
and `Codecov <https://app.codecov.io/gh/aio-libs/aiomysql/branch/main>`_ for
|
||||
coverage reports.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
- Python 3.9+
|
||||
- :term:`PyMySQL`
|
||||
- aiomysql.sa requires :term:`sqlalchemy`.
|
||||
|
||||
|
||||
Authors and License
|
||||
-------------------
|
||||
|
||||
The ``aiomysql`` package is written by Nikolay Novik, :term:`PyMySQL` and
|
||||
aio-libs_ contributors. It's MIT licensed (same as PyMySQL).
|
||||
|
||||
Feel free to improve this package and send a pull request to GitHub_.
|
||||
|
||||
Contents:
|
||||
---------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:titlesonly:
|
||||
|
||||
connection
|
||||
cursors
|
||||
pool
|
||||
tutorial
|
||||
sa
|
||||
examples
|
||||
glossary
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -0,0 +1,146 @@
|
||||
.. _aiomysql-pool:
|
||||
|
||||
Pool
|
||||
====
|
||||
|
||||
The library provides *connection pool* as well as plain
|
||||
:class:`Connection` objects.
|
||||
|
||||
|
||||
The basic usage is::
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def go():
|
||||
pool = await aiomysql.create_pool(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='mysql', loop=loop, autocommit=False)
|
||||
|
||||
async with pool.acquire() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute("SELECT 10")
|
||||
# print(cur.description)
|
||||
(r,) = await cur.fetchone()
|
||||
assert r == 10
|
||||
pool.close()
|
||||
await pool.wait_closed()
|
||||
|
||||
loop.run_until_complete(go())
|
||||
|
||||
|
||||
.. function:: create_pool(minsize=1, maxsize=10, loop=None, **kwargs)
|
||||
|
||||
A :ref:`coroutine <coroutine>` that creates a pool of connections to
|
||||
:term:`MySQL` database.
|
||||
|
||||
:param int minsize: minimum sizes of the *pool*.
|
||||
:param int maxsize: maximum sizes of the *pool*.
|
||||
:param loop: is an optional *event loop* instance,
|
||||
:func:`asyncio.get_event_loop` is used if *loop* is not specified.
|
||||
:param bool echo: -- executed log SQL queryes (``False`` by default).
|
||||
:param kwargs: The function accepts all parameters that
|
||||
:func:`aiomysql.connect` does plus optional keyword-only parameters
|
||||
*loop*, *minsize*, *maxsize*.
|
||||
:param float pool_recycle: number of seconds after which connection is
|
||||
recycled, helps to deal with stale connections in pool, default
|
||||
value is -1, means recycling logic is disabled.
|
||||
:returns: :class:`Pool` instance.
|
||||
|
||||
|
||||
.. class:: Pool
|
||||
|
||||
A connection pool.
|
||||
|
||||
After creation pool has *minsize* free connections and can grow up
|
||||
to *maxsize* ones.
|
||||
|
||||
If *minsize* is ``0`` the pool doesn't creates any connection on startup.
|
||||
|
||||
If *maxsize* is ``0`` than size of pool is unlimited (but it
|
||||
recycles used connections of course).
|
||||
|
||||
The most important way to use it is getting connection in *with statement*::
|
||||
|
||||
async with pool.acquire() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
pass
|
||||
|
||||
|
||||
See also :meth:`Pool.acquire` and :meth:`Pool.release` for acquiring
|
||||
:class:`Connection` without *with statement*.
|
||||
|
||||
.. attribute:: echo
|
||||
|
||||
Return *echo mode* status. Log all executed queries to logger
|
||||
named ``aiomysql`` if ``True``
|
||||
|
||||
.. attribute:: minsize
|
||||
|
||||
A minimal size of the pool (*read-only*), ``1`` by default.
|
||||
|
||||
.. attribute:: maxsize
|
||||
|
||||
A maximal size of the pool (*read-only*), ``10`` by default.
|
||||
|
||||
.. attribute:: size
|
||||
|
||||
A current size of the pool (*readonly*). Includes used and free
|
||||
connections.
|
||||
|
||||
.. attribute:: freesize
|
||||
|
||||
A count of free connections in the pool (*readonly*).
|
||||
|
||||
.. method:: clear()
|
||||
|
||||
A :ref:`coroutine <coroutine>` that closes all *free* connections
|
||||
in the pool. At next connection acquiring at least :attr:`minsize` of
|
||||
them will be recreated.
|
||||
|
||||
.. method:: close()
|
||||
|
||||
Close pool.
|
||||
|
||||
Mark all pool connections to be closed on getting back to pool.
|
||||
Closed pool doesn't allow to acquire new connections.
|
||||
|
||||
If you want to wait for actual closing of acquired connection please
|
||||
call :meth:`wait_closed` after :meth:`close`.
|
||||
|
||||
.. warning:: The method is not a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: terminate()
|
||||
|
||||
Terminate pool.
|
||||
|
||||
Close pool with instantly closing all acquired connections also.
|
||||
|
||||
:meth:`wait_closed` should be called after :meth:`terminate` for
|
||||
waiting for actual finishing.
|
||||
|
||||
.. warning:: The method is not a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: wait_closed()
|
||||
|
||||
A :ref:`coroutine <coroutine>` that waits for releasing and
|
||||
closing all acquired connections.
|
||||
|
||||
Should be called after :meth:`close` for waiting for actual pool
|
||||
closing.
|
||||
|
||||
.. method:: acquire()
|
||||
|
||||
A :ref:`coroutine <coroutine>` that acquires a connection from
|
||||
*free pool*. Creates new connection if needed and :attr:`size`
|
||||
of pool is less than :attr:`maxsize`.
|
||||
|
||||
Returns a :class:`Connection` instance.
|
||||
|
||||
.. method:: release(conn)
|
||||
|
||||
Reverts connection *conn* to *free pool* for future recycling.
|
||||
|
||||
.. warning:: The method is not a :ref:`coroutine <coroutine>`.
|
||||
@@ -0,0 +1,632 @@
|
||||
.. _aiomysql-sa:
|
||||
|
||||
:mod:`aiomysql.sa` --- support for SQLAlchemy functional SQL layer
|
||||
==================================================================
|
||||
|
||||
.. module:: aiomysql.sa
|
||||
:synopsis: support for SQLAlchemy functional SQL layer
|
||||
.. currentmodule:: aiomysql.sa
|
||||
|
||||
|
||||
Intro
|
||||
-----
|
||||
.. note:: :term:`sqlalchemy` support ported from aiopg_, so api should be
|
||||
very familiar for aiopg_ user.
|
||||
|
||||
While :ref:`core API <aiomysql-index>` provides a core support for
|
||||
access to :term:`MySQL` database, manipulations with raw SQL strings
|
||||
too annoying.
|
||||
|
||||
Fortunately we can use excellent :ref:`aiomysql <aiomysql-index>` as **SQL query builder**.
|
||||
|
||||
|
||||
Example::
|
||||
|
||||
import asyncio
|
||||
import sqlalchemy as sa
|
||||
|
||||
from aiomysql.sa import create_engine
|
||||
|
||||
|
||||
metadata = sa.MetaData()
|
||||
|
||||
tbl = sa.Table(
|
||||
"tbl",
|
||||
metadata,
|
||||
sa.Column("id", sa.Integer, primary_key=True),
|
||||
sa.Column("val", sa.String(255)),
|
||||
)
|
||||
|
||||
|
||||
async def go():
|
||||
engine = await create_engine(
|
||||
user="root",
|
||||
db="test_pymysql",
|
||||
host="127.0.0.1",
|
||||
password="",
|
||||
)
|
||||
|
||||
async with engine.acquire() as conn:
|
||||
async with conn.begin() as transaction:
|
||||
await conn.execute(tbl.insert().values(val="abc"))
|
||||
await transaction.commit()
|
||||
|
||||
res = await conn.execute(tbl.select())
|
||||
async for row in res:
|
||||
print(row.id, row.val)
|
||||
|
||||
engine.close()
|
||||
await engine.wait_closed()
|
||||
|
||||
|
||||
asyncio.run(go())
|
||||
|
||||
|
||||
So you can execute SQL query built by
|
||||
``tbl.insert().values(val='abc')`` or ``tbl.select()`` expressions.
|
||||
|
||||
:term:`sqlalchemy` has rich and very powerful set of SQL construction
|
||||
functions, please read :ref:`tutorial <aiomysql-index>` for full list
|
||||
of available operations.
|
||||
|
||||
Also we provide SQL transactions support. Please take a look on
|
||||
:meth:`SAConnection.begin` method and family.
|
||||
|
||||
|
||||
.. _aiopg: https://github.com/aio-libs/aiopg
|
||||
|
||||
Engine
|
||||
------
|
||||
|
||||
.. function:: create_engine(*, minsize=1, maxsize=10, loop=None, \
|
||||
dialect=dialect, **kwargs)
|
||||
|
||||
A :ref:`coroutine <coroutine>` for :class:`Engine` creation.
|
||||
|
||||
Returns :class:`Engine` instance with embedded connection pool.
|
||||
|
||||
The pool has *minsize* opened connections to :term:`MySQL` server.
|
||||
|
||||
At *kwargs* function accepts all parameters that
|
||||
:func:`aiomysql.connect` does.
|
||||
|
||||
|
||||
.. data:: dialect
|
||||
|
||||
An instance of :term:`SQLAlchemy` dialect set up for :term:`pymysql` usage.
|
||||
|
||||
An :class:`sqlalchemy.engine.interfaces.Dialect` instance.
|
||||
|
||||
.. seealso:: :mod:`sqlalchemy.dialects.mysql.pymysql`
|
||||
PyMySQL dialect.
|
||||
|
||||
|
||||
.. class:: Engine
|
||||
|
||||
Connects a :class:`aiomysql.Pool` and
|
||||
:class:`sqlalchemy.engine.interfaces.Dialect` together to provide a
|
||||
source of database connectivity and behavior.
|
||||
|
||||
An :class:`Engine` object is instantiated publicly using the
|
||||
:func:`create_engine` coroutine.
|
||||
|
||||
|
||||
.. attribute:: dialect
|
||||
|
||||
A :class:`sqlalchemy.engine.interfaces.Dialect` for the engine,
|
||||
readonly property.
|
||||
|
||||
.. attribute:: name
|
||||
|
||||
A name of the dialect, readonly property.
|
||||
|
||||
.. attribute:: driver
|
||||
|
||||
A driver of the dialect, readonly property.
|
||||
|
||||
.. attribute:: minsize
|
||||
|
||||
A minimal size of the pool (*read-only*), ``1`` by default.
|
||||
|
||||
.. attribute:: maxsize
|
||||
|
||||
A maximal size of the pool (*read-only*), ``10`` by default.
|
||||
|
||||
.. attribute:: size
|
||||
|
||||
A current size of the pool (*readonly*). Includes used and free
|
||||
connections.
|
||||
|
||||
.. attribute:: freesize
|
||||
|
||||
A count of free connections in the pool (*readonly*).
|
||||
|
||||
.. method:: close()
|
||||
|
||||
Close engine.
|
||||
|
||||
Mark all engine connections to be closed on getting back to engine.
|
||||
Closed engine doesn't allow to acquire new connections.
|
||||
|
||||
If you want to wait for actual closing of acquired connection please
|
||||
call :meth:`wait_closed` after :meth:`close`.
|
||||
|
||||
.. warning:: The method is not a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: terminate()
|
||||
|
||||
Terminate engine.
|
||||
|
||||
Close engine's pool with instantly closing all acquired connections
|
||||
also.
|
||||
|
||||
:meth:`wait_closed` should be called after :meth:`terminate` for
|
||||
waiting for actual finishing.
|
||||
|
||||
.. warning:: The method is not a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: wait_closed()
|
||||
|
||||
A :ref:`coroutine <coroutine>` that waits for releasing and
|
||||
closing all acquired connections.
|
||||
|
||||
Should be called after :meth:`close` for waiting for actual engine
|
||||
closing.
|
||||
|
||||
.. method:: acquire()
|
||||
|
||||
Get a connection from pool.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
Returns a :class:`SAConnection` instance.
|
||||
|
||||
.. method:: release()
|
||||
|
||||
Revert back connection *conn* to pool.
|
||||
|
||||
.. warning:: The method is not a :ref:`coroutine <coroutine>`.
|
||||
|
||||
Connection
|
||||
----------
|
||||
|
||||
.. class:: SAConnection
|
||||
|
||||
A wrapper for :class:`aiomysql.Connection` instance.
|
||||
|
||||
The class provides methods for executing *SQL queries* and working with
|
||||
*SQL transactions*.
|
||||
|
||||
.. method:: execute(query, *multiparams, **params)
|
||||
|
||||
Executes a *SQL* *query* with optional parameters.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
:param query: a SQL query string or any :term:`sqlalchemy`
|
||||
expression (see :ref:`aiomysql core <aiomysql-index>`)
|
||||
|
||||
:param \*multiparams/\**params: represent bound parameter values
|
||||
to be used in the execution. Typically, the format is either a
|
||||
dictionary passed to \*multiparams::
|
||||
|
||||
await conn.execute(
|
||||
table.insert(),
|
||||
{"id":1, "value":"v1"}
|
||||
)
|
||||
|
||||
...or individual key/values interpreted by \**params::
|
||||
|
||||
await conn.execute(
|
||||
table.insert(), id=1, value="v1"
|
||||
)
|
||||
|
||||
In the case that a plain SQL string is passed, a tuple or
|
||||
individual values in \*multiparams may be passed::
|
||||
|
||||
await conn.execute(
|
||||
"INSERT INTO table (id, value) VALUES (%d, %s)",
|
||||
(1, "v1")
|
||||
)
|
||||
|
||||
await conn.execute(
|
||||
"INSERT INTO table (id, value) VALUES (%s, %s)",
|
||||
1, "v1"
|
||||
)
|
||||
|
||||
:returns: :class:`ResultProxy` instance with results of SQL
|
||||
query execution.
|
||||
|
||||
.. method:: scalar(query, *multiparams, **params)
|
||||
|
||||
Executes a *SQL* *query* and returns a scalar value.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. seealso:: :meth:`SAConnection.execute` and :meth:`ResultProxy.scalar`.
|
||||
|
||||
.. attribute:: closed
|
||||
|
||||
The readonly property that returns ``True`` if connections is closed.
|
||||
|
||||
.. method:: begin()
|
||||
|
||||
Begin a transaction and return a transaction handle.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
The returned object is an instance of :class:`.Transaction`.
|
||||
This object represents the "scope" of the transaction,
|
||||
which completes when either the :meth:`.Transaction.rollback`
|
||||
or :meth:`.Transaction.commit` method is called.
|
||||
|
||||
Nested calls to :meth:`.begin` on the same :class:`.SAConnection`
|
||||
will return new :class:`.Transaction` objects that represent
|
||||
an emulated transaction within the scope of the enclosing
|
||||
transaction, that is::
|
||||
|
||||
trans = await conn.begin() # outermost transaction
|
||||
trans2 = await conn.begin() # "inner"
|
||||
await trans2.commit() # does nothing
|
||||
await trans.commit() # actually commits
|
||||
|
||||
Calls to :meth:`.Transaction.commit` only have an effect
|
||||
when invoked via the outermost :class:`.Transaction` object, though the
|
||||
:meth:`.Transaction.rollback` method of any of the
|
||||
:class:`.Transaction` objects will roll back the
|
||||
transaction.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.SAConnection.begin_nested` - use a SAVEPOINT
|
||||
|
||||
:meth:`.SAConnection.begin_twophase` - use a two phase (XA)
|
||||
transaction
|
||||
|
||||
.. method:: begin_nested()
|
||||
|
||||
Begin a nested transaction and return a transaction handle.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
The returned object is an instance of :class:`.NestedTransaction`.
|
||||
|
||||
Any transaction in the hierarchy may ``commit`` and
|
||||
``rollback``, however the outermost transaction still controls
|
||||
the overall ``commit`` or ``rollback`` of the transaction of a
|
||||
whole. It utilizes SAVEPOINT facility of :term:`MySQL` server.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.SAConnection.begin`, :meth:`.SAConnection.begin_twophase`.
|
||||
|
||||
.. method:: begin_twophase(xid=None)
|
||||
|
||||
Begin a two-phase or XA transaction and return a transaction
|
||||
handle.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
The returned object is an instance of
|
||||
:class:`.TwoPhaseTransaction`, which in addition to the methods
|
||||
provided by :class:`.Transaction`, also provides a
|
||||
:meth:`~.TwoPhaseTransaction.prepare` method.
|
||||
|
||||
:param xid: the two phase transaction id. If not supplied, a
|
||||
random id will be generated.
|
||||
|
||||
.. seealso::
|
||||
:meth:`.SAConnection.begin`, :meth:`.SAConnection.begin_twophase`.
|
||||
|
||||
.. method:: recover_twophase()
|
||||
|
||||
Return a list of prepared twophase transaction ids.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: rollback_prepared(xid)
|
||||
|
||||
Rollback prepared twophase transaction *xid*.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: commit_prepared(xid)
|
||||
|
||||
Commit prepared twophase transaction *xid*.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. attribute:: in_transaction
|
||||
|
||||
The readonly property that returns ``True`` if a transaction is
|
||||
in progress.
|
||||
|
||||
.. method:: close()
|
||||
|
||||
Close this :class:`SAConnection`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
This results in a release of the underlying database
|
||||
resources, that is, the :class:`aiomysql.Connection` referenced
|
||||
internally. The :class:`aiomysql.Connection` is typically restored
|
||||
back to the connection-holding :class:`aiomysql.Pool` referenced
|
||||
by the :class:`.Engine` that produced this
|
||||
:class:`SAConnection`. Any transactional state present on
|
||||
the :class:`aiomysql.Connection` is also unconditionally released via
|
||||
calling :meth:`Transaction.rollback` method.
|
||||
|
||||
After :meth:`~.SAConnection.close` is called, the
|
||||
:class:`.SAConnection` is permanently in a closed state,
|
||||
and will allow no further operations.
|
||||
|
||||
ResultProxy
|
||||
-----------
|
||||
|
||||
.. class:: ResultProxy
|
||||
|
||||
Wraps a *DB-API like* :class:`Cursor` object to provide easier
|
||||
access to row columns.
|
||||
|
||||
Individual columns may be accessed by their integer position,
|
||||
case-sensitive column name, or by :class:`sqlalchemy.schema.Column``
|
||||
object. e.g.::
|
||||
|
||||
async for row in conn.execute(...):
|
||||
col1 = row[0] # access via integer position
|
||||
col2 = row['col2'] # access via name
|
||||
col3 = row[mytable.c.mycol] # access via Column object.
|
||||
|
||||
:class:`ResultProxy` also handles post-processing of result column
|
||||
data using :class:`sqlalchemy.types.TypeEngine` objects, which are
|
||||
referenced from the originating SQL statement that produced this
|
||||
result set.
|
||||
|
||||
.. attribute:: dialect
|
||||
|
||||
The readonly property that returns
|
||||
:class:`sqlalchemy.engine.interfaces.Dialect` dialect
|
||||
for the :class:`ResultProxy` instance.
|
||||
|
||||
.. seealso:: :data:`dialect` global data.
|
||||
|
||||
.. method:: keys()
|
||||
|
||||
Return the current set of string keys for rows.
|
||||
|
||||
.. attribute:: rowcount
|
||||
|
||||
The readonly property that returns the 'rowcount' for this result.
|
||||
|
||||
The 'rowcount' reports the number of rows *matched*
|
||||
by the WHERE criterion of an UPDATE or DELETE statement.
|
||||
|
||||
.. note::
|
||||
|
||||
Notes regarding :attr:`ResultProxy.rowcount`:
|
||||
|
||||
* This attribute returns the number of rows *matched*,
|
||||
which is not necessarily the same as the number of rows
|
||||
that were actually *modified* - an UPDATE statement, for example,
|
||||
may have no net change on a given row if the SET values
|
||||
given are the same as those present in the row already.
|
||||
Such a row would be matched but not modified.
|
||||
* :attr:`ResultProxy.rowcount` is *only* useful in conjunction
|
||||
with an UPDATE or DELETE statement. Contrary to what the Python
|
||||
DBAPI says, it does *not* return the
|
||||
number of rows available from the results of a SELECT statement
|
||||
as DBAPIs cannot support this functionality when rows are
|
||||
unbuffered.
|
||||
* Statements that use RETURNING does not return a correct
|
||||
rowcount.
|
||||
|
||||
.. attribute:: lastrowid
|
||||
|
||||
Returns the 'lastrowid' accessor on the DBAPI cursor.
|
||||
|
||||
value generated for an *AUTO_INCREMENT* column by the previous INSERT
|
||||
or UPDATE statement or None when there is no such value available. For
|
||||
example, if you perform an *INSERT* into a table that contains an
|
||||
AUTO_INCREMENT column, `lastrowid` returns the *AUTO_INCREMENT* value
|
||||
for the new row.
|
||||
|
||||
.. attribute:: returns_rows
|
||||
|
||||
A readonly property that returns ``True`` if this
|
||||
:class:`ResultProxy` returns rows.
|
||||
|
||||
I.e. if it is legal to call the methods
|
||||
:meth:`ResultProxy.fetchone`,
|
||||
:meth:`ResultProxy.fetchmany`,
|
||||
:meth:`ResultProxy.fetchall`.
|
||||
|
||||
.. attribute:: closed
|
||||
|
||||
Return ``True`` if this :class:`ResultProxy` is closed (no
|
||||
pending rows in underlying cursor).
|
||||
|
||||
.. method:: close()
|
||||
|
||||
Close this :class:`ResultProxy`.
|
||||
|
||||
Closes the underlying :class:`aiomysql.Cursor` corresponding to the
|
||||
execution.
|
||||
|
||||
Note that any data cached within this :class:`ResultProxy` is
|
||||
still available. For some types of results, this may include
|
||||
buffered rows.
|
||||
|
||||
This method is called automatically when:
|
||||
|
||||
* all result rows are exhausted using the fetchXXX() methods.
|
||||
* cursor.description is None.
|
||||
|
||||
.. method:: fetchall()
|
||||
|
||||
Fetch all rows, just like :meth:`aiomysql.Cursor.fetchall`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
The connection is closed after the call.
|
||||
|
||||
Returns a list of :class:`RowProxy`.
|
||||
|
||||
.. method:: fetchone()
|
||||
|
||||
Fetch one row, just like :meth:`aiomysql.Cursor.fetchone`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
If a row is present, the cursor remains open after this is called.
|
||||
|
||||
Else the cursor is automatically closed and ``None`` is returned.
|
||||
|
||||
Returns an :class:`RowProxy` instance or ``None``.
|
||||
|
||||
.. method:: fetchmany(size=None)
|
||||
|
||||
Fetch many rows, just like :meth:`aiomysql.Cursor.fetchmany`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
If rows are present, the cursor remains open after this is called.
|
||||
|
||||
Else the cursor is automatically closed and an empty list is returned.
|
||||
|
||||
Returns a list of :class:`RowProxy`.
|
||||
|
||||
.. method:: first()
|
||||
|
||||
Fetch the first row and then close the result set unconditionally.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
Returns ``None`` if no row is present or an :class:`RowProxy` instance.
|
||||
|
||||
.. method:: scalar()
|
||||
|
||||
Fetch the first column of the first row, and close the result set.
|
||||
|
||||
Returns ``None`` if no row is present or an :class:`RowProxy` instance.
|
||||
|
||||
|
||||
.. class:: RowProxy
|
||||
|
||||
A :class:`collections.abc.Mapping` for representing a row in query result.
|
||||
|
||||
Keys are column names, values are result values.
|
||||
|
||||
Individual columns may be accessed by their integer position,
|
||||
case-sensitive column name, or by :class:`sqlalchemy.schema.Column``
|
||||
object.
|
||||
|
||||
Has overloaded operators ``__eq__`` and ``__ne__`` for comparing two rows.
|
||||
|
||||
The :class:`RowProxy` is *not hashable*.
|
||||
|
||||
..method:: as_tuple()
|
||||
|
||||
Return a tuple with values from :meth:`RowProxy.values`.
|
||||
|
||||
Transaction objects
|
||||
-------------------
|
||||
|
||||
.. class:: Transaction
|
||||
|
||||
Represent a database transaction in progress.
|
||||
|
||||
The :class:`Transaction` object is procured by
|
||||
calling the :meth:`SAConnection.begin` method of
|
||||
:class:`SAConnection`::
|
||||
|
||||
async with engine.acquire() as conn:
|
||||
trans = await conn.begin()
|
||||
try:
|
||||
await conn.execute("insert into x (a, b) values (1, 2)")
|
||||
except Exception:
|
||||
await trans.rollback()
|
||||
else:
|
||||
await trans.commit()
|
||||
|
||||
The object provides :meth:`.rollback` and :meth:`.commit`
|
||||
methods in order to control transaction boundaries.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`SAConnection.begin`, :meth:`SAConnection.begin_twophase`,
|
||||
:meth:`SAConnection.begin_nested`.
|
||||
|
||||
.. attribute:: is_active
|
||||
|
||||
A readonly property that returns ``True`` if a transaction is active.
|
||||
|
||||
.. attribute:: connection
|
||||
|
||||
A readonly property that returns :class:`SAConnection` for transaction.
|
||||
|
||||
.. method:: close()
|
||||
|
||||
Close this :class:`Transaction`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
If this transaction is the base transaction in a begin/commit
|
||||
nesting, the transaction will :meth:`Transaction.rollback`.
|
||||
Otherwise, the method returns.
|
||||
|
||||
This is used to cancel a :class:`Transaction` without affecting
|
||||
the scope of an enclosing transaction.
|
||||
|
||||
.. method:: rollback()
|
||||
|
||||
Roll back this :class:`Transaction`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
.. method:: commit()
|
||||
|
||||
Commit this :class:`Transaction`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
|
||||
.. class:: NestedTransaction
|
||||
|
||||
Represent a 'nested', or SAVEPOINT transaction.
|
||||
|
||||
A new :class:`NestedTransaction` object may be procured
|
||||
using the :meth:`SAConnection.begin_nested` method.
|
||||
|
||||
The interface is the same as that of :class:`Transaction`.
|
||||
|
||||
.. seealso:: `SAVEPOINT, ROLLBACK TO SAVEPOINT, and RELEASE SAVEPOINT`__
|
||||
on :term:`MySQL`:
|
||||
|
||||
.. __: https://dev.mysql.com/doc/refman/8.4/en/savepoint.html
|
||||
|
||||
|
||||
.. class:: TwoPhaseTransaction
|
||||
|
||||
Represent a two-phase transaction.
|
||||
|
||||
A new :class:`TwoPhaseTransaction` object may be procured
|
||||
using the :meth:`SAConnection.begin_twophase` method.
|
||||
|
||||
The interface is the same as that of :class:`Transaction`
|
||||
with the addition of the :meth:`TwoPhaseTransaction.prepare` method.
|
||||
|
||||
.. attribute:: xid
|
||||
|
||||
A readonly property that returns twophase transaction id.
|
||||
|
||||
.. method:: prepare()
|
||||
|
||||
Prepare this :class:`TwoPhaseTransaction`.
|
||||
|
||||
This method is a :ref:`coroutine <coroutine>`.
|
||||
|
||||
After a `PREPARE`, the transaction can be committed.
|
||||
|
||||
.. seealso:: :term:`MySQL` commands for two phase transactions:
|
||||
|
||||
https://dev.mysql.com/doc/refman/8.4/en/xa-statements.html
|
||||
@@ -0,0 +1,146 @@
|
||||
.. _aiomysql-tutorial:
|
||||
|
||||
Tutorial
|
||||
========
|
||||
|
||||
Python database access modules all have similar interfaces, described by the
|
||||
:term:`DBAPI`. Most relational databases use the same synchronous interface,
|
||||
*aiomysql* tries to provide same api you just need
|
||||
to use ``await conn.f()`` instead of just call ``conn.f()`` for
|
||||
every method.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install aiomysql
|
||||
|
||||
.. note:: :mod:`aiomysql` requires :term:`PyMySQL` library.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Lets start from basic example::
|
||||
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def test_example():
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='', db='mysql',
|
||||
loop=loop)
|
||||
|
||||
cur = await conn.cursor()
|
||||
await cur.execute("SELECT Host,User FROM user")
|
||||
print(cur.description)
|
||||
r = await cur.fetchall()
|
||||
print(r)
|
||||
await cur.close()
|
||||
conn.close()
|
||||
|
||||
loop.run_until_complete(test_example())
|
||||
|
||||
|
||||
Connection is established by invoking the :func:`connect()` coroutine,
|
||||
arguments list are keyword arguments, almost same as in :term:`PyMySQL`
|
||||
corresponding method. Example makes connection to :term:`MySQL` server on
|
||||
local host to access `mysql` database with user name `root`' and empty password.
|
||||
|
||||
If :func:`connect()` coroutine succeeds, it returns a :class:`Connection`
|
||||
instance as the basis for further interaction with :term:`MySQL`.
|
||||
|
||||
After the connection object has been obtained, code in example invokes
|
||||
:meth:`Connection.cursor()` coroutine method to create a cursor object for
|
||||
processing statements. Example uses cursor to issue a
|
||||
``SELECT Host,User FROM user;`` statement, which returns a list of `host` and
|
||||
`user` from :term:`MySQL` system table ``user``::
|
||||
|
||||
cur = await conn.cursor()
|
||||
await cur.execute("SELECT Host,User FROM user")
|
||||
print(cur.description)
|
||||
r = await cur.fetchall()
|
||||
|
||||
The cursor object's :meth:`Cursor.execute()` method sends the query the server
|
||||
and :meth:`Cursor.fetchall()` retrieves rows.
|
||||
|
||||
Finally, the script invokes :meth:`Cursor.close()` coroutine and
|
||||
connection object's :meth:`Connection.close()` method to disconnect
|
||||
from the server::
|
||||
|
||||
await cur.close()
|
||||
conn.close()
|
||||
|
||||
After that, ``conn`` becomes invalid and should not be used to access the
|
||||
server.
|
||||
|
||||
Inserting Data
|
||||
--------------
|
||||
|
||||
Let's take basic example of :meth:`Cursor.execute` method::
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
|
||||
async def test_example_execute(loop):
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='test_pymysql', loop=loop)
|
||||
|
||||
cur = await conn.cursor()
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute("DROP TABLE IF EXISTS music_style;")
|
||||
await cur.execute("""CREATE TABLE music_style
|
||||
(id INT,
|
||||
name VARCHAR(255),
|
||||
PRIMARY KEY (id));""")
|
||||
await conn.commit()
|
||||
|
||||
# insert 3 rows one by one
|
||||
await cur.execute("INSERT INTO music_style VALUES(1,'heavy metal')")
|
||||
await cur.execute("INSERT INTO music_style VALUES(2,'death metal');")
|
||||
await cur.execute("INSERT INTO music_style VALUES(3,'power metal');")
|
||||
await conn.commit()
|
||||
|
||||
conn.close()
|
||||
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(test_example_execute(loop))
|
||||
|
||||
Please note that you need to manually call :func:`commit()` bound to your :class:`Connection` object, because by default it's set to ``False`` or in :meth:`aiomysql.connect()` you can transfer addition keyword argument ``autocommit=True``.
|
||||
|
||||
Example with ``autocommit=True``::
|
||||
|
||||
import asyncio
|
||||
import aiomysql
|
||||
|
||||
|
||||
async def test_example_execute(loop):
|
||||
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
|
||||
user='root', password='',
|
||||
db='test_pymysql', loop=loop,
|
||||
autocommit=True)
|
||||
|
||||
cur = await conn.cursor()
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute("DROP TABLE IF EXISTS music_style;")
|
||||
await cur.execute("""CREATE TABLE music_style
|
||||
(id INT,
|
||||
name VARCHAR(255),
|
||||
PRIMARY KEY (id));""")
|
||||
|
||||
# insert 3 rows one by one
|
||||
await cur.execute("INSERT INTO music_style VALUES(1,'heavy metal')")
|
||||
await cur.execute("INSERT INTO music_style VALUES(2,'death metal');")
|
||||
await cur.execute("INSERT INTO music_style VALUES(3,'power metal');")
|
||||
|
||||
conn.close()
|
||||
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(test_example_execute(loop))
|
||||
Reference in New Issue
Block a user