aio-scrapy 2.1.4__py3-none-any.whl → 2.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {aio_scrapy-2.1.4.dist-info → aio_scrapy-2.1.7.dist-info}/LICENSE +1 -1
  2. aio_scrapy-2.1.7.dist-info/METADATA +147 -0
  3. aio_scrapy-2.1.7.dist-info/RECORD +134 -0
  4. {aio_scrapy-2.1.4.dist-info → aio_scrapy-2.1.7.dist-info}/WHEEL +1 -1
  5. aioscrapy/VERSION +1 -1
  6. aioscrapy/cmdline.py +438 -5
  7. aioscrapy/core/downloader/__init__.py +522 -17
  8. aioscrapy/core/downloader/handlers/__init__.py +187 -5
  9. aioscrapy/core/downloader/handlers/aiohttp.py +190 -6
  10. aioscrapy/core/downloader/handlers/curl_cffi.py +126 -5
  11. aioscrapy/core/downloader/handlers/httpx.py +135 -5
  12. aioscrapy/core/downloader/handlers/pyhttpx.py +137 -5
  13. aioscrapy/core/downloader/handlers/requests.py +120 -2
  14. aioscrapy/core/downloader/handlers/webdriver/__init__.py +2 -0
  15. aioscrapy/core/downloader/handlers/webdriver/drissionpage.py +493 -0
  16. aioscrapy/core/downloader/handlers/webdriver/driverpool.py +234 -0
  17. aioscrapy/core/downloader/handlers/webdriver/playwright.py +498 -0
  18. aioscrapy/core/engine.py +381 -20
  19. aioscrapy/core/scheduler.py +350 -36
  20. aioscrapy/core/scraper.py +509 -33
  21. aioscrapy/crawler.py +392 -10
  22. aioscrapy/db/__init__.py +149 -0
  23. aioscrapy/db/absmanager.py +212 -6
  24. aioscrapy/db/aiomongo.py +292 -10
  25. aioscrapy/db/aiomysql.py +363 -10
  26. aioscrapy/db/aiopg.py +299 -2
  27. aioscrapy/db/aiorabbitmq.py +444 -4
  28. aioscrapy/db/aioredis.py +260 -11
  29. aioscrapy/dupefilters/__init__.py +110 -5
  30. aioscrapy/dupefilters/disk.py +124 -2
  31. aioscrapy/dupefilters/redis.py +598 -32
  32. aioscrapy/exceptions.py +151 -13
  33. aioscrapy/http/__init__.py +1 -1
  34. aioscrapy/http/headers.py +237 -3
  35. aioscrapy/http/request/__init__.py +257 -11
  36. aioscrapy/http/request/form.py +83 -3
  37. aioscrapy/http/request/json_request.py +121 -9
  38. aioscrapy/http/response/__init__.py +306 -33
  39. aioscrapy/http/response/html.py +42 -3
  40. aioscrapy/http/response/text.py +496 -49
  41. aioscrapy/http/response/web_driver.py +144 -0
  42. aioscrapy/http/response/xml.py +45 -3
  43. aioscrapy/libs/downloader/defaultheaders.py +66 -2
  44. aioscrapy/libs/downloader/downloadtimeout.py +91 -2
  45. aioscrapy/libs/downloader/ja3fingerprint.py +95 -2
  46. aioscrapy/libs/downloader/retry.py +192 -6
  47. aioscrapy/libs/downloader/stats.py +142 -0
  48. aioscrapy/libs/downloader/useragent.py +93 -2
  49. aioscrapy/libs/extensions/closespider.py +166 -4
  50. aioscrapy/libs/extensions/corestats.py +151 -1
  51. aioscrapy/libs/extensions/logstats.py +145 -1
  52. aioscrapy/libs/extensions/metric.py +370 -1
  53. aioscrapy/libs/extensions/throttle.py +235 -1
  54. aioscrapy/libs/pipelines/__init__.py +345 -2
  55. aioscrapy/libs/pipelines/csv.py +242 -0
  56. aioscrapy/libs/pipelines/excel.py +545 -0
  57. aioscrapy/libs/pipelines/mongo.py +132 -0
  58. aioscrapy/libs/pipelines/mysql.py +67 -0
  59. aioscrapy/libs/pipelines/pg.py +67 -0
  60. aioscrapy/libs/spider/depth.py +141 -3
  61. aioscrapy/libs/spider/httperror.py +144 -4
  62. aioscrapy/libs/spider/offsite.py +202 -2
  63. aioscrapy/libs/spider/referer.py +396 -21
  64. aioscrapy/libs/spider/urllength.py +97 -1
  65. aioscrapy/link.py +115 -8
  66. aioscrapy/logformatter.py +199 -8
  67. aioscrapy/middleware/absmanager.py +328 -2
  68. aioscrapy/middleware/downloader.py +218 -0
  69. aioscrapy/middleware/extension.py +50 -1
  70. aioscrapy/middleware/itempipeline.py +96 -0
  71. aioscrapy/middleware/spider.py +360 -7
  72. aioscrapy/process.py +200 -0
  73. aioscrapy/proxy/__init__.py +142 -3
  74. aioscrapy/proxy/redis.py +136 -2
  75. aioscrapy/queue/__init__.py +168 -16
  76. aioscrapy/scrapyd/runner.py +124 -3
  77. aioscrapy/serializer.py +182 -2
  78. aioscrapy/settings/__init__.py +610 -128
  79. aioscrapy/settings/default_settings.py +314 -14
  80. aioscrapy/signalmanager.py +151 -20
  81. aioscrapy/signals.py +183 -1
  82. aioscrapy/spiderloader.py +165 -12
  83. aioscrapy/spiders/__init__.py +233 -6
  84. aioscrapy/statscollectors.py +312 -1
  85. aioscrapy/utils/conf.py +345 -17
  86. aioscrapy/utils/curl.py +168 -16
  87. aioscrapy/utils/decorators.py +76 -6
  88. aioscrapy/utils/deprecate.py +212 -19
  89. aioscrapy/utils/httpobj.py +55 -3
  90. aioscrapy/utils/log.py +79 -0
  91. aioscrapy/utils/misc.py +189 -21
  92. aioscrapy/utils/ossignal.py +67 -5
  93. aioscrapy/utils/project.py +165 -3
  94. aioscrapy/utils/python.py +254 -44
  95. aioscrapy/utils/reqser.py +75 -1
  96. aioscrapy/utils/request.py +173 -12
  97. aioscrapy/utils/response.py +91 -6
  98. aioscrapy/utils/signal.py +196 -14
  99. aioscrapy/utils/spider.py +51 -4
  100. aioscrapy/utils/template.py +93 -6
  101. aioscrapy/utils/tools.py +191 -17
  102. aioscrapy/utils/trackref.py +198 -12
  103. aioscrapy/utils/url.py +341 -36
  104. aio_scrapy-2.1.4.dist-info/METADATA +0 -239
  105. aio_scrapy-2.1.4.dist-info/RECORD +0 -133
  106. aioscrapy/core/downloader/handlers/playwright/__init__.py +0 -115
  107. aioscrapy/core/downloader/handlers/playwright/driverpool.py +0 -59
  108. aioscrapy/core/downloader/handlers/playwright/webdriver.py +0 -96
  109. aioscrapy/http/response/playwright.py +0 -36
  110. aioscrapy/libs/pipelines/execl.py +0 -169
  111. {aio_scrapy-2.1.4.dist-info → aio_scrapy-2.1.7.dist-info}/entry_points.txt +0 -0
  112. {aio_scrapy-2.1.4.dist-info → aio_scrapy-2.1.7.dist-info}/top_level.txt +0 -0
