本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本教程详细讲解如何使用C#语言连接并操作MySQL数据库,涵盖增删改查(CRUD)等基础功能,适合初学者学习数据库编程。通过NuGet安装MySql.Data库并编写数据库连接代码,结合完整代码示例演示用户数据的插入、查询、更新和删除操作。掌握本课程内容可为Web开发和数据驱动型应用开发打下坚实基础。

1. C# 与 MySQL 连接开发环境搭建

在进行 C# 与 MySQL 数据库连接开发之前,需完成基础环境的搭建。本章将引导开发者完成 Visual Studio 的安装与配置、MySQL 数据库的部署,以及必要的 .NET 数据驱动安装。

首先,安装 Visual Studio (推荐 2022 或更高版本),选择 “.NET 桌面开发” 工作负载,确保 C# 开发环境就绪。接着,安装 MySQL Server ,可通过 MySQL 官网下载并安装 MySQL Community Server,并配置 root 用户及权限。

最后,为支持 C# 访问 MySQL,需安装 MySQL Connector/NET ,它提供了 MySql.Data.dll ,用于 C# 项目中操作 MySQL 数据库。

完成上述步骤后,即可进入数据库连接的编码实践。

2. C# 连接 MySQL 的基础配置与实现

在完成开发环境的搭建后,接下来我们进入 C# 与 MySQL 数据库交互的核心阶段。本章将从数据驱动的引入、连接字符串的配置到数据库连接的建立与释放,系统性地讲解 C# 连接 MySQL 的全过程。通过本章内容,开发者将掌握连接数据库的完整流程,并具备构建稳定数据库连接的能力。

2.1 MySQL 数据驱动的引入与使用

在 C# 中操作 MySQL 数据库,首先需要引入对应的数据库驱动程序。MySQL 提供了专门的 .NET 驱动程序:MySQL Connector/NET,它封装了与 MySQL 数据库通信所需的类和方法。本节将详细讲解如何安装和引用该驱动,并解决在引用过程中可能遇到的问题。

2.1.1 安装 MySQL Connector/NET

MySQL Connector/NET 是 MySQL 官方提供的 ADO.NET 驱动,支持与 MySQL 数据库的连接和操作。以下是安装该驱动的两种方式:

方式一:通过 NuGet 安装(推荐)
  1. 打开 Visual Studio。
  2. 右键项目 → 选择“管理 NuGet 包”。
  3. 搜索 MySql.Data
  4. 选择最新版本并点击“安装”。
方式二:手动下载安装
  1. 访问 MySQL 官网下载页面
  2. 下载 MSI 安装包。
  3. 运行安装程序并完成安装。
  4. 在 Visual Studio 中手动添加对 MySql.Data.dll 的引用。

版本说明 :当前主流版本为 8.x,支持 MySQL 8.0 及以上版本,建议使用最新稳定版本。

2.1.2 在 Visual Studio 中引用 MySql.Data.dll

安装完成后,需要在项目中引用 MySql.Data.dll ,这是操作 MySQL 数据库的核心类库。

添加引用步骤:
  1. 在“解决方案资源管理器”中,右键“引用” → 选择“添加引用”。
  2. 点击“浏览” → 定位到安装目录中的 MySql.Data.dll (通常路径为 C:\Program Files (x86)\MySQL\MySQL Connector Net x.x.x\Assemblies\v4.5 )。
  3. 选中该 DLL 文件并点击“添加”。
引用成功后的使用方式:

在代码文件顶部添加如下命名空间引用:

using MySql.Data.MySqlClient;

2.1.3 常见引用错误的排查与解决

在引用 MySql.Data.dll 时,可能会遇到以下几种常见问题:

错误 1:找不到 DLL 或类型或命名空间不存在

解决方法

  • 确认是否成功添加引用。
  • 检查项目目标框架是否为 .NET Framework (Connector/NET 不支持 .NET Core 或 .NET 5+ 的某些版本)。
  • 若使用的是 .NET Core,建议使用 MySql.EntityFrameworkCore Pomelo.EntityFrameworkCore.MySql
错误 2:DLL 版本不兼容

解决方法

  • 确保项目与 DLL 的 .NET Framework 版本一致。
  • 若项目为 x64 架构,需确认引用的 DLL 是否为 64 位版本(MySQL Connector/NET 提供了 x86 与 x64 两个版本)。
错误 3:运行时报错 Could not load file or assembly 'MySql.Data'

解决方法

  • 尝试将 MySql.Data.dll 文件复制到项目的 bin 目录下。
  • 或在项目属性中设置“复制本地”为 True

2.2 数据库连接字符串的配置方法

连接字符串是建立数据库连接的关键参数,它包含数据库服务器地址、端口、用户名、密码、数据库名称等信息。本节将讲解连接字符串的格式、存储方式以及动态构建的技巧。

2.2.1 连接字符串的基本格式与参数说明

MySQL 的连接字符串格式如下:

Server=localhost;Port=3306;Database=testdb;Uid=root;Pwd=yourpassword;
参数名 说明
Server MySQL 服务器地址,如 localhost 或 IP 地址
Port MySQL 服务端口,默认为 3306
Database 要连接的数据库名称
Uid 登录数据库的用户名
Pwd 登录数据库的密码

扩展参数 :还可以添加如 SslMode=none (禁用 SSL)、 Charset=utf8mb4 (设置字符集)等参数。

2.2.2 使用 App.config 存储连接字符串

为了便于管理和修改连接字符串,建议将其存储在 App.config 文件中。

配置步骤:
  1. 在项目中添加 App.config 文件(若无)。
  2. <configuration> 节点下添加如下内容:
<connectionStrings>
    <add name="MySqlConnection" connectionString="Server=localhost;Port=3306;Database=testdb;Uid=root;Pwd=yourpassword;" providerName="MySql.Data.MySqlClient"/>
</connectionStrings>
  1. 在 C# 代码中读取连接字符串:
using System.Configuration;

string connString = ConfigurationManager.ConnectionStrings["MySqlConnection"].ConnectionString;

