解决pymysql查不到最新数据的办法

这里写自定义目录标题
项目场景:
问题描述:
原因分析:
解决方案:
参考资料:
项目场景:
python3.6,windows,mysql

问题描述:
在本地远程连接mysql数据库,用的是pymysql,我本地创建了两个连接,分别是pymysql的,另一个是用Popen创建的命令行的客户端,我先创建的pymysql的客户端进行查询,然后利用Popen的客户端进行插入数据,然后在用之前创建的pymysql的客户端进行数据的查询,然后我发现,查询到的结果为空,但是我手动查询能查得到,以为sql写错了,拿程序运行的sql去查询,发现并没有问题,然后我怀疑是因为客户端的问题,然后我在查询时,重新创建了一个客户端,发现就能查询到数据了,这很奇怪,难道mysql的事务还能这样,我抱着怀疑的态度查询了一下资料

原因分析:
MySQL默认事务隔离级别是 REPEATABLE READ,当我在本地 Popen中利用SQL插入用户数据 后,Pymysql连接端的事务A不会读取到Pepen连接端更新的事务B,即便事务B已提交,而事务A每次查询到的数据都是最开始创建事务查询到结果的快照,事务A一直没进行更新。

现在回到最初的问题:

基于InnoDB默认的repeatable read事务隔离和select为快照读可知,连接池中的连接在初始化时,没有设置autocommit为True,会导致复用同一个连接的多次select查询其实都在一个事务内,且都为快照读,这样,每个select查的数据源并不是表中的最新数据,而是第1个查询时的快照,因此导致查不到表中其他事务(下单接口的写入操作)写入的最新数据。
将autocommit设置为True后,每个事务中只有1个查询,下一个查询属于一个全新的事务,这样就能读到新事务开始前的最新数据了。

更详细的解释说明,可参考文末列出的网上资料

解决方案:
1:修改MySQL的事务隔离级别
2:每次查询操作后,都进行 commit() 提交事务。
3:Python创建pymysql连接时,设置 autocommit=True ,即让其操作后自动提交事务(推荐使用)。

参考资料:
http://t.zoukankan.com/wintest-p-12825371.html

