SqlSugar 使用教程

SqlSugar 使用教程

SqlSugar 是一款 .NET 生态下开源免费、高性能、低代码、开箱即用的 ORM 框架,MIT 开源协议,性能接近原生 ADO.NET,支持多数据库兼容,是 .NET 开发中最主流的 ORM 之一。

本教程基于 SqlSugar 5.X 最新稳定版编写,覆盖从入门安装到进阶实战的全流程,适配 .NET Core 3.1 / .NET 5+ 及以上版本(.NET Framework 需使用 SqlSugar 非 Core 版本)。

一、环境准备与安装

1. 支持范围

  • 框架支持:.NET Core 3.1、.NET 5/6/7/8/9/10、.NET Framework 4.0+
  • 数据库支持:SQL Server、MySQL、PostgreSQL、Oracle、SQLite、达梦、人大金仓等主流数据库
  • 核心包区分
    • .NET Core/.NET 5+ :SqlSugarCore(推荐,持续更新维护)
    • .NET Framework :SqlSugar

2. 安装方式

方式1:NuGet 包管理器(Visual Studio/Rider)

在 NuGet 包管理界面搜索 SqlSugarCore,点击安装对应稳定版即可。

方式2:命令行安装
bash 复制代码
# .NET CLI 命令(推荐)
dotnet add package SqlSugarCore

# Package Manager 命令
Install-Package SqlSugarCore

二、核心对象初始化

SqlSugar 的所有数据库操作都围绕 SqlSugarClient 核心对象展开,初始化仅需配置 ConnectionConfig 连接配置即可。

1. 基础初始化(控制台/单例场景)

核心配置项说明:

配置项 作用 推荐值
ConnectionString 数据库连接字符串 按对应数据库格式填写
DbType 数据库类型枚举 对应数据库类型(如 DbType.MySql)
IsAutoCloseConnection 自动关闭连接 必须设为 true,避免连接泄露
InitKeyType 主键识别方式 InitKeyType.Attribute(通过特性指定主键,更稳定)
csharp 复制代码
using SqlSugar;

// 1. 构建连接配置
var connectionConfig = new ConnectionConfig()
{
    ConnectionString = "Server=localhost;Database=TestDB;Uid=root;Pwd=123456;", // MySQL示例
    // SQL Server示例:"Server=.;Database=TestDB;Uid=sa;Pwd=123456;TrustServerCertificate=True;"
    DbType = DbType.MySql,
    IsAutoCloseConnection = true,
    InitKeyType = InitKeyType.Attribute
};

// 2. 创建核心客户端对象
var db = new SqlSugarClient(connectionConfig);

// 3. 可选:配置SQL日志(调试必备,可查看生成的SQL语句)
db.Aop.OnLogExecuting = (sql, pars) =>
{
    Console.WriteLine($"【生成SQL】{sql}");
    Console.WriteLine($"【参数】{string.Join(",", pars.Select(p => $"{p.ParameterName}={p.Value}"))}");
};

// 4. 测试数据库连接
var isConnected = db.Ado.IsValidConnection();
Console.WriteLine(isConnected ? "数据库连接成功" : "数据库连接失败");

2. 全局单例模式(推荐)

SqlSugarClient 是线程安全的,强烈建议全局单例初始化,避免频繁创建销毁对象带来的性能损耗。

csharp 复制代码
/// <summary>
/// SqlSugar 单例上下文
/// </summary>
public static class SqlSugarContext
{
    // 全局唯一实例
    public static readonly SqlSugarClient Db = new SqlSugarClient(new ConnectionConfig()
    {
        ConnectionString = "你的数据库连接字符串",
        DbType = DbType.MySql,
        IsAutoCloseConnection = true,
        InitKeyType = InitKeyType.Attribute
    },
    // 全局配置AOP
    db =>
    {
        // 全局SQL日志
        db.Aop.OnLogExecuting = (sql, pars) =>
        {
            Console.WriteLine($"SQL:{sql}\r\n参数:{string.Join(",", pars.Select(p => $"{p.ParameterName}={p.Value}"))}");
        };
    });
}