注意 :需要添加对 System.Configuration 的引用。

2.2.3 动态构建连接字符串的实践技巧

有时我们需要根据用户输入或配置文件动态构建连接字符串。可以使用 MySqlConnectionStringBuilder 类来实现。

示例代码:
MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
builder.Server = "localhost";
builder.Port = 3306;
builder.Database = "testdb";
builder.UserID = "root";
builder.Password = "yourpassword";
builder.SslMode = MySqlSslMode.None;

string dynamicConnString = builder.ConnectionString;

优势 :自动处理特殊字符、空格等,避免拼接错误。

2.3 数据库连接的建立与释放

连接数据库是整个数据库操作的第一步,也是最关键的一步。本节将介绍如何创建 MySqlConnection 对象并打开连接,同时讲解使用 using 语句确保连接释放的最佳实践,并简要介绍连接池技术的原理与配置。

2.3.1 MySqlConnection 对象的创建与打开

要连接 MySQL 数据库,首先需要创建 MySqlConnection 实例,并调用其 Open() 方法打开连接。

示例代码:
string connString = "Server=localhost;Port=3306;Database=testdb;Uid=root;Pwd=yourpassword;";

using (MySqlConnection connection = new MySqlConnection(connString))
{
    try
    {
        connection.Open();
        Console.WriteLine("连接成功!");
    }
    catch (Exception ex)
    {
        Console.WriteLine("连接失败:" + ex.Message);
    }
}
代码逻辑分析:
  • MySqlConnection 是用于连接 MySQL 的核心类。
  • Open() 方法尝试与数据库建立连接。
  • 使用 try-catch 捕获连接异常,防止程序崩溃。

2.3.2 使用 using 语句确保连接释放

数据库连接是有限资源,必须在使用完成后及时释放,否则可能导致连接泄漏或性能下降。C# 提供了 using 语句,用于自动释放实现了 IDisposable 接口的对象。

示例代码:
using (MySqlConnection connection = new MySqlConnection(connString))
{
    connection.Open();
    // 数据库操作
}
// connection 在此自动关闭并释放资源
优势:
  • 自动调用 Dispose() 方法,释放资源。
  • 避免因忘记调用 Close() 而导致的连接未释放问题。

2.3.3 连接池技术的基本原理与配置

MySQL Connector/NET 默认启用了连接池技术。连接池允许在多个请求之间复用数据库连接,从而减少频繁建立和关闭连接的开销,提高系统性能。

连接池原理:
  • 程序首次请求连接时,新建一个数据库连接。
  • 使用完成后,连接不会真正关闭,而是返回连接池。
  • 后续请求将复用池中的连接,避免重复创建。
常用连接池参数:
参数 说明
Pooling=true 启用连接池(默认)
Min Pool Size=5 最小连接池大小
Max Pool Size=100 最大连接池大小
Connection Lifetime=300 连接最大存活时间(秒)
示例连接字符串:
Server=localhost;Database=testdb;Uid=root;Pwd=yourpassword;Pooling=true;Min Pool Size=5;Max Pool Size=100;

建议 :根据系统并发需求合理配置连接池大小,避免资源浪费或瓶颈。

本章小结

本章详细讲解了 C# 连接 MySQL 的基础配置与实现过程。从安装 MySQL Connector/NET 驱动、引用 DLL 文件,到配置连接字符串、建立数据库连接,再到连接池的使用,构建了完整的数据库连接流程。通过本章内容,开发者不仅掌握了连接数据库的必要知识,还了解了连接池等性能优化技巧,为后续的数据库操作打下了坚实的基础。

下章预告 :第三章将深入讲解 C# 中使用 MySqlCommand 执行 SQL 操作,包括参数化查询、异常处理与执行效率优化等内容,敬请期待。

3. C# 中使用 MySqlCommand 执行 SQL 操作

MySqlCommand 是 MySQL Connector/NET 提供的核心类之一,用于在 C# 中执行 SQL 语句,包括查询、更新、插入、删除等操作。本章将深入讲解 MySqlCommand 的使用方式、参数化查询的实现以及 SQL 操作中的常见问题与优化策略。

3.1 MySqlCommand 的基本使用方式

MySqlCommand 类提供了多种方法用于执行 SQL 命令,其中最常用的是 ExecuteNonQuery ExecuteScalar ExecuteReader 。开发者可以根据具体操作类型选择合适的方法。

3.1.1 创建 MySqlCommand 对象并绑定连接

在使用 MySqlCommand 之前,必须先创建一个 MySqlConnection 实例,并打开数据库连接。然后将该连接绑定到 MySqlCommand 对象上。

string connectionString = "Server=localhost;Database=testdb;Uid=root;Pwd=123456;";
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string query = "SELECT * FROM Users";
    using (MySqlCommand cmd = new MySqlCommand(query, conn))
    {
        // 执行查询
    }
}

代码逻辑分析:

  • MySqlConnection 实例化并打开连接;
  • MySqlCommand 构造函数传入 SQL 语句和已打开的连接对象;
  • 使用 using 语句确保命令对象和连接对象在使用完毕后正确释放。

参数说明:
- query :SQL 查询语句;
- conn :已打开的数据库连接对象。

3.1.2 执行非查询语句(ExecuteNonQuery)

ExecuteNonQuery 方法用于执行不返回结果集的 SQL 语句,如 INSERT UPDATE DELETE

string insertQuery = "INSERT INTO Users (Name, Email) VALUES ('Tom', 'tom@example.com')";
using (MySqlCommand cmd = new MySqlCommand(insertQuery, conn))
{
    int rowsAffected = cmd.ExecuteNonQuery();
    Console.WriteLine($"{rowsAffected} 行被插入");
}

执行逻辑说明:

  • 构建插入语句;
  • 调用 ExecuteNonQuery() 执行插入;
  • 返回受影响的行数。

参数说明:
- rowsAffected :返回受影响的记录数,用于判断是否插入成功。

3.1.3 执行标量查询(ExecuteScalar)

当只需要返回一个值(如计数、最大值、平均值等)时,可以使用 ExecuteScalar 方法。