<think>好的,我现在需要帮用户写一个脚本,这个脚本要连接MySQL,查询包含“b66”关键字的数据库,然后在找到的每个库里执行建表语句。让我先理清楚步骤,再考虑可能出现的问题和解决办法。 首先,用户的需求分为几个部分:连接MySQL,查询特定数据库,执行建表语句。我需要用哪种语言来写脚本呢?用户没有指定,但常见的是Shell或者Python。Python可能更灵活,尤其是在处理数据库连接和结果集的时候,所以可能更适合。 接下来是连接MySQL。我需要用到MySQL的客户端库,比如Python中的pymysql或者mysql-connector-python。需要确保用户已经安装了这些库。在脚本里,需要配置数据库的连接参数,比如主机、端口、用户名、密码。这些信息不能硬编码,应该让用户自己输入或者从配置文件中读取,或者通过命令行参数传入。但为了方便用户,可能需要提示用户修改相关参数,或者使用环境变量。 然后是查询带有“b66”关键字的数据库MySQL中查询所有数据库的语句是SHOW DATABASES,然后过滤出名字包含“b66”的。这里需要注意的是,用户是否有权限访问所有数据库,或者是否需要考虑大小写敏感的问题。比如,MySQL默认情况下,数据库名是大小写敏感的,取决于操作系统,但通常Linux下是敏感的。所以需要确保匹配正确,可能需要使用LIKE或正则表达式。例如:SHOW DATABASES WHERE `Database` LIKE '%b66%'; 这个语句在MySQL中可能有效,但需要确认是否正确。或者,在Python中获取所有数据库名后,再用字符串匹配筛选。 接下来,对每个符合条件的数据库执行建表语句。建表语句需要用户提供,或者脚本中包含。用户没有给出具体的建表语句,所以脚本里可能需要留一个变量,让用户自行填写。比如,在Python脚本中,将建表语句作为字符串,用户需要修改这部分内容。 另外,需要考虑事务处理,比如是否在每次执行后提交,或者捕获异常,防止某个数据库执行失败导致脚本中断。可能需要使用try-except块来处理错误,并给出提示。 现在,我需要把这些步骤整合成一个脚本的大纲: 1. 导入必要的库,如pymysql。 2. 配置数据库连接参数。 3. 连接到MySQL服务器。 4. 查询所有数据库,过滤出包含“b66”的。 5. 遍历每个数据库,执行建表语句。 6. 处理可能出现的错误,如连接失败、执行SQL错误等。 7. 关闭数据库连接。 同时,需要注意的事项: - 权限问题:执行SHOW DATABASES需要用户有足够的权限,而且在每个数据库上执行CREATE TABLE也需要相应的权限。 - SQL注入:如果数据库名是动态生成的,需要确保不会有注入风险,但这里因为是内部查询结果,可能风险较低。 - 建表语句是否已经存在表的情况:是否需要先检查表是否存在,使用CREATE TABLE IF NOT EXISTS结构。 - 字符编码:确保连接和建表语句的字符编码正确,比如utf8mb4。 现在,考虑用户可能的实际情况。例如,用户可能在多个数据库中需要创建相同的表结构,可能是为了初始化或者数据分片等场景。因此,脚本需要高效地处理多个数据库。 可能的代码结构: 在Python中,使用pymysql库,首先连接到MySQL,执行SHOW DATABASES,然后循环处理每个库。需要注意的是,每次执行USE database;然后执行建表语句,或者在执行建表语句时指定数据库名,如CREATE TABLE dbname.tablename (...)。 例如,建表语句可以是: CREATE TABLE IF NOT EXISTS `example_table` (...); 这样,可以在每个目标数据库中创建表。 现在,把这些思考转化为代码。需要处理的问题: 1. 如何获取数据库列表:执行SHOW DATABASES,然后过滤。 2. 如何切换数据库或者指定数据库名执行语句。 3. 错误处理。 代码示例的大致步骤: - 连接MySQL获取所有数据库。 - 过滤出包含b66的。 - 对每个数据库,建立新的连接(或者复用原连接)然后执行建表语句。 不过,可能不需要重新连接,只需要在每次执行时使用USE语句,或者在SQL语句中指定数据库名。 比如,建表语句可以写成: CREATE TABLE `database_name`.`table_name` (...); 或者在执行前USE database_name; 两种方法都可以。可能更高效的是在同一个连接中切换数据库,但需要注意线程安全等问题。不过如果是单线程脚本,可能没问题。 现在,综合以上分析,编写Python脚本的大纲: import pymysql # 配置连接信息 host = 'localhost' user = 'root' password = 'your_password' port = 3306 # 建表语句,需要用户自行修改 create_table_sql = """ CREATE TABLE IF NOT EXISTS `example_table` ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; """ # 连接MySQL获取数据库列表 try: connection = pymysql.connect(host=host, user=user, password=password, port=port) with connection.cursor() as cursor: cursor.execute("SHOW DATABASES") databases = cursor.fetchall() target_dbs = [db[0] for db in databases if 'b66' in db[0]] print(f"找到符合条件的数据库:{target_dbs}") # 遍历每个数据库执行建表 for db_name in target_dbs: try: # 可能需要为每个数据库创建新的连接,或者在原连接中切换 # 使用原连接的话,需要执行USE语句 with connection.cursor() as cursor: cursor.execute(f"USE `{db_name}`") cursor.execute(create_table_sql) connection.commit() print(f"数据库 {db_name} 执行成功") except Exception as e: print(f"数据库 {db_name} 执行失败:{e}") # 可以选择是否回滚 connection.rollback() except Exception as e: print(f"连接或查询数据库失败:{e}") finally: if 'connection' in locals() and connection.open: connection.close() 不过,这里可能存在一个问题:在同一个连接中切换数据库并执行语句是否可靠。或者,更稳妥的是,为每个数据库创建新的连接,这样避免潜在的问题。比如,对于每个数据库,单独建立连接,并执行操作。 改进后的代码可能如下: for db_name in target_dbs: try: # 为每个数据库建立新连接 db_conn = pymysql.connect(host=host, user=user, password=password, port=port, database=db_name) with db_conn.cursor() as cursor: cursor.execute(create_table_sql) db_conn.commit() print(f"数据库 {db_name} 执行成功") db_conn.close() except Exception as e: print(f"数据库 {db_name} 执行失败:{e}") 这样,每个数据库都是独立的连接,可能更安全。特别是在处理不同的数据库时,避免之前的USE语句可能带来的副作用。 所以,最终的脚本可能需要这样写。同时,需要注意的是,连接参数中的database参数可以设置为db_name,这样就不需要执行USE语句,直接在该数据库下执行建表操作。 现在,关于建表语句,用户需要自己替换,所以需要在脚本中提示用户修改create_table_sql变量的内容。 另外,可能存在的错误包括: - 用户没有权限访问某些数据库。 - 建表语句在某个数据库中已经存在表,但用户使用的是CREATE TABLE,没有IF NOT EXISTS,会导致错误。所以建表语句中最好包含IF NOT EXISTS。 - 数据库名中包含特殊字符,比如反引号,需要用转义,但Python的pymysql应该会自动处理参数化,但在这个案例中,因为数据库名来自查询结果,所以应该安全,但要注意SQL注入的风险。不过因为数据库名是系统查询出来的,所以风险较低,但最好还是用参数化。但这里建表语句中的数据库名可能需要直接拼接,所以需要注意。 例如,在原来的方式中,使用cursor.execute(f"USE `{db_name}`")可能会有SQL注入的风险,但假设db_name是来自SHOW DATABASES的结果,那么应该是可信的。不过,安全起见,应该用参数化查询,但SHOW DATABASES的结果可能需要处理转义。 或者在创建连接时,将database参数设为db_name,这样就无需执行USE语句,且更安全。 综上,修改后的脚本可能更安全,并且使用每个数据库独立连接的方式。 另外,用户可能需要调整匹配数据库名的逻辑,比如是否区分大小写,或者使用正则表达式。例如,在查询数据库时,是否在MySQL端过滤,还是在Python端过滤。例如,执行SQL语句: SHOW DATABASES WHERE `Database` LIKE '%b66%'; 这样可以减少传输的数据量,特别是当数据库数量较多时。但需要注意,LIKE是不区分大小写的,如果MySQL的配置是大小写不敏感的,那么会匹配不同大小写的名称。否则可能需要调整。例如,在MySQL中,默认的collation下,LIKE是大小写不敏感的,但实际结果取决于数据库的配置。或者用户可能需要明确的大小写匹配。 所以,在Python中查询所有数据库,然后在代码中过滤可能更灵活,比如: cursor.execute("SHOW DATABASES") databases = cursor.fetchall() target_dbs = [db[0] for db in databases if 'b66' in db[0].lower()] 这样不管数据库名是大写还是小写,只要包含b66(不区分大小写)就会被选中。或者用户可能需要严格的小写匹配,比如使用if 'b66' in db[0]。这取决于用户的具体需求。因此,在脚本中可能需要说明这一点,或者让用户自行调整过滤条件。 总结,现在将整个思路整理成一个Python脚本,并添加必要的注释和提示,让用户根据实际情况修改连接参数和建表语句。</think>以下是一个用于连接MySQL、查询包含"b66"关键字的数据库并在这些库中执行建表语句的Python脚本示例。使用前请确保已安装`pymysql`库(可通过`pip install pymysql`安装)。 ```python import pymysql # 配置MySQL连接信息(需用户修改) host = "localhost" # MySQL主机地址 user = "root" # 用户名 password = "your_password" # 密码 port = 3306 # 端口 # 建表SQL语句(需用户修改) create_table_sql = """ CREATE TABLE IF NOT EXISTS `example_table` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `data` VARCHAR(255) NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; """ # 连接MySQL并获取数据库列表 try: # 建立初始连接(无需指定数据库) connection = pymysql.connect( host=host, user=user, password=password, port=port, charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor ) # 查询所有数据库并筛选含"b66"的库 with connection.cursor() as cursor: cursor.execute("SHOW DATABASES") databases = [row["Database"] for row in cursor.fetchall()] target_dbs = [db for db in databases if "b66" in db] print(f"找到目标数据库: {', '.join(target_dbs)}") # 遍历每个目标数据库执行建表 for db_name in target_dbs: try: # 为每个数据库创建新连接 db_conn = pymysql.connect( host=host, user=user, password=password, port=port, database=db_name, # 直接指定数据库 charset='utf8mb4' ) with db_conn.cursor() as cursor: cursor.execute(create_table_sql) db_conn.commit() print(f"✅ 成功在数据库 [{db_name}] 中创建表") db_conn.close() except Exception as e: print(f"❌ 数据库 [{db_name}] 执行失败: {str(e)}") except pymysql.Error as e: print(f"🚨 MySQL连接错误: {str(e)}") finally: if 'connection' in locals() and connection.open: connection.close() ``` --- ### 使用说明 1. **修改配置信息** - 替换`host`、`user`、`password`、`port`为实际MySQL连接参数 - 修改`create_table_sql`变量中的建表语句 2. **执行脚本** ```bash python script.py ``` 3. **预期输出** ``` 找到目标数据库: db_b66_test, b66_analytics
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值