欢迎来到 安卓源码空间!
安卓源码空间

                                        C#— —数据库访问技术



本文主要介绍在C#中如何访问和操作数据库。



1. ADO .NET介绍

ADO .NET是在.NET Framework上访问、操作多种数据源的一组类库。

ADO .NET分为两个部分:数据访问和数据操作。数据访问主要由数据提供者(Data Provider)负责,数据操作主要由DataSet类负责。ADO .NET的类主要定义在System.Data中。数据访问和数据操作可以独立使用,也可以一前一后进行使用。

1.1 Data Provider

ADO .NET为数据访问提供了标准接口,只要数据库管理系统的各个厂商(MySQL、Oracle等)提供实现了标准接口的数据提供者(Data Provider),那么只要在项目中引入相关的数据提供者依赖,我们就可以使用ADO .NET规定的标准接口进行数据库连接、执行命令和获取结果等操作。

ADO .NET定义的标准接口主要有以下几种:

  • IDbConnection:表示与数据源的连接,数据提供者需要实现该接口以连接数据库;
  • IDbCommand:表示执行 SQL 命令,数据提供者需要实现该接口以进行数据库操作,并返回结果;
  • IDbDataAdapter:表示一组与命令相关的属性,用于填充数据集并更新数据源,数据提供者需要实现该接口;
  • IDataReader:通过IDbCommand从数据源获取数据流,只能在该流上进行只读操作,数据提供者需要实现该接口;

命名空间System.Data.Common提供了上述接口的一些实现,如:

public abstract class DbConnection : System.ComponentModel.Component, IDisposable, System.Data.IDbConnection
public abstract class DbCommand : System.ComponentModel.Component, IDisposable, System.Data.IDbCommand
public abstract class DbDataAdapter : System.Data.Common.DataAdapter, ICloneable, System.Data.IDbDataAdapter
public abstract class DbDataReader : MarshalByRefObject, IDisposable, System.Collections.IEnumerable, System.Data.IDataReader

我们以DbConnection为例,介绍该命名空间中抽象基类的作用:

DbConnection定义了数据库连接的核心行为,并且为具体数据库的连接提供了一个基类。

如果要继承该类,则需要重写如下成员:

Close()
BeginDbTransaction(IsolationLevel)
ChangeDatabase(String)
CreateDbCommand()
Open()
StateChange.

同时,子类也必须提供如下属性:

ConnectionString
Database
DataSource
ServerVersion,
State

对于具体的数据库厂商,他们的数据提供者可以继承上述的基类,并且根据标准重写对应的方法以及提供具体的属性。以MySQL为例,有数据提供者MySQL.Data,它的具体实现类如下:

public sealed class MySqlConnection : DbConnection, ICloneable
public sealed class MySqlCommand : DbCommand, IDisposable, ICloneable
public sealed class MySqlDataAdapter : DbDataAdapter, IDbDataAdapter, IDataAdapter
public sealed class MySqlDataReader : DbDataReader, IDataReader, IDataRecord, IDisposable

只要引入MySQL.Data依赖,我们就可以在项目中,根据ADO .NET提供的标准接口进行数据库访问了。

同理,引入其他数据库的数据提供者依赖,就可以访问对应的数据库了。

1.2 DataSet

DataSet主要用于在内存中暂存并处理各种从数据源中取回的数据,如同在内存中的数据库管理系统。

DataSet中的数据必须通过DataAdapter对象与数据库进行数据交换。在DataSet内部允许同时存放一个或多个DataTable对象,DataTable由一个或多个DataRow、DataColumn组成,并包含PrimaryKey、Relations、Constraints等:

在这里插入图片描述

1.3 ADO .NET 访问数据库的流程

ADO .NET访问数据库的一般流程如下:

  1. 建立数据库连接对象-Connection;
  2. 在建立连接的基础上,可以使用Command对象对数据库发生查询、新增、修改和删除等命令;
  3. 创建DataAdapter对象,从数据库中取得数据;
  4. 创建DataSet对象,将DataAdapter对象填充到DataSet对象中;
  5. 如果需要,可以重复操作,即在一个DataSet对象中容纳多个数据集合;
  6. 关闭数据连接;
  7. 在DataSet上进行离线数据操作;

2. 操作MySQL数据库

2.1 MySQL下载安装

此处不再详细讲解MySQL的下载安装,下载链接:MySQL :: Download MySQL Installer

在这里插入图片描述

安装完成后,进入MySQL如下:

在这里插入图片描述

2.2 C#操作MySQL数据库

2.2.1 添加MySQL.Data.dll

首先在项目中添加MySQL.Data.dll动态链接库,这个文件可以在目录:C:\Program Files (x86)\MySQL\Connector NET 8.0\Assemblies\v4.5.2下找到:

在这里插入图片描述

我们可以将本地的动态链接库添加到项目中,也可以使用NuGet进行引入:

在这里插入图片描述

单击下载后,在我们的项目依赖项中就有如下包了:

在这里插入图片描述

2.2.2 连接数据库

连接数据库主要的类是MySqlConnection,其构造函数如下:

  • public MySqlConnection();:无参构造函数,连接数据库的值都是默认值;
  • public MySqlConnection(string connectionString);:根据连接字符串构造数据库连接;