// 使用方式
var list = SqlSugarContext.Db.Queryable<User>().ToList();

3. ASP.NET Core 依赖注入(Web项目推荐)

Program.cs 中注入服务,支持 Scope/单例 两种生命周期:

csharp 复制代码
var builder = WebApplication.CreateBuilder(args);

// 读取配置文件中的连接字符串
var connectionString = builder.Configuration.GetConnectionString("Default");

// 注入SqlSugar客户端(Scope模式,推荐Web项目使用)
builder.Services.AddScoped<ISqlSugarClient>(sp =>
{
    return new SqlSugarClient(new ConnectionConfig()
    {
        ConnectionString = connectionString,
        DbType = DbType.MySql,
        IsAutoCloseConnection = true,
        InitKeyType = InitKeyType.Attribute
    });
});

// 单例模式注入
// builder.Services.AddSingleton<ISqlSugarClient>(...);

var app = builder.Build();
app.Run();

配置文件 appsettings.json 中添加连接字符串:

json 复制代码
{
  "ConnectionStrings": {
    "Default": "Server=localhost;Database=TestDB;Uid=root;Pwd=123456;"
  }
}

三、实体映射与表结构管理

SqlSugar 支持 CodeFirst(代码优先,实体生成表)DbFirst(数据库优先,表生成实体) 两种模式,通过特性完成实体与表/字段的精准映射。

1. 实体映射特性详解

核心特性分为类级别的 SugarTable 和属性级别的 SugarColumn,常用参数如下:

csharp 复制代码
using SqlSugar;

/// <summary>
/// 用户实体类 示例
/// </summary>
[SugarTable("sys_user")] // 指定数据库表名,不填则默认使用类名作为表名
public class User
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "user_id")]
    // 主键、自增、映射数据库字段名user_id
    public int UserId { get; set; }

    [SugarColumn(ColumnName = "user_name", Length = 50, IsNullable = false)]
    // 字段名映射、长度50、非空
    public string UserName { get; set; }

    [SugarColumn(ColumnName = "user_age", DefaultValue = "18")]
    // 默认值18
    public int Age { get; set; }

    [SugarColumn(ColumnName = "create_time", DefaultValue = "NOW()", IsOnlyIgnoreInsert = true)]
    // 默认值为当前时间,插入时忽略该字段(由数据库生成)
    public DateTime CreateTime { get; set; }

    [SugarColumn(IsIgnore = true)]
    // 忽略该字段,不映射到数据库表
    public string TempData { get; set; }

    [SugarColumn(IsNullable = true, Length = 100)]
    public string Email { get; set; }
}

2. CodeFirst 代码优先(实体生成表)

无需手动写建表SQL,通过实体类自动生成/同步数据库表结构,适合新项目开发。

csharp 复制代码
// 1. 单个实体生成表(表不存在则创建,存在则同步字段变更)
SqlSugarContext.Db.CodeFirst.InitTables<User>();

// 2. 批量多个实体生成表
SqlSugarContext.Db.CodeFirst.InitTables(typeof(User), typeof(Order), typeof(OrderItem));

// 3. 高级配置:自定义表结构
SqlSugarContext.Db.CodeFirst
    .ConfigTable<User>(t => t.TableName = "sys_user") // 自定义表名
    .ConfigColumn<User>(c =>
    {
        if (c.PropertyName == nameof(User.UserName))
        {
            c.Length = 100; // 自定义字段长度
            c.IsNullable = false; // 非空
        }
    })
    .InitTables<User>();

3. DbFirst 数据库优先(表生成实体)

已有数据库表时,一键生成对应的实体类,无需手动编写。