aioscrapy/db/aiomysql.py CHANGED
@@ -1,3 +1,14 @@
1
+ """
2
+ MySQL connection pool manager for aioscrapy.
3
+ aioscrapy的MySQL连接池管理器。
4
+
5
+ This module provides classes for managing MySQL connection pools in aioscrapy.
6
+ It includes a pool manager for creating and managing MySQL connections, and an executor
7
+ for convenient execution of SQL queries.
8
+ 此模块提供了在aioscrapy中管理MySQL连接池的类。
9
+ 它包括一个用于创建和管理MySQL连接的池管理器,以及一个用于方便执行SQL查询的执行器。
10
+ """
11
+
1
12
  import socket
2
13
  from contextlib import asynccontextmanager
3
14
 
@@ -8,92 +19,407 @@ from aioscrapy.db.absmanager import AbsDBPoolManager
8
19
 
9
20
 
10
21
  class MysqlExecutor:
22
+ """
23
+ Executor for MySQL queries.
24
+ MySQL查询的执行器。
25
+
26
+ This class provides a convenient way to execute SQL queries on a specific
27
+ MySQL connection pool. It offers methods for inserting data, executing queries,
28
+ and fetching results.
29
+ 此类提供了一种在特定MySQL连接池上执行SQL查询的便捷方式。
30
+ 它提供了插入数据、执行查询和获取结果的方法。
31
+ """
32
+
11
33
  def __init__(self, alias: str, pool_manager: "AioMysqlPoolManager"):
