导读:本期聚焦于高永康创作的《C#怎么操作SQLite数据库?详解System.Data.SQLite轻量级存储完整教程》,敬请观看详情。为什么越来越多的桌面软件和小型项目选择SQLite而不是SQL Server?答案很简单:SQLite无需安装服务、整个数据库就是一个文件、部署成本几乎为零。本文围绕C#操作SQLite数据库展开,从安装System.Data.SQLite驱动开始,逐步讲解如何创建数据库文件、建表、执行增删改查、使用参数化查询防止SQL注入,以及事务处理和常用性能优化技巧。文中所有代码示例都可以直接复制到控制台项目中运行,适合刚接触嵌入式数据库的.NET开发者快速上手。

SQLite是目前最流行的嵌入式关系型数据库之一,它最大的特点是整个数据库就是磁盘上的一个单独文件,不需要单独安装和启动数据库服务进程。对于桌面工具、小型管理系统、本地缓存这类场景,用C#配合SQLite比部署SQL Server要轻便得多。本文将以System.Data.SQLite这个官方推荐的驱动库为例,完整演示从建库建表到增删改查再到事务处理的全部流程。

C#怎么操作SQLite数据库?详解System.Data.SQLite轻量级存储完整教程

一、环境准备与驱动安装

操作SQLite数据库的第一步是引入驱动。在.NET项目中最常用的是System.Data.SQLite,它是一个开源的ADO.NET提供程序,由SQLite官方维护。打开Visual Studio,在NuGet包管理器中搜索System.Data.SQLite并安装即可,或者在程序包管理器控制台直接执行安装命令。

Install-Package System.Data.SQLite

安装完成后,项目中会自动引入System.Data.SQLite命名空间。如果你使用的是.NET Core或.NET 5以上版本,也可以选择Microsoft.Data.Sqlite,它的用法类似但更轻量。本文以System.Data.SQLite为例进行讲解,因为它对传统ADO.NET的兼容性更好,熟悉SqlClient写法的开发者几乎可以无缝切换。

需要特别注意的一点是程序集位数问题。System.Data.SQLite包含非托管代码,在早期版本中需要区分x86和x64。现在的NuGet包会自动处理依赖,但如果编译时报无法加载SQLite.Interop.dll的错误,可以在项目属性中把平台目标改为x86或x64其中之一,不要使用Any CPU。

二、创建数据库与建表

SQLite创建数据库的方式非常直接:只要在连接字符串里写上一个不存在的文件路径,连接打开时就会自动创建这个数据库文件。下面这段代码演示了如何创建一个名为test.db的数据库文件,并在其中创建一张用户表。

using System;
using System.Data.SQLite;

class Program
{
    static void Main()
    {
        // 连接字符串中的Data Source指向文件路径,文件不存在时自动创建
        string connStr = "Data Source=test.db;Version=3;";
        using (SQLiteConnection conn = new SQLiteConnection(connStr))
        {
            conn.Open();

            string sql = @"CREATE TABLE IF NOT EXISTS users (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            name TEXT NOT NULL,
                            age INTEGER,
                            email TEXT)";

            using (SQLiteCommand cmd = new SQLiteCommand(sql, conn))
            {
                cmd.ExecuteNonQuery();
                Console.WriteLine("数据库和表创建成功");
            }
        }
    }
}

这段代码有几个值得关注的细节。首先是id INTEGER PRIMARY KEY AUTOINCREMENT,这是SQLite实现自增主键的标准写法,插入数据时不指定id字段即可自动递增。其次是CREATE TABLE IF NOT EXISTS,加上这个判断可以避免重复执行建表语句时报错,这个习惯在程序初始化时特别实用。

另外,SQLite是弱类型数据库,字段声明的TEXT、INTEGER更多是一种类型倾向而不是强制约束,往INTEGER字段里存字符串在默认情况下也不会报错。如果你希望严格校验类型,可以在建表语句末尾加上STRICT关键字(需要SQLite 3.37以上版本),这样类型不匹配就会直接抛出异常,行为更接近传统关系型数据库。

三、增删改查操作详解

有了表之后就可以进行数据操作了。执行增删改用ExecuteNonQuery方法,它返回受影响的行数;执行查询用ExecuteReader遍历结果集,或者用ExecuteScalar获取单个值(比如统计数量)。下面的示例完整演示了插入、查询、更新和删除。

