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访问数据库的一般流程如下:
-
建立数据库连接对象-Connection;
-
在建立连接的基础上,可以使用Command对象对数据库发生查询、新增、修改和删除等命令;
-
创建DataAdapter对象,从数据库中取得数据;
-
创建DataSet对象,将DataAdapter对象填充到DataSet对象中;
-
如果需要,可以重复操作,即在一个DataSet对象中容纳多个数据集合;
-
关闭数据连接;
-
在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()有以下注意点:
-
Fill()方法完成了两件事:从数据库获取数据、将数据填充到DateSet对象中;
-
如果在调用Fill()方法之前连接已关闭,需要先打开连接,从数据库中获取获取,完成后再关闭连接;
-
在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