string countQuery = "SELECT COUNT(*) FROM Users";
using (MySqlCommand cmd = new MySqlCommand(countQuery, conn))
{
    object result = cmd.ExecuteScalar();
    if (result != null)
    {
        int count = Convert.ToInt32(result);
        Console.WriteLine($"用户总数为:{count}");
    }
}

执行逻辑说明:

  • 构建返回单个值的 SQL 查询;
  • 调用 ExecuteScalar() 获取结果;
  • 将结果转换为 int 类型并输出。

参数说明:
- result :返回的单个值对象,需要进行类型转换。

3.2 参数化查询的实现

在实际开发中,直接拼接 SQL 语句存在严重的 SQL 注入风险。使用参数化查询不仅可以提升安全性,还能增强代码的可读性和执行效率。

3.2.1 参数化查询的必要性与优势

参数化查询通过将 SQL 语句与参数分离的方式,有效防止 SQL 注入攻击。以下是参数化查询的主要优势:

优势 说明
安全性 防止恶意用户注入恶意 SQL 代码
可读性 SQL 与参数分离,结构更清晰
性能 可重用 SQL 语句,提升执行效率
可维护性 修改参数更方便,无需重构 SQL

3.2.2 添加参数的方式(AddWithValue 与 Add)

有两种常见方式向 MySqlCommand 添加参数:

  1. AddWithValue(推荐用于简单场景)
string query = "INSERT INTO Users (Name, Email) VALUES (@name, @email)";
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
    cmd.Parameters.AddWithValue("@name", "Jerry");
    cmd.Parameters.AddWithValue("@email", "jerry@example.com");
    cmd.ExecuteNonQuery();
}

执行逻辑说明:

  • 使用 @name @email 作为参数占位符;
  • 通过 AddWithValue 添加参数;
  • 执行插入操作。

参数说明:
- @name :SQL 参数名,与代码中定义一致;
- @email :对应 Email 字段的参数。

  1. Add(适合复杂场景或指定类型)
MySqlParameter param = new MySqlParameter("@id", MySqlDbType.Int32);
param.Value = 1;
cmd.Parameters.Add(param);

执行逻辑说明:

  • 显式定义参数类型为 MySqlDbType.Int32
  • 设置参数值;
  • 添加到命令对象中。

3.2.3 防止 SQL 注入的实践案例

假设用户输入如下内容:

Name = "Tom'; DROP TABLE Users;--"

若使用拼接 SQL 的方式:

string sql = "SELECT * FROM Users WHERE Name = '" + inputName + "'";

攻击者将执行以下 SQL:

SELECT * FROM Users WHERE Name = 'Tom'; DROP TABLE Users;--'

而使用参数化查询则完全规避该风险:

string sql = "SELECT * FROM Users WHERE Name = @name";
cmd.Parameters.AddWithValue("@name", inputName);

此时 inputName 会被视为字符串参数,而不会作为 SQL 语句执行。

mermaid流程图说明参数化查询与非参数化查询的区别:

graph TD
    A[用户输入] --> B{是否使用参数化查询?}
    B -->|是| C[参数被安全处理]
    B -->|否| D[拼接SQL存在注入风险]
    C --> E[执行安全查询]
    D --> F[可能执行恶意SQL]

3.3 SQL 语句执行的常见问题与优化

SQL 语句的执行效率和安全性是数据库操作中的关键点。本节将介绍 SQL 拼接的风险、异常处理的必要性以及性能优化技巧。

3.3.1 SQL 语句拼接的风险与规避

直接拼接 SQL 语句容易引入 SQL 注入漏洞。例如:

string sql = "SELECT * FROM Users WHERE Name = '" + txtName.Text + "'";

如果用户输入 ' OR '1'='1 ,则 SQL 变为:

SELECT * FROM Users WHERE Name = '' OR '1'='1'

这将返回所有用户信息。

规避方法:使用参数化查询 (如前所述)

3.3.2 异常处理在 SQL 执行中的作用

在数据库操作中,网络中断、连接失败、权限不足等问题时有发生。良好的异常处理机制可以提升程序的健壮性。

try
{
    using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM NonExistTable", conn))
    {
        using (MySqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                Console.WriteLine(reader["Name"]);
            }
        }
    }
}
catch (MySqlException ex)
{
    Console.WriteLine("MySQL 错误:" + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine("未知错误:" + ex.Message);
}
finally
{
    if (conn.State == ConnectionState.Open)
        conn.Close();
}

执行逻辑说明:

  • try :执行 SQL 查询;
  • catch (MySqlException) :捕获 MySQL 专属异常;
  • catch (Exception) :捕获其他未知异常;
  • finally :确保连接关闭。

参数说明:
- MySqlException :专用于捕获 MySQL 错误;
- Message :错误描述信息。

3.3.3 提升执行效率的小技巧

提升 SQL 执行效率可以从多个方面入手:

技巧 说明
使用 using 管理资源 自动释放数据库连接、命令、读取器等资源
合理使用索引 在经常查询的字段上建立索引
批量操作 减少数据库往返次数,如批量插入
避免 SELECT * 只选择需要的字段,减少数据传输量
分页查询 大数据量时使用分页减少一次性查询的数据量

示例:使用批量插入提升性能

string query = "INSERT INTO Users (Name, Email) VALUES (@name, @email)";
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
    for (int i = 0; i < 1000; i++)
    {
        cmd.Parameters.Clear();
        cmd.Parameters.AddWithValue("@name", "User" + i);
        cmd.Parameters.AddWithValue("@email", $"user{i}@example.com");
        cmd.ExecuteNonQuery();
    }
}

执行逻辑说明:

  • 使用循环插入 1000 条记录;
  • 每次插入前清除旧参数;
  • 使用 ExecuteNonQuery 执行插入。

优化建议:
- 使用事务包裹整个插入操作;
- 使用 MySqlBulkCopy 或存储过程进行批量插入。