string connStr = "Data Source=test.db;Version=3;";
using (SQLiteConnection conn = new SQLiteConnection(connStr))
{
    conn.Open();

    // 插入数据,使用参数化查询
    string insertSql = "INSERT INTO users (name, age, email) VALUES (@name, @age, @email)";
    using (SQLiteCommand cmd = new SQLiteCommand(insertSql, conn))
    {
        cmd.Parameters.AddWithValue("@name", "张三");
        cmd.Parameters.AddWithValue("@age", 28);
        cmd.Parameters.AddWithValue("@email", "zhangsan@ipipp.com");
        int rows = cmd.ExecuteNonQuery();
        Console.WriteLine($"插入成功,受影响行数:{rows}");
    }

    // 查询数据
    string selectSql = "SELECT id, name, age, email FROM users WHERE age > @age";
    using (SQLiteCommand cmd = new SQLiteCommand(selectSql, conn))
    {
        cmd.Parameters.AddWithValue("@age", 20);
        using (SQLiteDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                Console.WriteLine($"ID:{reader.GetInt32(0)}, 姓名:{reader.GetString(1)}, 年龄:{reader.GetInt32(2)}, 邮箱:{reader.GetString(3)}");
            }
        }
    }

    // 更新数据
    using (SQLiteCommand cmd = new SQLiteCommand("UPDATE users SET age = @age WHERE name = @name", conn))
    {
        cmd.Parameters.AddWithValue("@age", 29);
        cmd.Parameters.AddWithValue("@name", "张三");
        cmd.ExecuteNonQuery();
    }

    // 删除数据
    using (SQLiteCommand cmd = new SQLiteCommand("DELETE FROM users WHERE id = @id", conn))
    {
        cmd.Parameters.AddWithValue("@id", 1);
        cmd.ExecuteNonQuery();
    }
}

这里要重点强调参数化查询的写法。SQLite的参数占位符以@开头,通过Parameters.AddWithValue方法传值。千万不要用字符串拼接的方式把用户输入直接拼进SQL语句,那会直接引入SQL注入漏洞。参数化写法不仅安全,还能让驱动正确处理字符串中的单引号、反斜杠等特殊字符,避免各种奇怪的转义问题。

读取数据时要注意空值处理。如果某个字段可能为NULL,用reader.GetInt32(2)直接取值会抛出异常,正确做法是先用reader.IsDBNull(2)判断,或者用reader["age"] as int?这种可空类型的方式接收。这是实际开发中非常常见的坑。

四、事务处理与性能优化

当你需要批量插入大量数据时,一定会发现默认模式下SQLite的写入速度慢得惊人。原因是SQLite默认为每条语句自动开启并提交一个事务,每次提交都会触发磁盘同步操作。解决方法是把批量操作包在一个显式事务里,速度可以提升成百上千倍。

string connStr = "Data Source=test.db;Version=3;";
using (SQLiteConnection conn = new SQLiteConnection(connStr))
{
    conn.Open();
    using (SQLiteTransaction tran = conn.BeginTransaction())
    {
        try
        {
            string sql = "INSERT INTO users (name, age, email) VALUES (@name, @age, @email)";
            using (SQLiteCommand cmd = new SQLiteCommand(sql, conn, tran))
            {
                cmd.Parameters.Add("@name", System.Data.DbType.String);
                cmd.Parameters.Add("@age", System.Data.DbType.Int32);
                cmd.Parameters.Add("@email", System.Data.DbType.String);

                for (int i = 0; i < 10000; i++)
                {
                    cmd.Parameters["@name"].Value = "用户" + i;
                    cmd.Parameters["@age"].Value = 20 + i % 30;
                    cmd.Parameters["@email"].Value = "user" + i + "@ipipp.com";
                    cmd.ExecuteNonQuery();
                }
            }
            tran.Commit(); // 提交事务,所有插入一次性生效
            Console.WriteLine("批量插入完成");
        }
        catch
        {
            tran.Rollback(); // 出错时回滚,保证数据一致性
            throw;
        }
    }
}

上面这个例子还用到了另一个优化技巧:循环外只创建一次SQLiteCommand并预先定义好参数,循环内只更新参数值。这省去了每次循环重复解析SQL语句的开销,配合事务使用效果最佳。如果不使用事务,插入一万条数据可能需要几十秒;包在事务里之后,通常一秒之内就能完成,差距非常明显。

除了事务,还有几个实用的优化点值得了解。连接字符串中可以加上Pooling=True启用连接池,减少频繁创建连接的开销;对经常出现在WHERE条件中的字段建立索引,例如CREATE INDEX idx_users_name ON users(name),能显著加快查询速度;如果应用场景允许极小的数据丢失风险,还可以加Synchronous=Off;Journal Mode=WAL参数,在写入性能和数据安全之间取得平衡。

最后提一下部署。程序发布时只需要带上生成的数据库文件和驱动DLL,目标机器上不需要安装任何数据库软件。数据库文件可以直接拷贝备份,也可以用SQLiteConnection.BackupDatabase方法在程序运行时做在线备份,这对需要定期归档数据的桌面应用来说非常方便。掌握了以上内容,你就已经能够应对绝大多数C#本地数据存储的需求了。

C#操作SQLiteSystem.Data.SQLite轻量级数据库修改时间:2026-09-06 10:10:37

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260906/51478.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。