连接数据库示例如下:

// 连接字符串
String connectionString = "server=127.0.0.1;port=3306;user=root;password=root;database=test;";
// 创建数据库连接
MySqlConnection mySqlConnection = new MySqlConnection(connectionString);
// 打开连接
mySqlConnection.Open();
// 获取数据库版本
Console.WriteLine(mySqlConnection.ServerVersion);  //8.0.25
// 关闭连接
mySqlConnection.Close();

当然,连接字符串很长,我们可能记不住,我们可以使用MySqlConnectionStringBuilder帮助我们创建数据库连接:

// 创建MySqlConnectionStringBuilder对象
MySqlConnectionStringBuilder mySqlConnectionStringBuilder = new MySqlConnectionStringBuilder();// 依次传入连接数据库的属性
mySqlConnectionStringBuilder.Server = "localhost";
mySqlConnectionStringBuilder.Port = 3306;
mySqlConnectionStringBuilder.Database = "test";
mySqlConnectionStringBuilder.UserID = "root";
mySqlConnectionStringBuilder.Password = "root";
// 获取连接数据库的字符串
String connectionString = mySqlConnectionStringBuilder.ConnectionString;
2.2.3 操作数据库

当连接数据库后,我们就可以操作数据库了,进行增删改查操作。

首先在test数据库中创建学生表,并添加一些数据:

CREATE TABLE `test`.`tab_student` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, `age` INT UNSIGNED NOT NULL, `school` VARCHAR(100) NOT NULL, PRIMARY KEY (`id`)) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COMMENT = '学生表'; INSERT INTO `test`.`tab_student` (`name`, `age`, `school`) VALUES ('张三', '20', '中山大学'); INSERT INTO `test`.`tab_student` (`name`, `age`, `school`) VALUES ('李花', '19', '中山大学'); 

操作数据库的主要类是MySqlCommand,其构造函数如下:

  • public MySqlCommand(string cmdText, MySqlConnection connection);:cmdText表示SQL语句,connection表示数据库连接对象,通过这两个参数创建MySqlCommand对象;

在MySqlCommand中,操作数据库的方法主要有以下的方法:

  • public MySqlDataReader ExecuteReader();:执行查询操作;
  • public override int ExecuteNonQuery();:执行增加、删除、修改操作;
查询

ExecuteReader():执行查询操作,返回MySqlDataReader对象;

try
{
    // 在操作数据库时,可能发生异常情况,所以使用try-catch块包裹
    // 打开数据库连接
    mySqlConnection.Open();

    // 进行查询操作
    // SQL语句
    String sql = "select * from tab_student;";
    // 创建MySqlCommand对象
    MySqlCommand mySqlCommand = new MySqlCommand(sql,mySqlConnection);
    // 执行查询操作,获取查询结果
    MySqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader();
    // 遍历查询结果
    while (mySqlDataReader.Read())
    {
        int id = mySqlDataReader.GetInt32("id");
        String name = mySqlDataReader.GetString("name");
        int age = mySqlDataReader.GetInt32("age");
        String school = mySqlDataReader.GetString("school");

        Console.WriteLine("{0}\t{1}\t{2}\t{3}", id, name, age, school);
    }
    // 关闭mySqlDataReader
    mySqlDataReader.Close();
}
catch(Exception e)
{
    Console.WriteLine("发生异常情况:{0}", e.Message);
}
finally
{
    mySqlConnection.Close();
}

结果:

在这里插入图片描述

注意:一定要关闭MySqlDataReader!

接下来说说mySqlDataReader类,这个类表示查询结果,我们可以把查询结果看作是一张表,即把mySqlDataReader看作一张表,如下表。

在这里插入图片描述

表中红框中的数据是实际获得数据数据,红色指针首先指向第一行数据之前。

当我们调用mySqlDataReader.Read()方法后,指针往下移动一行,并返回下一行是否有数据(bool值):

在这里插入图片描述

此时指针指向实际数据第一行,这样我们就可以根据列名以及数据类型获取数据了,就是下面的代码:

int id = mySqlDataReader.GetInt32("id");
String name = mySqlDataReader.GetString("name");
int age = mySqlDataReader.GetInt32("age");
String school = mySqlDataReader.GetString("school");

在上面的案例中,我们使用DataReader来接收数据,现在我们使用DataSet来接收数据:

String connetStr = "server=127.0.0.1;port=3306;user=root;password=root;database=test;";
MySqlConnection mySqlConnection = new MySqlConnection(connetStr);

try
{
    // 打开数据库连接
    mySqlConnection.Open();
    // 创建MySqlCommand对象
    string sql = "select * from tab_student";
    MySqlCommand mySqlCommand = new MySqlCommand(sql,mySqlConnection);
    // 创建MySqlDataAdapter对象
    MySqlDataAdapter mySqlDataAdapter = new MySqlDataAdapter(mySqlCommand);
    // 创建DataSet对象,准备接收对象
    DataSet dataSet = new DataSet();
    // 执行SQL语句,并将结果填充到dataSet中,以表的形式存在,表名为tab_student
    mySqlDataAdapter.Fill(dataSet,"tab_student");
    // 打印结果
    DataRowCollection rows= dataSet.Tables["tab_student"].Rows;
    foreach(DataRow row in rows)
    {
        Console.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}",
                                        row.Field<int>("id"),
                                        row.Field<string>("name"),
                                        row.Field<uint>("age"),
                                        row.Field<string>("school")));
    }
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
}
finally
{
    if (mySqlConnection != null)
    {
        mySqlConnection.Close();
    }
}