通过本章的学习,开发者可以掌握 MySqlCommand 的基本用法、参数化查询的实现方式以及 SQL 操作中的常见问题与优化策略。下一章将继续深入讲解 C# 中的数据库 CRUD 操作,帮助开发者构建完整的数据库应用系统。

4. 使用 C# 实现数据库的 CRUD 操作

在 C# 与 MySQL 的数据库编程中,CRUD(Create、Read、Update、Delete)操作是最基础、最核心的内容。通过实现这些操作,开发者能够完成对数据库中数据的增删改查,构建完整的业务逻辑。本章将深入探讨如何使用 C# 编写代码实现这些操作,并介绍事务处理、数据读取方式、条件控制等关键技术点,帮助开发者构建高效、安全的数据库交互程序。

4.1 数据插入(Create)操作

4.1.1 插入单条数据的实现方式

在 C# 中,插入单条数据通常使用 MySqlCommand 对象执行 INSERT SQL 语句。为确保数据一致性,建议使用参数化查询防止 SQL 注入攻击。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string query = "INSERT INTO users (name, email, created_at) VALUES (@name, @email, @created_at)";
    using (MySqlCommand cmd = new MySqlCommand(query, conn))
    {
        cmd.Parameters.AddWithValue("@name", "张三");
        cmd.Parameters.AddWithValue("@email", "zhangsan@example.com");
        cmd.Parameters.AddWithValue("@created_at", DateTime.Now);

        int rowsAffected = cmd.ExecuteNonQuery();
        Console.WriteLine($"插入成功,影响行数:{rowsAffected}");
    }
}

代码解析:

  • MySqlConnection :用于连接 MySQL 数据库。
  • MySqlCommand :执行 SQL 命令。
  • Parameters.AddWithValue :添加参数,防止 SQL 注入。
  • ExecuteNonQuery :执行插入、更新或删除操作,返回受影响的行数。

参数说明:

  • @name @email @created_at :SQL 中的命名参数,与 cmd.Parameters 中的值对应。

4.1.2 插入多条数据的事务处理

当需要一次性插入多条数据时,为了保证数据一致性,应使用事务(Transaction)来控制操作的原子性。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    using (MySqlTransaction transaction = conn.BeginTransaction())
    {
        try
        {
            string query = "INSERT INTO users (name, email, created_at) VALUES (@name, @email, @created_at)";
            using (MySqlCommand cmd = new MySqlCommand(query, conn, transaction))
            {
                // 插入第一条数据
                cmd.Parameters.AddWithValue("@name", "李四");
                cmd.Parameters.AddWithValue("@email", "lisi@example.com");
                cmd.Parameters.AddWithValue("@created_at", DateTime.Now);
                cmd.ExecuteNonQuery();

                // 插入第二条数据
                cmd.Parameters["@name"].Value = "王五";
                cmd.Parameters["@email"].Value = "wangwu@example.com";
                cmd.ExecuteNonQuery();
            }

            transaction.Commit();
            Console.WriteLine("多条数据插入成功");
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine($"插入失败,事务回滚:{ex.Message}");
        }
    }
}

事务流程图:

graph TD
    A[开始事务] --> B[执行插入操作]
    B --> C{是否全部成功?}
    C -- 是 --> D[提交事务]
    C -- 否 --> E[回滚事务]
    D --> F[操作完成]
    E --> G[异常处理]

事务处理关键点:

  • 使用 BeginTransaction() 启动事务。
  • 所有 MySqlCommand 必须绑定该事务。
  • 成功则 Commit() 提交,失败则 Rollback() 回滚。

4.1.3 获取插入后的自增主键值

在数据库设计中,常使用自增主键(如 AUTO_INCREMENT )。插入数据后,可通过 LAST_INSERT_ID() 函数获取最后插入的主键值。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string insertQuery = "INSERT INTO users (name, email, created_at) VALUES (@name, @email, @created_at)";
    string lastIdQuery = "SELECT LAST_INSERT_ID()";

    using (MySqlCommand cmd = new MySqlCommand(insertQuery, conn))
    {
        cmd.Parameters.AddWithValue("@name", "赵六");
        cmd.Parameters.AddWithValue("@email", "zhaoliu@example.com");
        cmd.Parameters.AddWithValue("@created_at", DateTime.Now);
        cmd.ExecuteNonQuery();

        cmd.CommandText = lastIdQuery;
        object result = cmd.ExecuteScalar();
        int userId = Convert.ToInt32(result);
        Console.WriteLine($"插入成功,新用户ID为:{userId}");
    }
}

代码说明:

  • ExecuteScalar() :执行查询并返回第一行第一列的值。
  • LAST_INSERT_ID() :MySQL 提供的函数,用于获取最近一次插入的自增主键。

4.2 数据查询(Read)操作

4.2.1 使用 MySqlDataReader 读取数据

MySqlDataReader 是一种轻量级的数据读取器,适合一次性顺序读取大量数据。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string query = "SELECT id, name, email FROM users";
    using (MySqlCommand cmd = new MySqlCommand(query, conn))
    {
        using (MySqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                int id = reader.GetInt32("id");
                string name = reader.GetString("name");
                string email = reader.IsDBNull(reader.GetOrdinal("email")) ? null : reader.GetString("email");

                Console.WriteLine($"ID: {id}, 姓名: {name}, 邮箱: {email ?? "无"}");
            }
        }
    }
}

特点:

  • 只读、顺序访问。
  • 占用资源少,适合大数据量场景。
  • 无法直接绑定控件,需手动处理数据。

4.2.2 使用 DataTable 存储查询结果

DataTable 是一个内存中的数据表结构,适合需要多次访问、绑定控件的场景。

DataTable table = new DataTable();
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string query = "SELECT * FROM users";
    using (MySqlCommand cmd = new MySqlCommand(query, conn))
    {
        using (MySqlDataAdapter adapter = new MySqlDataAdapter(cmd))
        {
            adapter.Fill(table);
        }
    }
}

foreach (DataRow row in table.Rows)
{
    Console.WriteLine($"ID: {row["id"]}, 姓名: {row["name"]}, 邮箱: {row["email"]}");
}

对比表格:

