with的用法

Python SQLite 操作详解

本文档详细解释了使用 Python 操作 SQLite 数据库时涉及的关键概念和代码实践,包括 with 语句、事务处理、批量插入以及相关的优化建议。

 一、with 语句的作用(自动关门的保险库)

with sqlite3.connect('city_1301.db') as conn:# 代码块# 在这里执行数据库操作,例如创建 cursor、执行 SQL 等pass
  • 作用with 语句就像一个“自动关门的保险库”。

    • 开门:当程序执行进入 with 代码块时,它会自动执行 sqlite3.connect('city_1301.db'),建立数据库连接,并将连接对象赋值给 conn 变量(类似打开保险库的门并拿到钥匙)。

    • 关门:无论 with 代码块内部的代码是正常执行完毕,还是中途发生了错误(异常),当程序流程离开 with 代码块时,它都会自动确保数据库连接 conn 被关闭(conn.close() 会被隐式调用)。

  • 为什么用它:核心目的是资源管理自动化,防止程序员忘记手动调用 conn.close() 来关闭数据库连接。忘记关闭连接可能会导致:

    • 资源泄露:连接一直占用系统资源。

    • 数据丢失或损坏:如果程序异常退出而连接未正常关闭,可能导致缓冲区的数据未完全写入磁盘。

    • 达到连接数上限:如果频繁创建连接而不关闭,可能耗尽数据库允许的最大连接数。

 二、代码逐行解析(省会垃圾数据批量入库)