在这里插入图片描述

插入、删除、修改

由于插入、删除、修改,都是由同一个方法ExecuteNonQuery()执行的,只是由于SQL语句的不同而不同,所以此处只演示插入操作:

// SQL语句
String sql = "insert into tab_student(`name`, `age`, `school`) values('王五','21','厦门大学');";
// 创建MySqlCommand对象
MySqlCommand mySqlCommand = new MySqlCommand(sql, mySqlConnection);
// 执行插入操作,返回受影响的行数
int records = mySqlCommand.ExecuteNonQuery();

结果:

在这里插入图片描述
在这里插入图片描述

接下来使用DataAdapter与DataSet来进行数据更新:

String connetStr = "server=127.0.0.1;port=3306;user=root;password=root;database=test;";
MySqlConnection mySqlConnection = new MySqlConnection(connetStr);

try
{
    // 打开数据库连接
    mySqlConnection.Open();
    // 创建MySqlCommand对象
    string sql = "select * from tab_student";
    MySqlCommand mySqlCommand = new MySqlCommand(sql,mySqlConnection);
    // 创建MySqlDataAdapter对象
    MySqlDataAdapter mySqlDataAdapter = new MySqlDataAdapter(mySqlCommand);
    // 创建DataSet对象,准备接收对象
    DataSet dataSet = new DataSet();
    // 执行SQL语句,并将结果填充到dataSet中,以表的形式存在,表名为tab_student
    mySqlDataAdapter.Fill(dataSet,"tab_student");
    // 获取tab_table中的所有行
    DataRowCollection rows= dataSet.Tables["tab_student"].Rows;
     
    rows[0].SetField<string>("name", "熊熊");    // 将第0行记录的姓名改为熊熊
    rows[4].Delete();                           // 删除第4行记录
	rows.Add(new object[] { null,"水木子",20,"厦门大学"});     // 新增一行

    // 由于在DataSet中所作的修改只存在与内存中
    // 如果我们需要更新到数据库中,则需要将之前的修改产生对应的SQL语句
    // MySqlCommandBuilder自动帮我们产生更新的SQL语句,并与DataAdapter绑定
    MySqlCommandBuilder mySqlCommandBuilder = new MySqlCommandBuilder(mySqlDataAdapter);

    // 调用DataAdapter的update()方法,将DataSet中的修改更新到数据库中
    mySqlDataAdapter.Update(dataSet,"tab_student");
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
}
finally
{
    if (mySqlConnection != null)
    {
        mySqlConnection.Close();
    }
}

在这里插入图片描述

3. DataAdapter和DataSet

之前只是演示了DataAdapter和DataSet的使用,接下来讲解这两个类中的一些重要属性和方法。

3.1 DataAdapter

  • Fill():用于向DataSet对象填充从数据源中读取的数据,最常见的调用格式为:

    Fill(DataSet dataSet,string "数据表名“)

    第一个参数是要填充的数据集对象;第二个参数表示在内存中建立的临时表的名称。

    使用Fill()有以下注意点:

    1. Fill()方法完成了两件事:从数据库获取数据、将数据填充到DateSet对象中;
    2. 如果在调用Fill()方法之前连接已关闭,需要先打开连接,从数据库中获取获取,完成后再关闭连接;
    3. 在DataSet中添加结果集时,每个结果集应该都放在一个单独的表中;
  • Update():用于将数据集DataSet对象中的数据按照InsertCommand、DeleteCommand、UpdateCommand属性所指定的要求更新数据库,即调用这3个属性中所定义的SQL语句来更新数据源。常见的调用格式为:

    Update(DataSet dataSet,string "数据表名")

    其中第一个参数是数据集对象名,表示要将哪个数据集对象中的数据更新到数据库中;第二个参数表示临时表的名称。

    在修改了内存中的DataSet里的数据后,我们如何获得Insert、Update、Delete操作所对应的SQL语句呢?系统提供了xxSqlCommandBuilder类,它根据用户对DataSet对象数据的操作自动生成相应的InsertCommand、DeleteCommand、UpdateCommand属性值,该类的构造函数如下:

    xxSqlCommandBuilder(DataAdapter dataAdapter)

3.2 DataSet

基本的属性、方法可以见名知意,也可以看源码进行学习(偷个懒,不想写了…😪

参考资料

[1] https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/

[2] 李春葆、曾平、喻丹丹编著 《C#程序设计教程(第3版)》


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
                            原文链接:https://blog.csdn.net/qq_41261251/article/details/119039280

copyright@ 2020-2028  安卓源码空间网版权所有   

备案号:豫ICP备2023034476号-1号