特性 MySqlDataReader DataTable
访问方式 顺序读取 随机访问
数据来源 来自数据库流式读取 全部加载到内存
内存占用 较低 较高
控件绑定支持 不支持 支持
性能 更快 稍慢

4.2.3 查询结果的绑定与展示技巧

将数据绑定到 UI 控件(如 DataGridView )时, DataTable 是首选。

dataGridView1.DataSource = table;

绑定技巧:

  • 使用 BindingSource 可以实现数据导航。
  • 设置 AutoGenerateColumns = true 自动创建列。
  • 使用 DefaultCellStyle 设置列样式。

4.3 数据更新(Update)操作

4.3.1 单表更新的实现逻辑

更新操作使用 UPDATE 语句,并通过 WHERE 子句定位目标记录。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string query = "UPDATE users SET email = @email WHERE id = @id";
    using (MySqlCommand cmd = new MySqlCommand(query, conn))
    {
        cmd.Parameters.AddWithValue("@email", "newemail@example.com");
        cmd.Parameters.AddWithValue("@id", 1);

        int rowsAffected = cmd.ExecuteNonQuery();
        Console.WriteLine($"更新成功,影响行数:{rowsAffected}");
    }
}

参数说明:

  • @email :要更新的新邮箱地址。
  • @id :用于定位需要更新的记录。

4.3.2 多条件更新的处理方式

在复杂业务中,可能需要多个条件来筛选更新目标。

string query = "UPDATE users SET name = @name WHERE id = @id AND status = @status";
cmd.Parameters.AddWithValue("@name", "新名字");
cmd.Parameters.AddWithValue("@id", 1);
cmd.Parameters.AddWithValue("@status", "active");

逻辑分析:

  • WHERE id = @id AND status = @status :确保只有处于活跃状态的用户才会被更新。

4.3.3 更新操作的事务保障

为防止更新过程中发生异常导致数据不一致,应使用事务机制。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    using (MySqlTransaction transaction = conn.BeginTransaction())
    {
        try
        {
            using (MySqlCommand cmd = new MySqlCommand("UPDATE users SET name = @name WHERE id = @id", conn, transaction))
            {
                cmd.Parameters.AddWithValue("@name", "新名字");
                cmd.Parameters.AddWithValue("@id", 1);
                cmd.ExecuteNonQuery();
            }

            transaction.Commit();
            Console.WriteLine("更新成功");
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine($"更新失败:{ex.Message}");
        }
    }
}

4.4 数据删除(Delete)操作

4.4.1 删除单条记录的实现

删除操作使用 DELETE 语句,并通过 WHERE 指定删除条件。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    string query = "DELETE FROM users WHERE id = @id";
    using (MySqlCommand cmd = new MySqlCommand(query, conn))
    {
        cmd.Parameters.AddWithValue("@id", 1);
        int rowsAffected = cmd.ExecuteNonQuery();
        Console.WriteLine($"删除成功,影响行数:{rowsAffected}");
    }
}

4.4.2 条件删除与软删除策略

硬删除(Hard Delete) :直接从表中删除数据。

软删除(Soft Delete) :通过字段标记删除状态,而非真正删除记录。

ALTER TABLE users ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE;
string query = "UPDATE users SET is_deleted = TRUE WHERE id = @id";

软删除优势:

  • 数据可恢复。
  • 保留操作日志。
  • 避免外键约束冲突。

4.4.3 删除操作的事务与回滚机制

与更新操作类似,删除也应使用事务保障数据一致性。

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    using (MySqlTransaction transaction = conn.BeginTransaction())
    {
        try
        {
            using (MySqlCommand cmd = new MySqlCommand("DELETE FROM users WHERE id = @id", conn, transaction))
            {
                cmd.Parameters.AddWithValue("@id", 2);
                cmd.ExecuteNonQuery();
            }

            transaction.Commit();
            Console.WriteLine("删除操作提交");
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine($"删除操作回滚:{ex.Message}");
        }
    }
}

事务流程总结:

  • 启动事务。
  • 执行删除操作。
  • 成功提交,失败回滚。

小提示:
在开发中,建议优先使用软删除策略,并结合日志记录删除操作,以增强系统安全性与可追溯性。

本章深入讲解了 C# 中实现 MySQL 数据库 CRUD 操作的具体方法,包括参数化插入、事务处理、数据读取方式、更新与删除逻辑,以及软删除策略等关键内容。下一章将聚焦数据库操作中的异常处理与数据绑定技术,为构建健壮的应用系统打下基础。

5. 数据库操作中的异常处理与数据处理技术

在 C# 与 MySQL 的数据库交互过程中,异常处理和数据处理是构建健壮应用程序的关键环节。数据库操作中可能遇到各种异常,例如连接失败、查询语法错误、超时等;而数据处理则涉及从数据库中读取数据、在程序中进行操作以及最终的数据展示。本章将深入探讨如何有效处理数据库操作中的异常,以及使用 DataTable 和 DataReader 等核心对象进行高效的数据处理和展示。

5.1 数据库操作的异常处理机制

在数据库开发中,异常是不可避免的。良好的异常处理机制不仅能提升程序的健壮性,还能改善用户体验。C# 提供了 try-catch-finally 语句结构,使得我们可以优雅地捕获和处理异常。

5.1.1 try-catch-finally 的使用方式

try-catch-finally 是 C# 中用于异常处理的标准结构。try 块中包含可能抛出异常的代码,catch 块用于捕获并处理异常,finally 块则用于执行无论是否发生异常都必须执行的清理代码,如关闭数据库连接。

using System;
using MySql.Data.MySqlClient;

class Program
{
    static void Main()
    {
        string connectionString = "server=localhost;database=testdb;uid=root;password=123456;";
        MySqlConnection connection = null;

        try
        {
            connection = new MySqlConnection(connectionString);
            connection.Open();
            Console.WriteLine("数据库连接成功。");

            // 执行数据库操作
            MySqlCommand command = new MySqlCommand("SELECT * FROM users", connection);
            MySqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                Console.WriteLine(reader["username"]);
            }
        }
        catch (MySqlException ex)
        {
            Console.WriteLine($"数据库异常:{ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"通用异常:{ex.Message}");
        }
        finally
        {
            if (connection != null && connection.State == System.Data.ConnectionState.Open)
            {
                connection.Close();
                Console.WriteLine("数据库连接已关闭。");
            }
        }
    }
}