# 假设 conn 是已经通过 with 语句建立的数据库连接
# data 是包含大量待插入数据的列表,例如 [(val1_row1, val2_row1, ...), (val1_row2, ...), ...]cursor = conn.cursor()  # 1. 获取游标:拿一个“笔”准备写数据到数据库这个“本子”上。
cursor.execute("BEGIN IMMEDIATE")  # 2. 开启立即事务:大喊:“现在我要开始连续写一堆数据了,在我喊停之前,其他人(其他连接)最好别写,可以读,但别干扰我!”try: # (结合优化建议中的异常处理)for i in range(0, len(data), 1000):  # 3. 分批处理循环:数据太多(比如60万条),一次处理不完,每次处理1000条。batch = data[i:i+1000]  # 4. 获取批次数据:从总数据 data 中取出当前这一小批(1000条)数据,装进一个临时的“小箱子” batch。# 5. 批量插入:使用 executemany 将 batch 这个“小箱子”里的所有数据一次性“传送”到数据库表中。#    "INSERT INTO bins VALUES (?, ?, ?)" 是 SQL 模板,? 是占位符,具体的值会从 batch 里的元组中按顺序填充。cursor.executemany("INSERT INTO bins (column1, column2, column3) VALUES (?, ?, ?)", batch)# 6. 阶段性提交:每成功插入1000条数据后,就执行一次 conn.commit()。#    这就像是把刚刚装满的那个“小箱子”里的货,正式确认推进仓库存档。conn.commit()except Exception as e: # (结合优化建议中的异常处理)conn.rollback() # 如果上面 try 块中任何一步出错,就执行回滚print(f"数据库操作出错,事务已回滚: {e}")# 注意:实际代码中,如果最后一批不足1000条,循环结束后也需要确保提交或有合适的处理。
# 更好的做法是将 commit 放在循环结束后,配合异常处理,实现原子性。见优化部分。
  • 关键点解析

    • BEGIN IMMEDIATE

      • 作用:开启一个立即事务 (IMMEDIATE Transaction)。一旦执行成功,数据库会被锁定为写锁定 (RESERVED lock) 状态。这意味着当前连接可以读写数据库,其他连接只能读,不能写,直到当前连接执行 COMMITROLLBACK

      • 类比:在进入仓库准备大规模整理货物前,在仓库大门挂上“内部整理中,暂停入库,可查询库存”的牌子,防止别人在你整理一半时又扔东西进来搞乱。

    • 分批次插入(例如 1000 条/次)

      • 原因:如果 data 列表非常大(如几十万、几百万条),一次性构建巨大的 SQL 语句或将所有数据加载到内存中传递给 executemany 可能导致程序内存溢出或数据库处理超时、卡顿。分批可以显著降低单次操作的内存消耗和数据库负载。

      • 类比:搬家时,用小推车分多次搬运包裹,而不是试图用一辆超载的大卡车一次性把所有东西硬塞进去,那样容易把车压垮或者堵在路上。

    • executemany

      • 作用:这是 SQLite(以及其他许多数据库接口)提供的批量执行同一条 SQL 语句的优化方法。它接收一个 SQL 模板和一个包含多组参数的序列(如列表的列表或列表的元组 batch)。相比于在 Python 循环中反复调用 execute 执行单条 INSERT 语句,executemany 的效率通常高得多(可能快 10 倍甚至更多),因为它减少了 Python 与数据库驱动之间的通信开销。

      • 示例中的 ?:这是参数化查询的占位符。使用占位符是防止 SQL 注入攻击 的标准做法。数据库驱动会安全地将 batch 中的值替换到 ? 的位置,而不是简单地将值拼接到 SQL 字符串中。

    • 循环内提交 (conn.commit())

      • 优势:如果在插入大量数据的过程中程序意外崩溃(比如处理到第 3500 条时崩溃),那么前 3000 条(前 3 批)因为已经被 commit,所以它们的数据会永久保存在数据库中,不会丢失。只丢失了当前正在处理但尚未提交的那一批(第 3001-4000 条)。这提供了部分持久性

      • 风险/缺点

        • 非原子性:整个“插入 60 万条数据”的操作不再是一个原子操作。它被分成了多个小的原子提交。如果业务要求这 60 万条数据必须要么全部成功插入,要么一条都不插入,那么这种方式就不合适。

        • 性能开销:每次 commit 都是一次相对昂贵的操作,因为它需要确保数据写入磁盘并释放锁。频繁提交会比在所有批次都插入完成后进行一次总提交要慢。

        • 最后批次丢失风险:如果总数据量不是批次大小的整数倍(例如 60500 条,批次 1000),最后一批 500 条在循环结束后如果没有显式调用 conn.commit(),则会丢失。

 三、代码优化建议(针对省会热点数据)

  1. 异常处理与事务原子性(防翻车,保完整):

    将整个循环和最后的提交操作包裹在 try...except...finally 或 try...except 块中,并在 except 中执行 conn.rollback()。将 commit 移到循环外部,确保整个批量插入操作的原子性。

    cursor = conn.cursor()
    try:cursor.execute("BEGIN IMMEDIATE") # 或者默认的 BEGIN DEFERRED 也可以for i in range(0, len(data), 1000):batch = data[i:i+1000]cursor.executemany("INSERT INTO bins (column1, column2, column3) VALUES (?, ?, ?)", batch)conn.commit() # 所有批次成功插入后,在循环外进行一次总提交print("所有数据批量插入成功并已提交。")
    except Exception as e:conn.rollback()  # 如果循环中任何地方出错,回滚整个事务print(f"批量插入过程中发生错误,事务已回滚: {e}")
    finally:# 可以在这里关闭 cursor,但如果使用 with conn:,连接会自动关闭# if cursor:#     cursor.close()pass
    • 作用:如果插入过程中任何一批数据失败(例如数据格式错误、违反约束等),整个事务会被回滚,数据库状态恢复到 BEGIN 之前的状态,一条新数据都不会插入。这保证了操作的原子性

  2. 坚持参数化查询(防黑客):

    始终使用占位符 ?(或其他数据库驱动支持的占位符如 %s)配合 execute 或 executemany 的第二个参数来传递数据,绝对不要手动拼接 SQL 字符串。

    # 正确写法 (已在上面示例中使用)
    cursor.executemany("INSERT INTO bins VALUES (?, ?, ?)", batch)# 错误且危险的写法 (容易被 SQL 注入)
    # for row in batch:
    #     sql = f"INSERT INTO bins VALUES ('{row[0]}', '{row[1]}', '{row[2]}')" # 非常危险!
    #     cursor.execute(sql)
    • 避免 SQL 注入:防止用户输入或外部数据中包含恶意的 SQL 代码片段(例如 '; DROP TABLE bins; --),如果直接拼接到 SQL 语句中,可能导致数据库被篡改或删除。

  3. 启用 WAL (Write-Ahead Logging) 模式(提高并发读写性能):

    对于需要较高并发读写性能的数据库(尤其是写操作频繁时),可以考虑将日志模式从默认的 DELETE 或 TRUNCATE 改为 WAL。

    # 在连接数据库后,执行 PRAGMA 命令
    conn.execute("PRAGMA journal_mode = WAL;")
    • 作用:WAL 模式下,写操作不再直接修改原始数据库文件,而是将更改追加到单独的 WAL 文件中。读操作可以直接读取数据库文件,不受写操作的长时间阻塞。这显著提高了读和写操作的并发性,“读不阻塞写,写不阻塞读”。但 WAL 模式会产生额外的 .wal.shm 文件,且在某些特定场景下(如网络文件系统)可能不适用或有性能问题。

四、总结

  • with 语句:提供自动、安全的数据库连接管理,确保连接无论如何都会被关闭,防止资源泄露。

  • 事务 (BEGIN, COMMIT, ROLLBACK):保证数据操作的原子性(要么全部成功,要么全部失败回滚),维护数据一致性。BEGIN IMMEDIATE 提供更强的写锁定。

  • 分批次处理与提交策略

    • 分批插入:针对大数据量,通过减小单次操作的数据量来降低内存和数据库负载。

    • 提交时机

      • 循环内提交:牺牲原子性换取部分持久性,适用于允许部分成功的场景,但性能稍差且有最后批次丢失风险。

      • 循环外提交(推荐):保证整个批量操作的原子性,性能通常更好,配合 try...except...rollback 最为健壮。

  • 批量插入 (executemany):大幅提升多条相同结构数据插入的效率,是性能优化的关键手段。

  • 参数化查询 (?):防止 SQL 注入攻击的金标准,必须坚持使用。

  • WAL 模式:通过改变日志机制,提高数据库的并发读写性能,适用于高并发场景。

实际部署建议:对于像省会城市这样可能访问频繁、数据量大的数据库文件(如 city_1301.db),建议:

  • 将其存放在性能较好的存储介质上,如 SSD (固态硬盘)

  • 使用监控工具(如 Prometheus + Grafana,或特定于 Python/SQLite 的监控库)来观察数据库的性能指标(如查询耗时、锁等待时间、磁盘 I/O 等),以便及时发现瓶颈并进行优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/79621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣解题汇总(困难)

文章目录 技巧42_接雨水 技巧 42_接雨水 class Solution {public int trap(int[] height) {int LMax 0, RMax 0;int len height.length;int[] L2R new int[len];int[] R2L new int[len];//计数每一个格的左右边最高柱for (int i 0; i < len; i) {LMax Math.max(LMa…

【Redis】Redis常用命令

4.Redis常见命令 4.1 Redis数据结构介绍 Redis是一个key-value的数据库&#xff0c;key一般是String类型&#xff0c;不过value的类型多种多样&#xff1a; 命令太多&#xff0c;不需要死记&#xff0c;学会查询就好了~ Redis为了方便我们学习&#xff0c;将操作不同数据类型…

Ubuntu 系统上广受好评的浏览器推荐

日常使用与开发者首选 Firefox 特点&#xff1a;开源、隐私保护强大&#xff0c;支持丰富扩展&#xff08;如开发者工具、广告拦截&#xff09;&#xff0c;默认预装且跨平台兼容368。 适用场景&#xff1a;日常浏览、开发者调试&#xff08;支持实时 CSS/JS 编辑&#xff09;、…

Rust Trait 学习

概述 特征&#xff08;trait&#xff09;是rust中的概念&#xff0c;类似于其他语言中的接口&#xff08;interface&#xff09;。特征定义了一个可以被共享的行为&#xff0c;只要实现了特征&#xff0c;你就能使用该行为。 如果不同的类型具有相同的行为&#xff0c;那么我们…

JavaScript性能优化实战(9):图像与媒体资源优化

引言 在当今视觉驱动的网络环境中,图像和媒体资源往往占据了网页总下载量的60%-80%,因此对图像和媒体资源进行有效优化已成为前端性能提升的关键领域。尽管网络带宽持续提升,但用户对加载速度的期望也在不断提高,特别是在移动设备和网络条件不稳定的场景下。 本文作为Jav…

NHANES指标推荐:LC9

文章题目&#xff1a;Association between lifes crucial 9 and kidney stones: a population-based study DOI&#xff1a;10.3389/fmed.2025.1558628 中文标题&#xff1a;生命的关键 9 与肾结石之间的关联&#xff1a;一项基于人群的研究 发表杂志&#xff1a;Front Med 影响…

谷歌 NotebookLM 支持生成中文播客

谷歌 NotebookLM 支持生成中文播客。 2025 年 4 月 29 日&#xff0c;NotebookLM 宣布其 “音频概览”&#xff08;Audio Overviews&#xff09;功能新增 76 种语言支持&#xff0c;其中包括中文。用户只需将文档、笔记、研究材料等上传至 NotebookLM&#xff0c;然后在设置中选…

ElasticSearch深入解析(十):字段膨胀(Mapping 爆炸)问题的解决思路

文章目录 一、核心原理&#xff1a;动态映射的双刃剑1. 动态映射的工作机制2. 映射爆炸的触发条件3. 底层性能损耗 二、典型场景与案例分析1. 日志系统&#xff1a;动态标签引发的灾难2. 物联网数据&#xff1a;设备属性的无序扩展 三、系统性解决方案1. 架构层优化2. 配置层控…

交互式智能体面临长周期决策和随机环境反馈交互等挑战 以及解决办法

交互式智能体面临长周期决策和随机环境反馈交互等挑战 以及解决办法 目录 交互式智能体面临长周期决策和随机环境反馈交互等挑战 以及解决办法随机初始化参数,lora但是训练需要更加细粒度的评价指数(对思考过程评价,对得出结果的证明评价,对结果评价)用户进看到结果《RAGE…

4:机器人目标识别无序抓取程序二次开发

判断文件是否存在 //判断文件在不在 int HandEyeCalib::AnsysFileExists(QString FileAddr) {QFile File1(FileAddr);if(!File1.exists()){QMessageBox::warning(this,QString::fromLocal8Bit("提示"),FileAddrQString::fromLocal8Bit("文件不存在"));retu…

【Touching China】2007-2011

文章目录 1、20072、20083、20094、20105、2011 1、2007 钱学森 身份&#xff1a;中国航天事业奠基人&#xff0c;中国科学院、中国工程院资深院士获奖事迹&#xff1a;钱学森1955年冲破重重阻力回到祖国&#xff0c;长期担任火箭导弹和航天器研制的技术领导职务。他以总体、动…

linux常用基础命令_最新版

常用命令 查看当前目录下个各个文件大小查看当前系统储存使用情况查看当前路径删除当前目录下所有包含".log"的文件linux开机启动jar更改自动配置文件后操作关闭自启动linux静默启动java服务查询端口被占用查看软件版本重启关机开机启动取别名清空当前行创建文件touc…

Mamba+Attention+CNN 预测模型:破局长程依赖的计算机视觉新范式

目录 一、引言:从 CNN 到 Mamba 的视觉建模进化之路 二、模型关键组成部分解析 (一)CNN 基干:局部特征提取器 (二)Mamba 块:长程依赖建模核心 (三)注意力机制:特征交互增强器 三、模型创新点 四、模型原理与作用 五、优缺点对比 六、应用领域 一、引言:从 C…

LangChain4j +DeepSeek大模型应用开发——8 Function Calling 函数调用

Function Calling 函数调用也叫 Tools 工具 入门案例 例如&#xff0c;大语言模型本身并不擅长数学运算。如果应用场景中偶尔会涉及到数学计算&#xff0c;我们可以**为他提供一个 “数学工具”。**当我们提出问题时&#xff0c;大语言模型会判断是否使用某个工具。 创建工具…

【Prometheus-Mongodb Exporter安装配置指南,开机自启】

目录 内容概述 一、创建MongoDB监控专用用户二、安装MongoDB Exporter三、启动Exporter服务四、配置Systemd服务五、服务管理命令六、Prometheus集成配置七、Grafana看板 内容概述 本教程详细演示了如何在Linux系统中部署MongoDB Exporter以监控MongoDB数据库&#xff0c;并将…

在 Ubuntu 上安装 cPanel

开始之前&#xff0c;请确保拥有一台 Ubuntu 服务器&#xff0c;推荐使用 Ubuntu 22.04 LTS。如果没有&#xff0c;可以查看免费服务器&#xff1a; 11个免费 VPS&#xff0c;够用一辈子了&#xff01;&#xff08;2025最新&#xff09;Top 11 免费VPS推荐平台对比&#xff08…

【算法基础】插入排序算法 - JAVA

一、算法基础 1.1 什么是插入排序 插入排序是一种简单直观的排序算法&#xff0c;它的工作原理类似于我们打牌时整理手牌的过程。插入排序的核心思想是将数组分为已排序和未排序两部分&#xff0c;每次从未排序部分取出一个元素&#xff0c;插入到已排序部分的适当位置。 1.…

WEB前端小练习——记事本

一、登陆页面 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>记事本登录注册</title><link…

[ACTF2020 新生赛]Include [ACTF2020 新生赛]Exec

[ACTF2020 新生赛]Include 因为前端过滤的太多了 所以直接使用 日志包含 搞 包含这个 /var/log/nginx/access.log [ACTF2020 新生赛]Include蚁剑连接 翻看 flag{1ce7a81e-0339-44ef-a398-a7784d3efe37} [ACTF2020 新生赛]Exec [ACTF2020 新生赛]Exec 127.0.0.1 |echo <?…

VFS Global 携手 SAP 推动数字化转型

2025年5月2日&#xff0c;SAP 公司宣布&#xff0c;全球领先的签证、领事和技术服务提供商 VFS Global 将采用 SAP 的多项核心软件解决方案&#xff0c;推动其全球政务服务和跨境流动解决方案迈向全面数字化和智能化。此次合作标志着 VFS Global 在 AI 赋能的政府科技&#xff…