34
+ """
35
+ Initialize a MysqlExecutor.
36
+ 初始化MysqlExecutor。
37
+
38
+ Args:
39
+ alias: The alias of the MySQL connection pool to use.
40
+ 要使用的MySQL连接池的别名。
41
+ pool_manager: The MySQL pool manager that manages the connection pool.
42
+ 管理连接池的MySQL池管理器。
43
+ """
12
44
  self.alias = alias
13
45
  self.pool_manager = pool_manager
14
46
 
15
- async def insert(self, sql, value):
16
- async with self.pool_manager.get(self.alias) as (connect, cursor):
47
+ async def insert(self, sql: str, value: list):
48
+ """
49
+ Insert multiple rows into a MySQL table.
50
+ 向MySQL表中插入多行数据。
51
+
52
+ This method executes an INSERT statement with multiple sets of values.
53
+ It automatically handles transactions, committing on success and
54
+ rolling back on failure.
55
+ 此方法执行带有多组值的INSERT语句。
56
+ 它自动处理事务,在成功时提交,在失败时回滚。
57
+
58
+ Args:
59
+ sql: The SQL INSERT statement with placeholders.
60
+ 带有占位符的SQL INSERT语句。
61
+ value: A list of tuples or lists, each containing values for one row.
62
+ 元组或列表的列表,每个包含一行的值。
63
+
64
+ Returns:
65
+ int: The number of affected rows.
66
+ 受影响的行数。
67
+
68
+ Raises:
69
+ Exception: If the query fails.
70
+ 如果查询失败。
71
+ """
72
+ async with self.pool_manager.get(self.alias) as (conn, cursor):
17
73
  try:
74
+ # Execute the query with multiple sets of values
75
+ # 使用多组值执行查询
18
76
  result = await cursor.executemany(sql, value)
19
- await connect.commit()
77
+ # Commit the transaction
78
+ # 提交事务
79
+ await conn.commit()
20
80
  return result
21
81
  except Exception as e:
22
- await connect.rollback()
82
+ # Roll back the transaction on error
83
+ # 出错时回滚事务
84
+ await conn.rollback()
23
85
  raise Exception from e
24
86
 
25
87
  async def execute(self, sql: str):
26
- async with self.pool_manager.get(self.alias) as (connect, cursor):
88
+ """
89
+ Execute a SQL query and fetch all results.
90
+ 执行SQL查询并获取所有结果。
91
+
92
+ This method executes a SQL query and returns all rows from the result.
93
+ 此方法执行SQL查询并返回结果中的所有行。
94
+
95
+ Args:
96
+ sql: The SQL query to execute.
97
+ 要执行的SQL查询。
98
+
99
+ Returns:
100
+ list: A list of tuples containing the query results.
101
+ 包含查询结果的元组列表。
102
+ """
103
+ async with self.pool_manager.get(self.alias) as (conn, cursor):
104
+ # Execute the query
105
+ # 执行查询
27
106
  await cursor.execute(sql)
107
+ # Fetch all results
108
+ # 获取所有结果
28
109
  return await cursor.fetchall()
29
110
 
30
111
  async def query(self, sql: str):
112
+ """
113
+ Alias for execute method.
114
+ execute方法的别名。
115
+
116
+ This method is a convenience alias for the execute method.
117
+ 此方法是execute方法的便捷别名。
118
+
119
+ Args:
120
+ sql: The SQL query to execute.
121
+ 要执行的SQL查询。
122
+
123
+ Returns:
124
+ list: A list of tuples containing the query results.
125
+ 包含查询结果的元组列表。
126
+ """
31
127
  return await self.execute(sql)
32
128
 
33
129
 
34
130
  class AioMysqlPoolManager(AbsDBPoolManager):
131
+ """
132
+ Pool manager for MySQL connections.
133
+ MySQL连接的池管理器。
134
+
135
+ This class manages MySQL connection pools. It implements the
136
+ AbsDBPoolManager interface for MySQL connections, providing methods for
137
+ creating, accessing, and closing MySQL connection pools.
138
+ 此类管理MySQL连接池。它为MySQL连接实现了AbsDBPoolManager接口,
139
+ 提供了创建、访问和关闭MySQL连接池的方法。
140
+ """
141
+
142
+ # Dictionary to store MySQL connection pools by alias
143
+ # 按别名存储MySQL连接池的字典
35
144
  _clients = {}