逐行解读分析:

  • try 块尝试打开数据库连接并执行查询操作。
  • 第一个 catch 捕获 MySqlException ,即特定于 MySQL 的异常,如连接失败、查询错误等。
  • 第二个 catch 捕获所有其他类型的异常,例如类型转换错误、空引用等。
  • finally 块确保数据库连接始终被关闭,无论是否发生异常。

5.1.2 捕获特定数据库异常类型

在数据库编程中,我们通常希望对不同类型的异常进行不同的处理。MySQL 提供了多种异常类型,如:

  • MySqlException :表示与 MySQL 数据库交互时发生的错误。
  • MySqlException 包含错误码( Number 属性)和错误信息( Message 属性),可用于判断错误类型。

以下是一个捕获特定错误码的示例:

catch (MySqlException ex)
{
    switch (ex.Number)
    {
        case 0:
            Console.WriteLine("无法连接到数据库服务器。");
            break;
        case 1045:
            Console.WriteLine("访问被拒绝,用户名或密码错误。");
            break;
        default:
            Console.WriteLine($"数据库错误:{ex.Message}");
            break;
    }
}

参数说明:

  • ex.Number 是 MySQL 提供的错误编号,例如 1045 表示认证失败。
  • 通过判断不同的错误编号,我们可以提供更具体的错误提示。

5.1.3 记录异常日志与用户提示

在实际项目中,仅在控制台输出错误信息是不够的。我们需要将异常记录到日志文件中,并向用户提供友好的提示。

推荐做法:

  • 使用 NLog 或 log4net 等日志框架记录异常。
  • 使用 MessageBox(在 WinForm 应用中)或前端提示(在 Web 应用中)通知用户。

示例:记录日志并提示用户

catch (MySqlException ex)
{
    File.WriteAllText("error.log", $"数据库异常:{ex.Message},时间:{DateTime.Now}");
    MessageBox.Show("数据库连接失败,请稍后重试。");
}

逻辑分析:

  • 使用 File.WriteAllText 将异常信息写入日志文件。
  • 使用 MessageBox.Show 向用户显示友好的提示信息,提升用户体验。

5.2 数据处理对象 DataTable 与 DataReader

在 C# 中,我们通常使用 DataTable MySqlDataReader 两种方式来处理数据库查询结果。它们各有优缺点,适用于不同的场景。

5.2.1 DataTable 的结构与操作方法

DataTable 是内存中的数据表结构,可以独立于数据库存在。它支持行、列的操作,适合需要对数据进行复杂处理的场景。

DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter("SELECT * FROM users", connection);
adapter.Fill(table);

逐行解读分析:

  • DataTable table = new DataTable(); 创建一个空的数据表。
  • MySqlDataAdapter 是一个适配器对象,用于填充 DataTable。
  • adapter.Fill(table); 将查询结果填充到 DataTable 中。

DataTable 的常用操作:

操作 说明
table.Rows.Add(...) 添加新行
table.Rows[i].Delete() 删除某一行
table.AcceptChanges() 提交更改
table.Select("username='admin'") 查询符合条件的行

5.2.2 DataReader 的读取特性与限制

MySqlDataReader 是一种只进、只读的数据读取器,适用于只需要顺序读取数据的场景。它比 DataTable 更节省内存,但灵活性较差。

MySqlCommand command = new MySqlCommand("SELECT * FROM users", connection);
MySqlDataReader reader = command.ExecuteReader();

while (reader.Read())
{
    Console.WriteLine(reader["username"]);
}

逐行解读分析:

  • command.ExecuteReader() 返回一个 MySqlDataReader 对象。
  • reader.Read() 逐行读取数据,返回 false 表示读取完毕。
  • reader["username"] 获取当前行的 username 字段。

DataReader 的限制:

限制 说明
只读 不能修改数据
只进 不能反向读取(不能回滚)
必须保持连接 在读取过程中数据库连接必须保持打开状态

5.2.3 DataTable 与 DataReader 的性能对比

对比项 DataTable DataReader
内存占用 较高 较低
灵活性 高(支持增删改查) 低(只读)
适用场景 数据处理、绑定控件 快速读取大量数据
性能 相对较慢 更快
是否需要保持连接 否(填充后可关闭连接)
graph TD
    A[数据库查询] --> B{选择数据处理方式}
    B -->|DataTable| C[数据绑定控件]
    B -->|DataReader| D[快速读取数据]
    C --> E[支持修改与操作]
    D --> F[只读,节省资源]

逻辑分析:

  • 如果需要对数据进行绑定或修改,建议使用 DataTable
  • 如果仅需要快速读取数据,建议使用 MySqlDataReader

5.3 数据绑定与展示技术

将数据库查询结果展示在用户界面中是数据库应用的重要组成部分。C# 提供了多种数据绑定机制,可以将 DataTable、DataReader 等数据源绑定到控件中。

5.3.1 将数据绑定到 DataGridView 控件

DataGridView 是 WinForm 中用于展示表格数据的常用控件。我们可以将 DataTable 绑定到 DataGridView 上。

DataTable table = GetUsers(); // 获取数据的方法
dataGridView1.DataSource = table;

逻辑分析:

  • GetUsers() 返回一个包含用户信息的 DataTable。
  • dataGridView1.DataSource = table; 将 DataTable 设置为 DataGridView 的数据源。

绑定效果:

ID username email
1 admin admin@example.com
2 user1 user1@example.com

5.3.2 使用 BindingSource 实现数据导航

BindingSource 是一个数据绑定组件,它可以实现数据导航、排序、筛选等功能。

BindingSource bs = new BindingSource();
bs.DataSource = table;
bindingNavigator1.BindingSource = bs;
dataGridView1.DataSource = bs;

