Mysql语句返回多个结果用list接收

本文探讨了在Java中遇到Mysql TooManyResultsException的具体原因,即预期返回一行但实际获取到多行数据。通过实例说明如何使用List封装查询结果,以适应返回多结果的情况。重点在于解决方法和类型转换技巧。

返回多条 Mysql报错

TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 7 你希望返回一行,但实际select得到的,超过一行记录
解决 :用list集合接收 结果集写list的封装类
public List<Integer> monthCount();
结果集类型问题

<think>我们面对的任务是:使用Python同时连多个MySQL数据库,执行SQL查询和插入操作。我们可以采用多线程或异步方式来实现。 根据引用[1]和[2],我们可以考虑使用多线程和数据库池(PooledDB)来管理多个数据库,以避免多线程环境下数据库多个线程共享导致的问题。 同时,引用[3]提供了一个MySQL表结构的例子,但我们的重点在于如何同时连多个数据库并执行操作。 方案选择: 1. 多线程:每个线程负责一个数据库的连和操作。我们可以为每个数据库创建一个连(或从连池获取),然后执行SQL。 2. 异步:使用asyncio和aiomysql(引用[1]中提到了aiohttp和aiomysql)可以实现异步操作,但需要异步驱动支持。 考虑到多个数据库之间是独立的,我们可以并行操作。这里我们展示两种方法:多线程和异步协程。 方法一:多线程(使用线程池和连池) 步骤: a. 为每个数据库创建连池(或者使用一个连池管理多个数据库的连?注意:连池通常针对一个数据库,因为连参数不同)。 由于每个数据库的连参数可能不同,我们需要为每个数据库创建一个连池。 b. 使用线程池(ThreadPoolExecutor)来并发执行多个数据库的操作。 方法二:异步协程(使用asyncio和aiomysql) 步骤: a. 为每个数据库创建连(使用异步连)。 b. 使用asyncio.gather来并发执行多个数据库的异步操作。 由于问题中同时提到了查询和插入,我们假设操作是相同的(比如执行相同的SQL语句,但数据库不同),或者也可以根据需求执行不同的SQL。 下面我们分别给出两种方法的代码示例。 注意:由于引用[2]中提到了dbutils的PooledDB,我们可以在多线程方法中使用它来管理每个数据库的连(每个数据库一个连池)。但注意,连池本身不是线程安全的吗?实际上,PooledDB是设计用于多线程的,每个线程从连池获取连,使用后归还。 但是,我们这里需要同时连多个不同的数据库,因此我们需要为每个数据库配置一个连池。然后,每个线程操作一个数据库时,使用对应的连池。 然而,如果使用异步方式,则不需要连池,因为异步操作可以在一个事件循环中管理多个。 我们先给出多线程方案: 多线程方案步骤: 1. 定义每个数据库的连参数(多个数据库,每个数据库一个配置)。 2. 为每个数据库创建一个连池(使用PooledDB)。 3. 定义一个函数,该函数接收一个连池和需要执行的SQL语句,然后执行(查询或插入)。 4. 使用线程池,为每个数据库提交一个任务(每个任务使用对应的连池和SQL)。 注意:如果每个数据库执行的SQL不同,可以传入不同的SQL。 代码示例(多线程): 假设我们有两个数据库,需要执行相同的查询操作(例如:SELECT * FROM table),然后将结果插入到另一个表(或做其他处理)。这里我们只演示查询。 首先,安装必要的库:pymysql 和 dbutils pip install pymysql dbutils 代码: """ import threading from dbutils.pooled_db import PooledDB from concurrent.futures import ThreadPoolExecutor # 假设有两个数据库配置 db_configs = [ { 'host': 'localhost', 'port': 3306, 'user': 'user1', 'password': 'password1', 'database': 'db1', 'charset': 'utf8mb4' }, { 'host': 'localhost', 'port': 3307, 'user': 'user2', 'password': 'password2', 'database': 'db2', 'charset': 'utf8mb4' } ] # 为每个数据库创建一个连池 pools = [] for config in db_configs: pool = PooledDB( creator=pymysql, # 使用pymysql作为连创建者 maxconnections=5, # 连池中最大连数 mincached=2, # 初始化时连池中至少创建的空闲连 blocking=True, # 连池中如果没有可用连后是否阻塞等待 **config ) pools.append(pool) # 定义执行SQL的函数 def execute_sql(pool, sql, operation='query'): # 从连池获取连 conn = pool.connection() cursor = conn.cursor() try: cursor.execute(sql) if operation == 'query': results = cursor.fetchall() # 这里可以处理查询结果,比如插入到另一个数据库等,这里仅返回 return results else: # 插入或更新 conn.commit() return cursor.rowcount finally: cursor.close() conn.close() # 实际是归还连 # 假设我们要在每个数据库上执行的SQL sql = "SELECT * FROM DimAccount;" # 使用线程池执行 with ThreadPoolExecutor(max_workers=len(pools)) as executor: # 提交任务,每个数据库一个任务 future_to_db = {executor.submit(execute_sql, pool, sql): i for i, pool in enumerate(pools)} for future in concurrent.futures.as_completed(future_to_db): db_index = future_to_db[future] try: data = future.result() print(f"Database {db_index} query result: {len(data)} rows") except Exception as e: print(f"Database {db_index} error: {e}") """ 方法二:异步协程(使用aiomysql) 安装:pip install aiomysql 步骤: 1. 定义每个数据库的连参数。 2. 创建一个异步函数,用于连一个数据库并执行SQL。 3. 使用asyncio.gather同时运行多个数据库的查询。 代码示例(异步): """ import asyncio import aiomysql # 数据库配置列表 db_configs = [ { 'host': 'localhost', 'port': 3306, 'user': 'user1', 'password': 'password1', 'db': 'db1', 'charset': 'utf8mb4' }, { 'host': 'localhost', 'port': 3307, 'user': 'user2', 'password': 'password2', 'db': 'db2', 'charset': 'utf8mb4' } ] async def execute_sql_async(config, sql, operation='query'): # 创建连 conn = await aiomysql.connect(**config) cursor = await conn.cursor() try: await cursor.execute(sql) if operation == 'query': result = await cursor.fetchall() return result else: await conn.commit() return cursor.rowcount finally: await cursor.close() conn.close() async def main(): sql = "SELECT * FROM DimAccount;" tasks = [] for config in db_configs: task = asyncio.create_task(execute_sql_async(config, sql)) tasks.append(task) results = await asyncio.gather(*tasks, return_exceptions=True) for i, result in enumerate(results): if isinstance(result, Exception): print(f"Database {i} error: {result}") else: print(f"Database {i} query result: {len(result)} rows") # 运行异步主函数 if __name__ == '__main__': asyncio.run(main()) """ 注意: 1. 在多线程方案中,我们使用了连池(PooledDB)来管理每个数据库的连,这样可以在多线程中复用连,避免频繁创建和关闭连。 2. 在异步方案中,我们为每个任务创建一个连,因为异步操作可以同时处理多个,而且每个连在一个协程内使用,不会阻塞其他协程。 3. 在实际应用中,如果每个数据库的操作很频繁,异步方案中也可以使用连池(aiomysql提供了连池),但本例中每个数据库只执行一次查询,所以直创建连即可。 选择哪种方式? - 如果操作是I/O密集型,且数据库数量多,异步方式可能更高效,因为异步可以避免线程切换的开销。 - 如果操作复杂,需要CPU密集型处理,或者需要利用多核,多线程可能更合适(但注意GIL限制,此时可以考虑多进程)。 另外,根据引用[1],还提到了多进程爬虫,但多进程适用于CPU密集型任务,且进程间通信复杂。数据库操作通常是I/O密集型,所以多线程或异步更合适。 最后,根据需求,如果同时向多个数据库插入数据,注意事务的处理。在示例中,对于非查询操作,我们执行了commit。如果插入操作需要保证一致性,可能需要更复杂的事务控制。 请根据实际数据库配置修改上述代码中的连参数,并处理可能出现的异常。</think>我将为您详细介绍使用Python多线程或异步方式同时连多个MySQL数据库执行查询和插入操作的方法,并提供完整代码示例。 ### 一、多线程方案(推荐) 使用`dbutils.PooledDB`创建数据库池,结合`concurrent.futures`线程池实现高效并发操作。 ```python import pymysql from dbutils.pooled_db import PooledDB from concurrent.futures import ThreadPoolExecutor, as_completed # 数据库配置列表(多个数据库) DB_CONFIGS = [ { 'host': 'db1.example.com', 'user': 'user1', 'password': 'pass1', 'database': 'db1', 'port': 3306 }, { 'host': 'db2.example.com', 'user': 'user2', 'password': 'pass2', 'database': 'db2', 'port': 3307 } ] # 为每个数据库创建连池 db_pools = [] for config in DB_CONFIGS: pool = PooledDB( creator=pymysql, maxconnections=5, # 连池最大连数 mincached=2, # 初始化空闲连数 blocking=True, # 连不足时阻塞等待 **config ) db_pools.append(pool) def execute_sql(pool, sql, params=None, operation='query'): """执行SQL语句的通用函数""" conn = pool.connection() cursor = conn.cursor() try: cursor.execute(sql, params) if operation == 'insert': conn.commit() return f"Inserted {cursor.rowcount} rows" elif operation == 'query': return cursor.fetchall() finally: cursor.close() conn.close() # 实际是归还连到池 # 示例使用 if __name__ == "__main__": sql_query = "SELECT * FROM DimAccount WHERE AccountKey > %s" sql_insert = "INSERT INTO LogTable (message) VALUES (%s)" with ThreadPoolExecutor(max_workers=10) as executor: futures = [] # 提交查询任务到所有数据库 for pool in db_pools: futures.append(executor.submit( execute_sql, pool, sql_query, (50,), 'query' )) # 提交插入任务到第一个数据库 futures.append(executor.submit( execute_sql, db_pools[0], sql_insert, ("Multi-threaded insert",), 'insert' )) # 处理结果 for future in as_completed(futures): try: result = future.result() print(f"Operation result: {result}") except Exception as e: print(f"Error: {str(e)}") ``` **关键点说明:** 1. 每个数据库独立连池,避免多线程竞争 2. `PooledDB`确保线程安全(引用[2]) 3. 查询和插入操作通过`operation`参数区分 4. 使用线程池控制最大并发数 5. 连自动回收,避免资源泄漏 ### 二、异步方案(aiomysql) 使用`asyncio`和`aiomysql`实现异步操作(适合I/O密集型场景): ```python import asyncio import aiomysql DB_CONFIGS = [...] # 同多线程方案配置 async def execute_async(db_config, sql, params=None, operation='query'): """异步执行SQL""" conn = await aiomysql.connect(**db_config) async with conn.cursor() as cursor: await cursor.execute(sql, params) if operation == 'insert': await conn.commit() return f"Inserted {cursor.rowcount} rows" elif operation == 'query': return await cursor.fetchall() conn.close() async def main(): tasks = [] # 创建查询任务 for config in DB_CONFIGS: task = asyncio.create_task( execute_async(config, "SELECT * FROM DimAccount", operation='query') ) tasks.append(task) # 创建插入任务 tasks.append(asyncio.create_task( execute_async(DB_CONFIGS[0], "INSERT INTO LogTable VALUES (%s)", ("Async insert",), 'insert') )) # 等待所有任务完成 results = await asyncio.gather(*tasks, return_exceptions=True) for i, res in enumerate(results): print(f"Task {i} result: {res}") if __name__ == "__main__": asyncio.run(main()) ``` ### 三、关键注意事项 1. **连池管理**: - 使用`PooledDB`确保线程安全(引用[2]) - 每个连池设置`maxconnections`限制最大连数 - 连用完必须归还(通过`conn.close()`) 2. **事务处理**: - 插入操作后需要显式`commit()` - 复杂事务建议使用`with conn.cursor() as cur:`上下文管理 3. **错误处理**: - 捕获`pymysql.Error`处理数据库错误 - 使用`try/finally`确保连关闭 4. **性能优化**: - 批量插入使用`executemany()` ```python cursor.executemany("INSERT INTO table VALUES (%s,%s)", data_list) ``` - 查询使用服务器端游标:`cursor = conn.cursor(pymysql.cursors.SSCursor)` 5. **数据类型映射**: - Python类型需正确映射到MySQL类型(如datetime) - 二进制数据使用`pymysql.Binary`包装 ### 四、应用场景对比 | 方案 | 适用场景 | 优势 | 注意事项 | |--------------|-----------------------------------|--------------------------|--------------------------| | **多线程** | CPU密集型任务,复杂事务处理 | 编程模型简单,调试方便 | GIL限制,线程安全需注意 | | **异步** | 高并发I/O操作,大量简单查询 | 资源占用低,扩展性好 | 需要异步库支持,调试复杂 | ### 五、数据库表结构建议 根据引用[3]的示例,设计表时注意: ```sql CREATE TABLE `DimAccount` ( `AccountKey` INT NOT NULL AUTO_INCREMENT, `ParentAccountKey` INT DEFAULT NULL, `AccountDescription` VARCHAR(50) DEFAULT NULL, PRIMARY KEY (`AccountKey`), INDEX `idx_parent` (`ParentAccountKey`) -- 确保外键索引 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值