36
145
 
37
146
  async def create(self, alias: str, params: dict):
147
+ """
148
+ Create a new MySQL connection pool.
149
+ 创建新的MySQL连接池。
150
+
151
+ This method creates a new MySQL connection pool with the given alias and parameters.
152
+ If a pool with the given alias already exists, it returns the existing pool.
153
+ 此方法使用给定的别名和参数创建新的MySQL连接池。
154
+ 如果具有给定别名的池已经存在,则返回现有池。
155
+
156
+ Args:
157
+ alias: The alias for the new MySQL connection pool.
158
+ 新MySQL连接池的别名。
159
+ params: The parameters for creating the MySQL connection pool. Can include:
160
+ 创建MySQL连接池的参数。可以包括:
161
+ - host: MySQL server host
162
+ MySQL服务器主机
163
+ - port: MySQL server port
164
+ MySQL服务器端口
165
+ - user: MySQL username
166
+ MySQL用户名
167
+ - password: MySQL password
168
+ MySQL密码
169
+ - db: MySQL database name
170
+ MySQL数据库名称
171
+ - connect_timeout: Connection timeout in seconds
172
+ 连接超时(秒)
173
+ - and other parameters accepted by aiomysql.create_pool
174
+ 以及aiomysql.create_pool接受的其他参数
175
+
176
+ Returns:
177
+ Pool: The created or existing MySQL connection pool.
178
+ 创建的或现有的MySQL连接池。
179
+ """
180
+ # Return existing pool if it exists
181
+ # 如果池已存在,则返回现有池
38
182
  if alias in self._clients:
39
183
  return self._clients[alias]
40
184
 
185
+ # Make a copy of params to avoid modifying the original
186
+ # 复制params以避免修改原始参数
41
187
  params = params.copy()
42
- # When the host is domain,converted to IP
188
+
189
+ # When the host is domain, convert to IP
190
+ # 当主机是域名时,转换为IP
43
191
  # https://github.com/aio-libs/aiomysql/issues/641
44
192
  params.update({'host': socket.gethostbyname(params['host'])})
193
+
194
+ # Set default connection timeout
195
+ # 设置默认连接超时
45
196
  params.setdefault('connect_timeout', 30)
197
+
198
+ # Create the MySQL connection pool
199
+ # 创建MySQL连接池
46
200
  mysql_pool = await create_pool(**params)
201
+
202
+ # Store and return the pool
203
+ # 存储并返回池
47
204
  return self._clients.setdefault(alias, mysql_pool)
48
205
 
49
206
  def get_pool(self, alias: str):
207
+ """
208
+ Get a MySQL connection pool by its alias.
209
+ 通过别名获取MySQL连接池。
210
+
211
+ This method retrieves an existing MySQL connection pool with the given alias.
212
+ 此方法检索具有给定别名的现有MySQL连接池。
213
+
214
+ Args:
215
+ alias: The alias of the MySQL connection pool to retrieve.
216
+ 要检索的MySQL连接池的别名。
217
+
218
+ Returns:
219
+ Pool: The MySQL connection pool with the given alias.
220
+ 具有给定别名的MySQL连接池。
221
+
222
+ Raises:
223
+ AssertionError: If no MySQL connection pool exists with the given alias.
224
+ 如果不存在具有给定别名的MySQL连接池。
225
+ """
50
226
  mysql_pool = self._clients.get(alias)
51
227
  assert mysql_pool is not None, f"Dont create the mysql pool named {alias}"
52
228
  return mysql_pool
53
229
 
54
230
  @asynccontextmanager
55
231
  async def get(self, alias: str, ping=False):
56
- """Get connection and cursor of mysql"""
232
+ """
233
+ Get a MySQL connection and cursor as an async context manager.
234
+ 获取MySQL连接和游标作为异步上下文管理器。
235
+
236
+ This method provides a convenient way to acquire a connection and cursor
237
+ from a MySQL connection pool, and automatically release them when the
238
+ context is exited.
239
+ 此方法提供了一种从MySQL连接池获取连接和游标的便捷方式,
240
+ 并在退出上下文时自动释放它们。
241
+
242
+ Example:
243
+ ```python
244
+ async with mysql_manager.get('default') as (conn, cur):
245
+ await cur.execute('SELECT * FROM users')
246
+ results = await cur.fetchall()
247
+ ```
248
+
249
+ Args:
250
+ alias: The alias of the MySQL connection pool to use.
251
+ 要使用的MySQL连接池的别名。
252
+ ping: Whether to ping the server to check the connection.
253
+ 是否ping服务器以检查连接。
254
+
255
+ Yields:
256
+ tuple: A tuple containing (connection, cursor).
257
+ 包含(连接, 游标)的元组。
258
+ """
259
+ # Get the MySQL connection pool
260
+ # 获取MySQL连接池
57
261
  mysql_pool = self.get_pool(alias)