参数说明:

  • BindingSource 作为中介,将数据源绑定到多个控件上。
  • bindingNavigator1 是一个导航控件,可以实现“上一条”、“下一条”等操作。

优势:

  • 实现数据导航功能。
  • 支持排序和筛选。
  • 可与多个控件共享数据源。

5.3.3 数据格式化与显示优化

为了提升用户体验,我们可以对数据进行格式化展示。例如日期字段可以格式化为“yyyy-MM-dd”。

dataGridView1.Columns["created_at"].DefaultCellStyle.Format = "yyyy-MM-dd";

逻辑分析:

  • DefaultCellStyle.Format 设置列的显示格式。
  • 支持的格式字符串包括:日期、时间、数字、货币等。

优化技巧:

技巧 说明
列宽自动调整 dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
隐藏列 dataGridView1.Columns["password"].Visible = false;
自定义列标题 dataGridView1.Columns["username"].HeaderText = "用户名";
graph LR
    A[数据源 DataTable] --> B[绑定到 BindingSource]
    B --> C[绑定到 DataGridView]
    B --> D[绑定到 BindingNavigator]
    C --> E[显示数据]
    D --> F[实现导航]

流程分析:

  • BindingSource 作为中间桥梁,连接数据源与多个 UI 控件。
  • DataGridView 显示数据,BindingNavigator 提供导航功能。

本章从异常处理机制入手,详细讲解了 try-catch-finally 的使用方式、特定异常的捕获及日志记录技巧。随后,深入探讨了 DataTable 和 DataReader 的结构、使用方式及性能对比,并通过代码示例展示了其应用场景。最后,介绍了数据绑定与展示技术,包括 DataGridView 控件的绑定、BindingSource 的使用以及数据格式化的优化技巧,帮助开发者构建稳定、高效、用户友好的数据库应用。

6. C# 与 MySQL CRUD 操作的完整实战应用

6.1 实战项目需求与功能规划

在本节中,我们将设计一个完整的数据库操作项目,以演示如何在 C# 应用程序中实现对 MySQL 数据库的增删改查(CRUD)功能。项目目标是开发一个“学生信息管理系统”,支持以下核心功能:

  • 学生信息的录入(Create)
  • 学生信息的查询(Read)
  • 学生信息的修改(Update)
  • 学生信息的删除(Delete)

6.1.1 应用场景与功能模块设计

该系统主要面向学校教务管理,适用于小型学校或班级管理。系统将提供一个图形化界面,允许用户通过按钮操作完成对数据库中学生信息的管理。

功能模块划分如下:

模块名称 功能描述
数据访问层(DAL) 负责与数据库交互,执行增删改查操作
业务逻辑层(BLL) 封装数据处理逻辑,如验证、计算等
表现层(UI) 提供用户交互界面,接收输入并展示结果

6.1.2 数据库表结构设计与建模

我们将使用 MySQL 创建一个名为 school 的数据库,并在其中建立一个 students 表,结构如下:

CREATE DATABASE school;

USE school;

CREATE TABLE students (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT,
    gender ENUM('男', '女') NOT NULL,
    class VARCHAR(50),
    score DECIMAL(5,2)
);

字段说明如下:

字段名 类型 描述
id INT 学生唯一标识
name VARCHAR(100) 姓名
age INT 年龄
gender ENUM 性别
class VARCHAR(50) 所属班级
score DECIMAL(5,2) 成绩

6.1.3 系统界面与交互逻辑概述

用户界面采用 Windows Forms 设计,包含以下主要控件:

  • TextBox :用于输入姓名、年龄、班级、成绩
  • ComboBox :选择性别
  • DataGridView :展示所有学生数据
  • Button :新增、修改、删除、查询按钮

交互流程如下:

  1. 用户输入信息并点击“新增”按钮,数据插入数据库;
  2. 点击“查询”按钮,刷新 DataGridView 展示所有学生数据;
  3. 选择某一行点击“修改”或“删除”,更新或删除数据库记录;
  4. 所有操作均通过 BLL 和 DAL 分层完成。

6.2 模块化开发与代码组织结构

本节介绍如何采用三层架构(UI、BLL、DAL)来组织项目结构,提升代码的可维护性和可扩展性。

6.2.1 数据访问层(DAL)的设计与实现

DAL 文件夹中创建 StudentDAL.cs 类,用于执行与数据库的交互操作:

using MySql.Data.MySqlClient;
using System;
using System.Data;

namespace StudentSystem.DAL
{
    public class StudentDAL
    {
        private string connectionString = "server=localhost;database=school;user=root;password=123456;";

        // 查询所有学生
        public DataTable GetAllStudents()
        {
            using (MySqlConnection conn = new MySqlConnection(connectionString))
            {
                conn.Open();
                string sql = "SELECT * FROM students";
                MySqlDataAdapter adapter = new MySqlDataAdapter(sql, conn);
                DataTable table = new DataTable();
                adapter.Fill(table);
                return table;
            }
        }

        // 插入学生数据
        public int InsertStudent(string name, int age, string gender, string @class, decimal score)
        {
            using (MySqlConnection conn = new MySqlConnection(connectionString))
            {
                conn.Open();
                string sql = "INSERT INTO students (name, age, gender, class, score) VALUES (@name, @age, @gender, @class, @score)";
                MySqlCommand cmd = new MySqlCommand(sql, conn);
                cmd.Parameters.AddWithValue("@name", name);
                cmd.Parameters.AddWithValue("@age", age);
                cmd.Parameters.AddWithValue("@gender", gender);
                cmd.Parameters.AddWithValue("@class", @class);
                cmd.Parameters.AddWithValue("@score", score);
                return cmd.ExecuteNonQuery();
            }
        }