csharp 复制代码
// 1. 生成所有表的实体类到指定路径
SqlSugarContext.Db.DbFirst
    .CreateClassFile(@"D:\Project\Models\", "YourProject.Models"); // 路径、命名空间

// 2. 生成指定表的实体类
SqlSugarContext.Db.DbFirst
    .Where("sys_user,sys_order") // 指定表名,多个用逗号分隔
    .CreateClassFile(@"D:\Project\Models\", "YourProject.Models");

// 3. 生成时添加默认特性
SqlSugarContext.Db.DbFirst
    .IsCreateAttribute() // 自动生成SugarTable/SugarColumn特性
    .CreateClassFile(@"D:\Project\Models\", "YourProject.Models");

四、核心 CRUD 操作

SqlSugar 采用链式API设计,语法简洁直观,支持同步+异步双模式(Web项目推荐优先使用异步方法),覆盖99%的业务场景。

以下示例均使用 SqlSugarContext.Db 单例对象,实体以 User 为例。

1. 新增操作(Insert)

csharp 复制代码
#region 同步方法
// 1. 单条新增
var user = new User() { UserName = "张三", Age = 20, Email = "zhangsan@test.com" };
int rows = SqlSugarContext.Db.Insertable(user).ExecuteCommand(); // 返回受影响行数

// 2. 单条新增并返回自增主键ID(自增主键专用)
int newUserId = SqlSugarContext.Db.Insertable(user).ExecuteReturnIdentity();

// 3. 批量新增(性能远高于循环单条插入)
var userList = new List<User>()
{
    new User(){ UserName = "李四", Age = 22, Email = "lisi@test.com" },
    new User(){ UserName = "王五", Age = 25, Email = "wangwu@test.com" }
};
int batchRows = SqlSugarContext.Db.Insertable(userList).ExecuteCommand();

// 4. 大数据批量插入(10万+数据,BulkCopy模式,性能拉满)
SqlSugarContext.Db.Fastest<User>().BulkCopy(userList);

// 5. 忽略指定字段插入
SqlSugarContext.Db.Insertable(user)
    .IgnoreColumns(u => u.CreateTime) // 忽略CreateTime字段
    .ExecuteCommand();

// 6. 仅插入指定字段
SqlSugarContext.Db.Insertable(user)
    .InsertColumns(u => new { u.UserName, u.Age }) // 仅插入UserName和Age
    .ExecuteCommand();
#endregion

#region 异步方法(推荐)
// 常用异步示例
int asyncRows = await SqlSugarContext.Db.Insertable(user).ExecuteCommandAsync();
int asyncNewId = await SqlSugarContext.Db.Insertable(user).ExecuteReturnIdentityAsync();
int asyncBatchRows = await SqlSugarContext.Db.Insertable(userList).ExecuteCommandAsync();
#endregion

2. 查询操作(Query)

查询是业务中最常用的操作,SqlSugar 提供 Queryable 链式查询对象,支持复杂条件、聚合、排序等操作。

csharp 复制代码
#region 基础查询
// 1. 查询表所有数据
var allUser = SqlSugarContext.Db.Queryable<User>().ToList();

// 2. 按主键查询单条数据
var userById = SqlSugarContext.Db.Queryable<User>().InSingle(1); // 主键=1

// 3. 条件查询列表
var userByWhere = SqlSugarContext.Db.Queryable<User>()
    .Where(u => u.Age > 18 && u.UserName.Contains("张")) // 年龄>18 且 用户名包含"张"
    .ToList();

// 4. 单条条件查询(无数据返回null)
var userFirst = SqlSugarContext.Db.Queryable<User>()
    .Where(u => u.UserName == "张三")
    .First();

// 5. 查询指定字段(避免select *)
var userSelect = SqlSugarContext.Db.Queryable<User>()
    .Select(u => new { u.UserId, u.UserName, u.Age }) // 匿名对象
    .ToList();

// 6. 排序查询
var userOrder = SqlSugarContext.Db.Queryable<User>()
    .OrderBy(u => u.CreateTime, OrderByType.Desc) // 按创建时间倒序
    .OrderBy(u => u.Age, OrderByType.Asc) // 再按年龄正序
    .ToList();

// 7. 分页查询(业务高频使用)
int pageIndex = 1; // 页码
int pageSize = 10; // 每页条数
int totalCount = 0; // 总条数
var pageList = SqlSugarContext.Db.Queryable<User>()
    .Where(u => u.Age > 18)
    .ToPageList(pageIndex, pageSize, ref totalCount);
Console.WriteLine($"总条数:{totalCount},总页数:{Math.Ceiling((double)totalCount / pageSize)}");
#endregion

#region 聚合查询
// 统计总数
int count = SqlSugarContext.Db.Queryable<User>().Count(u => u.Age > 18);
// 最大值
int maxAge = SqlSugarContext.Db.Queryable<User>().Max(u => u.Age);
// 最小值
int minAge = SqlSugarContext.Db.Queryable<User>().Min(u => u.Age);
// 平均值
double avgAge = SqlSugarContext.Db.Queryable<User>().Avg(u => u.Age);
// 求和
int sumAge = SqlSugarContext.Db.Queryable<User>().Sum(u => u.Age);
// 判断是否存在
bool isExist = SqlSugarContext.Db.Queryable<User>().Any(u => u.UserName == "张三");
#endregion

#region 异步方法
var allUserAsync = await SqlSugarContext.Db.Queryable<User>().ToListAsync();
var countAsync = await SqlSugarContext.Db.Queryable<User>().CountAsync();
var pageListAsync = await SqlSugarContext.Db.Queryable<User>().ToPageListAsync(pageIndex, pageSize, totalCount);
#endregion

3. 更新操作(Update)

csharp 复制代码
#region 同步方法
// 1. 全实体更新(根据主键更新,推荐先查询再更新)
var updateUser = SqlSugarContext.Db.Queryable<User>().InSingle(1);
updateUser.UserName = "张三修改";
updateUser.Age = 30;
int updateRows = SqlSugarContext.Db.Updateable(updateUser).ExecuteCommand();

// 2. 仅更新指定字段(推荐,避免全字段更新)
SqlSugarContext.Db.Updateable<User>()
    .SetColumns(u => u.UserName == "张三修改")
    .SetColumns(u => u.Age == 30)
    .Where(u => u.UserId == 1)
    .ExecuteCommand();

// 3. 实体指定字段更新
SqlSugarContext.Db.Updateable(updateUser)
    .UpdateColumns(u => new { u.UserName, u.Age }) // 仅更新这两个字段
    .ExecuteCommand();

// 4. 条件批量更新(年龄<18的用户,年龄+1)
SqlSugarContext.Db.Updateable<User>()
    .SetColumns(u => new User() { Age = u.Age + 1 })
    .Where(u => u.Age < 18)
    .ExecuteCommand();

// 5. 批量更新
var updateList = new List<User>()
{
    new User(){ UserId = 1, UserName = "张三", Age = 20 },
    new User(){ UserId = 2, UserName = "李四", Age = 21 }
};
SqlSugarContext.Db.Updateable(updateList).ExecuteCommand();

// 6. 忽略指定字段更新
SqlSugarContext.Db.Updateable(updateUser)
    .IgnoreColumns(u => u.CreateTime) // 忽略CreateTime字段不更新
    .ExecuteCommand();
#endregion

#region 异步方法
int asyncUpdateRows = await SqlSugarContext.Db.Updateable(updateUser).ExecuteCommandAsync();
#endregion

4. 删除操作(Delete)

注意:物理删除需谨慎,生产环境推荐使用软删除(逻辑删除),通过更新字段标记删除状态。

csharp 复制代码
#region 同步方法
// 1. 按主键删除
int deleteRows = SqlSugarContext.Db.Deleteable<User>().In(1).ExecuteCommand();

// 2. 批量主键删除
SqlSugarContext.Db.Deleteable<User>().In(new int[] { 1, 2, 3 }).ExecuteCommand();

// 3. 条件删除
SqlSugarContext.Db.Deleteable<User>()
    .Where(u => u.Age < 18)
    .ExecuteCommand();

// 4. 实体删除(根据主键)
var deleteUser = SqlSugarContext.Db.Queryable<User>().InSingle(1);
SqlSugarContext.Db.Deleteable(deleteUser).ExecuteCommand();
#endregion

#region 异步方法
int asyncDeleteRows = await SqlSugarContext.Db.Deleteable<User>().In(1).ExecuteCommandAsync();
#endregion

五、进阶实战用法

1. 多表联查

SqlSugar 提供极简的联表语法,支持 LeftJoin、InnerJoin、RightJoin,最多支持16表联查。

csharp 复制代码
// 示例:订单表 左联 用户表 左联 订单明细表
// 定义关联实体
[SugarTable("sys_order")]
public class Order
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int OrderId { get; set; }
    public int UserId { get; set; }
    public string OrderNo { get; set; }
    public decimal TotalAmount { get; set; }
    public DateTime CreateTime { get; set; }
}

[SugarTable("sys_order_item")]
public class OrderItem
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int ItemId { get; set; }
    public int OrderId { get; set; }
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

// 2表联查:查询订单及对应用户信息
var orderList = SqlSugarContext.Db.Queryable<Order>()
    .LeftJoin<User>((o, u) => o.UserId == u.UserId) // 订单表左联用户表,关联条件
    .Where((o, u) => o.TotalAmount > 100)
    .Select((o, u) => new
    {
        o.OrderId,
        o.OrderNo,
        o.TotalAmount,
        u.UserId,
        u.UserName
    })
    .ToList();

// 3表联查:查询订单、用户、订单明细
var orderDetailList = SqlSugarContext.Db.Queryable<Order>()
    .LeftJoin<User>((o, u) => o.UserId == u.UserId)
    .LeftJoin<OrderItem>((o, u, i) => o.OrderId == i.OrderId)
    .Where((o, u, i) => o.OrderId == 1)
    .Select((o, u, i) => new
    {
        o.OrderId,
        o.OrderNo,
        u.UserName,
        i.ProductName,
        i.Quantity,
        i.Price
    })
    .ToList();

2. 事务处理

SqlSugar 支持多种事务模式,保证数据操作的原子性,异常时自动回滚。

csharp 复制代码
#region 方式1:使用Using事务块(推荐)
try
{
    // 开启事务
    using (var tran = SqlSugarContext.Db.CreateTran())
    {
        // 事务内的多个操作
        var user = new User() { UserName = "事务测试", Age = 20 };
        int userId = SqlSugarContext.Db.Insertable(user).ExecuteReturnIdentity();

        var order = new Order() { UserId = userId, OrderNo = "ORD2024001", TotalAmount = 100 };
        SqlSugarContext.Db.Insertable(order).ExecuteCommand();

        // 提交事务
        tran.Commit();
        Console.WriteLine("事务执行成功");
    }
}
catch (Exception ex)
{
    // 异常自动回滚,无需手动处理
    Console.WriteLine($"事务执行失败,已回滚:{ex.Message}");
}

#region 方式2:手动开启/提交/回滚事务
try
{
    SqlSugarContext.Db.Ado.BeginTran(); // 开启事务

    // 业务操作
    SqlSugarContext.Db.Insertable(new User() { UserName = "手动事务测试" }).ExecuteCommand();

    SqlSugarContext.Db.Ado.CommitTran(); // 提交事务
}
catch (Exception ex)
{
    SqlSugarContext.Db.Ado.RollbackTran(); // 回滚事务
    Console.WriteLine($"事务执行失败,已回滚:{ex.Message}");
}
#endregion

3. 原生SQL执行

对于复杂统计、存储过程调用等场景,SqlSugar 支持直接执行原生SQL语句,兼顾灵活性与安全性。

csharp 复制代码
#region 查询类SQL
// 1. 原生SQL查询列表
var userList = SqlSugarContext.Db.Ado.SqlQuery<User>("select * from sys_user where age > @Age",
    new { Age = 18 }); // 参数化查询,避免SQL注入

// 2. 原生SQL查询单值
int count = SqlSugarContext.Db.Ado.SqlQuerySingle<int>("select count(1) from sys_user where age > @Age",
    new { Age = 18 });

// 3. 匿名对象查询
var list = SqlSugarContext.Db.Ado.SqlQueryDynamic("select user_id,user_name from sys_user where age > @Age",
    new { Age = 18 });
#endregion

#region 增删改类SQL
// 执行非查询SQL,返回受影响行数
int rows = SqlSugarContext.Db.Ado.ExecuteCommand(
    "update sys_user set age = age + 1 where user_id = @UserId",
    new { UserId = 1 });
#endregion

#region 存储过程调用
SqlSugarContext.Db.Ado.UseStoredProcedure().ExecuteCommand("Proc_UpdateUserAge",
    new { UserId = 1, AddAge = 1 });
#endregion

4. 全局过滤(软删除/租户隔离)

通过全局过滤器,自动为所有查询追加条件,无需手动在每个查询中写Where,适合软删除、多租户隔离等场景。

csharp 复制代码
// 1. 给实体添加软删除字段
[SugarTable("sys_user")]
public class User
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public int Age { get; set; }
    [SugarColumn(DefaultValue = "0")]
    public bool IsDeleted { get; set; } // 软删除标记:0=未删除,1=已删除
}

// 2. 初始化SqlSugarClient时配置全局过滤器
var db = new SqlSugarClient(new ConnectionConfig()
{
    // 连接配置...
},
db =>
{
    // 全局软删除过滤器:所有查询自动追加 IsDeleted=false
    db.QueryFilter.AddTableFilter<User>(u => u.IsDeleted == false);
    
    // 多租户过滤器示例
    // db.QueryFilter.AddTableFilter<User>(u => u.TenantId == 当前租户ID);
});

// 3. 使用:查询时自动过滤已删除数据,无需手动写Where
var list = db.Queryable<User>().ToList();
// 生成的SQL自动追加 where IsDeleted=0

// 4. 临时禁用过滤器(查询已删除数据)
var allList = db.Queryable<User>().Filter(null, false).ToList();

六、最佳实践与官方资源

1. 开发最佳实践

  1. 单例模式优先 :控制台/WinForm/WPF 项目使用全局单例,Web 项目使用依赖注入,避免频繁创建 SqlSugarClient 实例。
  2. 自动释放连接 :必须开启 IsAutoCloseConnection=true,杜绝连接泄露问题。
  3. 异步优先 :Web 项目优先使用 Async 结尾的异步方法,提升服务并发能力。
  4. 参数化查询:原生SQL必须使用参数化,禁止字符串拼接SQL,避免SQL注入风险。
  5. 避免select *:查询时指定需要的字段,减少数据传输,提升性能。
  6. 批量操作:大量数据新增/更新时,使用批量API而非循环单条操作,性能差距可达百倍。
  7. 调试必开日志 :开发环境开启 OnLogExecuting 日志,查看生成的SQL,及时发现性能问题。

2. 官方核心资源

  • 官方文档:www.donet5.com/Home/Doc (最全中文文档,持续更新)
  • GitHub 仓库:github.com/DotNetNext/... (源码、Issue、更新日志)
  • 官方视频教程:B站搜索 SqlSugar 官方教程,有完整的入门到进阶视频

3. 常见问题排查

  1. 连接失败:检查连接字符串格式、数据库服务是否启动、网络是否通畅、账号密码是否正确。
  2. 主键自增不生效 :检查实体是否配置 IsPrimaryKey=trueIsIdentity=true,数据库表字段是否设置自增。
  3. 字段映射失败 :检查 SugarColumnColumnName 是否正确,是否开启了 IsIgnore=true
  4. SQL生成异常:开启SQL日志,查看生成的SQL语句,排查表达式是否支持转换为SQL。
  5. 内存溢出/连接泄露 :确认开启了 IsAutoCloseConnection=true,未频繁创建 SqlSugarClient 实例。
相关推荐
AI人工智能+电脑小能手17 分钟前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
yyuuuzz20 分钟前
独立站的技术基础与常见运维问题
大数据·运维·服务器·网络·数据库·aws
红尘散仙32 分钟前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记2 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆2 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪2 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6163 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364573 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao3 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
键盘上的猫头鹰4 小时前
【MySQL 教程(八)】索引、事务、用户管理、导入导出与分页查询
数据库·python·mysql