262
+
263
+ # Acquire a connection from the pool
264
+ # 从池中获取连接
58
265
  conn = await mysql_pool.acquire()
266
+
267
+ # Create a cursor
268
+ # 创建游标
59
269
  cur = await conn.cursor()
270
+
60
271
  try:
272
+ # Ping the server if requested
273
+ # 如果请求,ping服务器
61
274
  if ping:
62
275
  await conn.ping()
276
+
277
+ # Yield the connection and cursor to the caller
278
+ # 将连接和游标传递给调用者
63
279
  yield conn, cur
64
280
  finally:
281
+ # Always close the cursor and release the connection
282
+ # 始终关闭游标并释放连接
65
283
  await cur.close()
66
284
  await mysql_pool.release(conn)
67
285
 
68
286
  def executor(self, alias: str) -> MysqlExecutor:
287
+ """
288
+ Get a MysqlExecutor for a specific MySQL connection pool.
289
+ 获取特定MySQL连接池的MysqlExecutor。
290
+
291
+ This method creates a MysqlExecutor that provides a convenient way to
292
+ execute SQL queries on the MySQL connection pool with the given alias.
293
+ 此方法创建一个MysqlExecutor,提供了一种在具有给定别名的MySQL连接池上
294
+ 执行SQL查询的便捷方式。
295
+
296
+ Args:
297
+ alias: The alias of the MySQL connection pool to use.
298
+ 要使用的MySQL连接池的别名。
299
+
300
+ Returns:
301
+ MysqlExecutor: An executor for the MySQL connection pool.
302
+ MySQL连接池的执行器。
303
+ """
69
304
  return MysqlExecutor(alias, self)
70
305
 
71
306
  async def close(self, alias: str):
307
+ """
308
+ Close a specific MySQL connection pool.
309
+ 关闭特定的MySQL连接池。
310
+
311
+ This method closes the MySQL connection pool with the given alias and removes it
312
+ from the managed pools.
313
+ 此方法关闭具有给定别名的MySQL连接池,并将其从管理的池中移除。
314
+
315
+ Args:
316
+ alias: The alias of the MySQL connection pool to close.
317
+ 要关闭的MySQL连接池的别名。
318
+
319
+ Returns:
320
+ None
321
+ """
322
+ # Remove the pool from the managed pools
323
+ # 从管理的池中移除池
72
324
  mysql_pool = self._clients.pop(alias, None)
325
+
326
+ # Close the pool if it exists
327
+ # 如果池存在,则关闭它
73
328
  if mysql_pool:
329
+ # Close the pool (stop accepting new connections)
330
+ # 关闭池(停止接受新连接)
74
331
  mysql_pool.close()
332
+
333
+ # Wait for all connections to be released and closed
334
+ # 等待所有连接被释放和关闭
75
335
  await mysql_pool.wait_closed()
76
336
 
77
337
  async def close_all(self):
338
+ """
339
+ Close all MySQL connection pools.
340
+ 关闭所有MySQL连接池。
341
+
342
+ This method closes all MySQL connection pools managed by this manager.
343
+ 此方法关闭此管理器管理的所有MySQL连接池。
344
+
345
+ Returns:
346
+ None
347
+ """
348
+ # Create a copy of the keys to avoid modifying the dictionary during iteration
349
+ # 创建键的副本,以避免在迭代期间修改字典
78
350
  for alias in list(self._clients.keys()):
79
351
  await self.close(alias)
80
352
 
81
353
  async def from_dict(self, db_args: dict):
354
+ """
355
+ Initialize MySQL connection pools from a configuration dictionary.
356
+ 从配置字典初始化MySQL连接池。
357
+
358
+ This method creates MySQL connection pools based on the configuration in db_args.
359
+ 此方法根据db_args中的配置创建MySQL连接池。
360
+
361
+ Args:
362
+ db_args: A dictionary mapping aliases to MySQL connection parameters.
363
+ 将别名映射到MySQL连接参数的字典。
364
+ Example:
365
+ {
366
+ 'default': {'host': 'localhost', 'user': 'root', 'password': 'password', 'db': 'mydb'},
367
+ 'analytics': {'host': 'analytics.example.com', 'user': 'analyst', 'password': 'password', 'db': 'analytics'}
368
+ }
369
+
370
+ Returns:
371
+ None
372
+ """
82
373
  for alias, mysql_args in db_args.items():