        // 更新学生数据
        public int UpdateStudent(int id, string name, int age, string gender, string @class, decimal score)
        {
            using (MySqlConnection conn = new MySqlConnection(connectionString))
            {
                conn.Open();
                string sql = "UPDATE students SET name=@name, age=@age, gender=@gender, class=@class, score=@score WHERE id=@id";
                MySqlCommand cmd = new MySqlCommand(sql, conn);
                cmd.Parameters.AddWithValue("@id", id);
                cmd.Parameters.AddWithValue("@name", name);
                cmd.Parameters.AddWithValue("@age", age);
                cmd.Parameters.AddWithValue("@gender", gender);
                cmd.Parameters.AddWithValue("@class", @class);
                cmd.Parameters.AddWithValue("@score", score);
                return cmd.ExecuteNonQuery();
            }
        }

        // 删除学生数据
        public int DeleteStudent(int id)
        {
            using (MySqlConnection conn = new MySqlConnection(connectionString))
            {
                conn.Open();
                string sql = "DELETE FROM students WHERE id=@id";
                MySqlCommand cmd = new MySqlCommand(sql, conn);
                cmd.Parameters.AddWithValue("@id", id);
                return cmd.ExecuteNonQuery();
            }
        }
    }
}

6.2.2 业务逻辑层(BLL)的功能封装

BLL 文件夹中创建 StudentBLL.cs 类,用于处理业务逻辑:

using StudentSystem.DAL;
using System.Data;

namespace StudentSystem.BLL
{
    public class StudentBLL
    {
        private StudentDAL dal = new StudentDAL();

        public DataTable GetAllStudents()
        {
            return dal.GetAllStudents();
        }

        public int AddStudent(string name, int age, string gender, string @class, decimal score)
        {
            return dal.InsertStudent(name, age, gender, @class, score);
        }

        public int ModifyStudent(int id, string name, int age, string gender, string @class, decimal score)
        {
            return dal.UpdateStudent(id, name, age, gender, @class, score);
        }

        public int RemoveStudent(int id)
        {
            return dal.DeleteStudent(id);
        }
    }
}

6.2.3 表现层(UI)的控件布局与交互

Form1.cs 中添加以下控件并编写事件处理代码:

using StudentSystem.BLL;
using System;
using System.Windows.Forms;

namespace StudentSystem.UI
{
    public partial class Form1 : Form
    {
        private StudentBLL bll = new StudentBLL();

        public Form1()
        {
            InitializeComponent();
            LoadData();
        }

        private void LoadData()
        {
            dataGridView1.DataSource = bll.GetAllStudents();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            string name = txtName.Text;
            int age = int.Parse(txtAge.Text);
            string gender = cmbGender.SelectedItem.ToString();
            string @class = txtClass.Text;
            decimal score = decimal.Parse(txtScore.Text);

            bll.AddStudent(name, age, gender, @class, score);
            LoadData();
        }

        private void btnUpdate_Click(object sender, EventArgs e)
        {
            int id = int.Parse(txtID.Text);
            string name = txtName.Text;
            int age = int.Parse(txtAge.Text);
            string gender = cmbGender.SelectedItem.ToString();
            string @class = txtClass.Text;
            decimal score = decimal.Parse(txtScore.Text);

            bll.ModifyStudent(id, name, age, gender, @class, score);
            LoadData();
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            int id = int.Parse(txtID.Text);
            bll.RemoveStudent(id);
            LoadData();
        }

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0)
            {
                DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
                txtID.Text = row.Cells["id"].Value.ToString();
                txtName.Text = row.Cells["name"].Value.ToString();
                txtAge.Text = row.Cells["age"].Value.ToString();
                cmbGender.SelectedItem = row.Cells["gender"].Value.ToString();
                txtClass.Text = row.Cells["class"].Value.ToString();
                txtScore.Text = row.Cells["score"].Value.ToString();
            }
        }
    }
}

6.3 CRUD 完整流程的集成与测试

6.3.1 功能模块的集成测试

将 UI、BLL、DAL 各模块集成后,测试以下流程:

  1. 点击“新增”按钮,插入一条学生记录;
  2. 点击“查询”,确认数据已正确显示在 DataGridView
  3. 修改某条记录后点击“修改”,验证数据是否更新;
  4. 选择某条记录点击“删除”,验证数据是否被删除。

6.3.2 性能优化与异常处理完善

  • 连接池优化 :确保 MySqlConnection 使用 using 语句自动释放,避免资源泄漏。
  • SQL 参数化 :所有操作均使用参数化查询,防止 SQL 注入。
  • 异常处理增强 :在 DAL 层添加 try-catch ,捕获数据库异常并返回错误提示。
// 修改 DAL 中的插入方法
public int InsertStudent(string name, int age, string gender, string @class, decimal score)
{
    try
    {
        using (MySqlConnection conn = new MySqlConnection(connectionString))
        {
            conn.Open();
            string sql = "INSERT INTO students (name, age, gender, class, score) VALUES (@name, @age, @gender, @class, @score)";
            MySqlCommand cmd = new MySqlCommand(sql, conn);
            cmd.Parameters.AddWithValue("@name", name);
            cmd.Parameters.AddWithValue("@age", age);
            cmd.Parameters.AddWithValue("@gender", gender);
            cmd.Parameters.AddWithValue("@class", @class);
            cmd.Parameters.AddWithValue("@score", score);
            return cmd.ExecuteNonQuery();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("数据库操作失败:" + ex.Message);
        return -1;
    }
}

6.3.3 系统打包与部署发布流程

  1. 在 Visual Studio 中右键项目 → “发布”;
  2. 选择目标平台(如 Windows 桌面);
  3. 设置安装包输出路径;
  4. 配置应用程序名称、图标、安装路径;
  5. 生成 .exe 安装包;
  6. 在目标机器上安装并运行,确保 MySQL 服务已启动,连接字符串配置正确。

提示 :若目标机器没有 MySQL,可将连接字符串改为远程数据库地址,实现跨机器访问。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本教程详细讲解如何使用C#语言连接并操作MySQL数据库,涵盖增删改查(CRUD)等基础功能,适合初学者学习数据库编程。通过NuGet安装MySql.Data库并编写数据库连接代码,结合完整代码示例演示用户数据的插入、查询、更新和删除操作。掌握本课程内容可为Web开发和数据驱动型应用开发打下坚实基础。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