83
374
  await self.create(alias, mysql_args)
84
375
 
85
376
  async def from_settings(self, settings: aioscrapy.Settings):
377
+ """
378
+ Initialize MySQL connection pools from aioscrapy settings.
379
+ 从aioscrapy设置初始化MySQL连接池。
380
+
381
+ This method creates MySQL connection pools based on the MYSQL_ARGS setting.
382
+ 此方法根据MYSQL_ARGS设置创建MySQL连接池。
383
+
384
+ The MYSQL_ARGS setting should be a dictionary mapping aliases to MySQL
385
+ connection parameters, for example:
386
+ MYSQL_ARGS设置应该是一个将别名映射到MySQL连接参数的字典,例如:
387
+
388
+ ```python
389
+ MYSQL_ARGS = {
390
+ 'default': {'host': 'localhost', 'user': 'root', 'password': 'password', 'db': 'mydb'},
391
+ 'analytics': {'host': 'analytics.example.com', 'user': 'analyst', 'password': 'password', 'db': 'analytics'}
392
+ }
393
+ ```
394
+
395
+ Args:
396
+ settings: The aioscrapy settings object.
397
+ aioscrapy设置对象。
398
+
399
+ Returns:
400
+ None
401
+ """
86
402
  for alias, mysql_args in settings.getdict('MYSQL_ARGS').items():
87
403
  await self.create(alias, mysql_args)
88
404
 
89
405
 
406
+ # Singleton instance of AioMysqlPoolManager
407
+ # AioMysqlPoolManager的单例实例
90
408
  mysql_manager = AioMysqlPoolManager()
91
409
 
410
+ # Example usage
411
+ # 示例用法
92
412
  if __name__ == '__main__':
93
413
  import asyncio
94
414
 
95
415
 
96
416
  async def test():
417
+ """
418
+ Test function demonstrating the usage of the MySQL manager.
419
+ 演示MySQL管理器用法的测试函数。
420
+ """
421
+ # Create a MySQL connection pool with alias 'default'
422
+ # 创建别名为'default'的MySQL连接池
97
423
  mysql_pool = await mysql_manager.create('default', {
98
424
  'db': 'mysql',
99
425
  'user': 'root',
@@ -102,23 +428,50 @@ if __name__ == '__main__':
102
428
  'port': 3306
103
429
  })
104
430
 
105
- # 方式一:
431
+ # Method 1: Using the pool directly
432
+ # 方式一:直接使用连接池
106
433
  try:
434
+ # Acquire a connection from the pool
435
+ # 从池中获取连接
107
436
  conn = await mysql_pool.acquire()
437
+
438
+ # Create a cursor
439
+ # 创建游标
108
440
  cur = await conn.cursor()
441
+
442
+ # Execute a query
443
+ # 执行查询
109
444
  await cur.execute('select * from user')
445
+
446
+ # Fetch and print the results
447
+ # 获取并打印结果
110
448
  print(await cur.fetchall())
449
+
450
+ # Uncomment to commit changes if needed
451
+ # 如果需要,取消注释以提交更改
111
452
  # await conn.commit()
112
453
  finally:
454
+ # Always close the cursor and release the connection
455
+ # 始终关闭游标并释放连接
113
456
  await cur.close()
114
457
  await mysql_pool.release(conn)
115
458
 
116
- # 方式二:
117
- async with mysql_manager.get('xxx') as (conn, cur):
459
+ # Method 2: Using the context manager
460
+ # 方式二:使用上下文管理器
461
+ async with mysql_manager.get('default') as (conn, cur):
462
+ # Execute a query and print the number of affected rows
463
+ # 执行查询并打印受影响的行数
118
464
  print(await cur.execute('select 1'))
465
+
466
+ # Uncomment to commit changes if needed
467
+ # 如果需要,取消注释以提交更改
119
468
  # await conn.commit()
120
469
 
470
+ # Close all connection pools
471
+ # 关闭所有连接池
121
472
  await mysql_manager.close_all()
122
473
 
123
474
 
475
+ # Run the test function
476
+ # 运行测试函数
124
477
  asyncio.run(test())