编程语言与数据库的连接是通过一个接口,达到两者交流,以便两者谈情说爱。
1、ODBC,面向C/C++。
2、DAO, 面向VB,操作ACCEss
3、RDO,上面的加强型
4、OLE DB
5、ADO, 对OLE DB的加强型
6、ADO.net, ADO的加强型。
Ado.net基于XML和离线计算模型。
ADO以Recorderset存储,类似单表,若要多表就要多表连接。必须在线
ADO.net可以在线或离线,DataSet直接可以是多表。
ADO使用Com技术,ADO.net基于XML格式,数据类型更丰富。
体系结构如下:
ADO.net的两个核心组件:.Net数据提供程序(左)、DataSet(右)。
.net数据提供程序用来与数据库的连接。包括Connection,Command,DataReader,DataAdapter四个。
DataSet用来与XML数据连接。设计的目的是独立于任何数据源的数据访问,可有多种不同数据,也可用于XML数据。
它内部用XML描述数据,与平台无关。其内常用对象是DataTable和DataRow等。DataSet通过DataAdapter获得数据,
DataAdapter就是DataSet与数据库之间的桥梁,也就是前面的搬运工。它把数据库中的结果集搬运到本地缓存中,这样
就可与数据离线,直接处理DataSet,处理完后,再连接,再搬运回数据库。
DataSet有三个特点:
1、独立性:独立于各数据源。即与数据库不发生关系,专注于处理。
2、离线连接: 一般是离线,只是返回数据库时,才保持连接。
3、XML描述: DataSet对象是用XML格式表示的关系型数据视图。
它提供四个对象,保持与不同数据库连接。
1、SQLServer.net数据提供程序,空间:System.Data.SqlClient, 操作SQl2000或以上版本。
2、OleDb.net数据提供程序,空间:System.Data.OleDb,主要访问Access,FoxPro等
3、OracleDB.net数据提供程序,空间:System.Data.OracleClient,支持Oracle8.1.7以上版本。
4、ODBC.net数据提供程序,空间:System.Data.Odbc
这个说五个是:
Connection对象负责连接数据库
Command对象负责生成执行SQl语句
DataReader对象负责读取数据库的数据
DataAdapter对象负责在Command对象执行完SQL语句后生成并填充DataSet和DataTable。
DataSet对象负责存取和更新数据。
表示一个数据源的单个连接。
例一:连接Access的例子:
例二:连接Sqlserver的例子:
它用来执行SQL语句,执行的结果由DataReader和DataAdapter填充到DataSet中,这样就完成 数据库数据操作的工作 。
注1:CommandType有三个:
Text,说明是一个SQL语句,这是默认值,不设置时就是它。
TableDirect,一个要操作的数据表的名
StoredProcedure,一个存储过程。
注2:构造函数有四个,用第三个较多。
就是上面的四个方法,这个是重点。
通过DataReader类型的对象,应用程序可获得执行SQL命令后的结果集。
这个方法有两种定义:
一是ExecuteReader() :不带参数,直接返回一个DataReader结果集;
二是ExecuteReader(CommandBehavior behavior):根据参数Behavior取值类型,决定DataReader类型。
如果behavior是CommandBehavior.SingleRow,则说明返回的ExecuteReader只是结果集中的第一条数据;
如果behavior是CommandBehavior.SingleResult,则说明只返回在查询结果中多个表里的第一个。
如果behavior是CommandBehavior.SequentialAccess,则说明对于返回的ExecuteReader对象只能顺序
读取它包含的列。一旦读过某列,就不能返回再次读取了,以方便性为代价换取读取数据时的高效率。
无论何结果,ExecuteReader方法返回一个DataReader对象,该对象是一个仅向向的只读数据流,所以主要用来执行
基本SQL查询,要求SQL语句返回记录集。
用executeReader返回一个DataReader,然后用它来填充(加载到)另一个对象DataTable中,最后DataTable直接绑定到控件上。
Imports System.Data.SqlClient Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim cn As New SqlConnection("Data Source=.;Initial Catalog=Sales;Integrated Security=False;User ID=sa;Password=123456;") cn.Open() Dim cmd As New SqlCommand("select * from grade", cn) Dim dr As SqlDataReader '不能new.应用程序不直接创建 IDataReader 接口的实例,而是创建继承 IDataReader 的类的实例 dr = cmd.ExecuteReader() Dim dt As New DataTable dt.Load(dr) DataGridView1.DataSource = dt cn.Close() End Sub End Class
前面用DataTable绑定数据,下面用BindingSource来绑定。界面一样,代码变化几句:
Imports System.Data.SqlClient Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim cn As New SqlConnection("Data Source=.;Initial Catalog=Sales;Integrated Security=False;User ID=sa;Password=123456;") cn.Open() Dim cmd As New SqlCommand("select * from grade", cn) Dim dr As SqlDataReader '不能new.应用程序不直接创建 IDataReader 接口的实例,而是创建继承 IDataReader 的类的实例 dr = cmd.ExecuteReader() '前面用DataTable绑定数据,下面用BindingSource来绑定 Dim bs As New BindingSource bs.DataSource = dr DataGridView1.DataSource = bs cn.Close() End Sub End Class
Scalar,标量,是一个值。一个结果集可能有多个记录,每个记录可能有多个列值。因此,
该方法返回的是首行首列的一个值,其它值忽略。主要用于那些聚合运算,比如求有多少个记录,总计是多少,等等。
Imports System.Data.SqlClient Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim cn As New SqlConnection("Data Source=.;Initial Catalog=Sales;Integrated Security=False;User ID=sa;Password=123456;") cn.Open() Dim cmd As New SqlCommand("select * from grade", cn) Dim strValue As String = cmd.ExecuteScalar.ToString MessageBox.Show(strValue) cn.Close() End Sub End Class
即,非查询命令。主要用来执行insert,update,delete和那些没有返回结果集的SQL语句,并返回执行命令后影响的行数。
如果insert,update对应的记录不存在,则返回0;如果出错,则返回-1.
注意:因为这个用户不知道成功与否,所以要加入一些提示或再次显示原数据库,以便了解执行情况。
前面几节有这个大量的例子,不再列出。
前面说了存储过程,存储过程就是一个批处理。
事务也是一个批处理过程,只不过加强版,即要么全部都成功执行,要么全部失败。(SQL自动会控制它)
所以事务有两个作用:
一致性:同时进行的查询和更新彼此不会发生冲突,其它用户不会看到发生了变化但尚未提交的数据;
可恢复性:一旦故障或失败,数据库会自动地完全恢复未完成的事务(Rollback)。
ADO.net中,使用Connection和Transaction对象来控制事务,事务顺序包括:
一、调用Connecton对象的BeginTransaction方法来标记事务的开始。
二、将Transaction对象分配给要执行的Command的Transaction属性;
三、执行所需的命令;
四、调用Transaction对象的Commit方法来完成事务,或调用RollBack方法来取消事务。
ADO.net事务处理的优点:简单、运行速度快、独立于数据库。
缺点:不能跨多个数据库连接。
事务执行建立在数据库的连接层上,所以需要在事务过程中一直保持数据库连接。
编程流程:
事务开始:Connection对象的BeginTransaction()声明开始
提交事务:即去执行,用Transaction对象的Commit()方法来提交
回滚事务:即事务失败后的全部恢复,用Transaction对象的RollBack()方法来回滚事务。
从 这个例子中,可以看到事务是多个SQL语句提交执行(批处理),当如果有一条不成功,则全部恢复(不管以前是否成功)。
Imports System.Data.SqlClient Public Class Form1 Dim cn As SqlConnection Dim cmd As SqlCommand Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click cn = New SqlConnection("Data Source=.;Initial Catalog=Sales;Integrated Security=False;User ID=sa;Password=123456;") cn.Open() cmd = New SqlCommand() cmd.Connection = cn Dim trans As SqlTransaction '这里不能new. friend成员 trans = cn.BeginTransaction '第一步,开始事务。这句必须在下句前,相当于实例事务对象 cmd.Transaction = trans 'cmd要做的事 Try cmd.CommandText = "update grade set 数学=33 where 姓名 like '%周%'" cmd.ExecuteNonQuery() cmd.CommandText = "update grade set 英语=11 where 姓名 like '%张%'" cmd.ExecuteNonQuery() trans.Commit() '第二步,执行事务,就是执行上面两个更新操作 Label1.Text = "事务提交执行成功" Catch ex As Exception trans.Rollback() '第三步,回滚事务,上面若有失败,则全部恢复执行事务前的状态。 Label1.Text = "事务提交失败,所有任务恢复原状。" End Try End Sub End Class
首先说明:DataReader不能实例化,即不能用New。它只能由Command对象ExecuteReader()方法来创建,所以2.2例中没用NEw
DataReader对象提供向前的、只读数据,所以只能依次来读:
DataReader的Read(),提供下一条记录的读取,返回值是布尔值,为真执行成功,为假说明下一条无记录。
这些记录是不能修改的。而DataSet因为是离线数据集,在本地内存中缓存,所以是可以任意修改的。
DataReader从数据库中检索只读数据流,存储在客户端的网络缓存当中。在内存当中只存储一行,所以开销小,速度快。
由于数据不在内存中缓存,所以在检索大量数据时,DataReader是一种较好的选择。
DataRader还是一个霸王,具有独占性,在已经打开DataReader的情况下,将不能对Connection进行任何操作,所以用完了它就
应及时调用Close()方法关闭。
通过Command对象返回多个结果集,并且通过DataReader对象NextResult()方法来使用。
再次强调它不能New,只能由Command对象的ExecuteReader()方法来创建 。
创建后,读取DataReader对象中的数据有两种方法:
一通过和DataGridView等数据控件绑定,直接输出;
二利用循环将数据取出。(即Read()方法进行循环读取)。
例子:用DataReader对象通过循环读取多条记录。
Imports System.Data.SqlClient Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim cn As New SqlConnection("Data Source=.;Initial Catalog=Sales;Integrated Security=False;User ID=sa;Password=123456;") cn.Open() Dim cmd As New SqlCommand("select * from grade", cn) Dim dr As SqlDataReader dr = cmd.ExecuteReader() Dim strDisplay As String = "" While dr.Read() strDisplay &= dr("学号").ToString + Space(5) strDisplay &= dr("姓名").ToString + Space(5) strDisplay &= dr("英语").ToString + Space(5) strDisplay &= dr("语文").ToString + Space(5) strDisplay &= dr("数学").ToString + Space(5) strDisplay &= vbCrLf End While cn.Close() Label1.Text = strDisplay End Sub End Class
DataAdapter数据适配器,它就是一个搬运工:从数据源搬运到本地内存中以便来填充DataSet;或者从本地内中数据搬运回到数据源中。
这两者的数据可以是相同,也可是不同,DataAdapter会自动匹配,发挥“适配”的作用。
从数据源到本地内存,然后再填充就用Fill()方法。
从本地内存到数据源,进行数据库的更新用Update()方法。
DataAdapter对象属性
属 性 |
说 明 |
DeleteCommand |
获取或设置一个语句或存储过程,以从数据集删除记录 |
InsertCommand |
获取或设置一个语句或存储过程,以在数据源中插入新记录 |
SelectCommand |
获取或设置一个语句或存储过程,用于在数据源中选择记录 |
UpdateBatchSize |
获取或设置每次到服务器的往返过程中处理的行数 |
UpdateCommand |
获取或设置一个语句或存储过程,用于更新数据源中的记录 |
DataAdapter方法
方法 说明
Dispose 删除该对象
Fill 用从源数据读取的数据行填充至DataSet对象中
FillSchema 将一个DataTable加入到指定的DataSet中,并配置表的模式
GetFillParameters 返回一个用于SELECT命令的DataParameter对象组成的数组
Update 在DataSet对象中的数据有所改动后更新数据源。
搬运工就是双面间谍,要么向本机的DataSet填充数据,要么就向另一个方向的数据库更新数据。
SqlDataAdapter类的构造函数
SqlDataAdapter() 不带参数, 创建SqlDataAdapter对象
SqlDataAdapter(SqlCommand selectCommand) selectCommand:指定新创建对象的SelectCommand属性
用参数selectCommand设置其Select Command属性
SqlDataAdapter(string selectCommandText,SqlConnection selectConnection) selectCommandText:指定新创建对象的SelectCommand属性值;
selectConnection:指定连接对象
用参数selectCommandText设置其Select Command属性值,
并设置其连接对象是selectConnection
SqlDataAdapter(string selectCommandText,String selectConnectionString) selectCommandText:指定新创建对象的SelectCommand属性值;
selectConnectionString:指定新创建对象的连接字符串
将参数selectCommandText设置为Select Command属性值,
其连接字符串是selectConnectionString
构造函数可以不带参数,或者带1,2,3个参数,由参数可以看到cmd有时超出自己的范围,跑到Connection的功能上去了。
这是搬运工填充本地内存的情况。
调用Fill()方法时,DataAdapter将向数据存储区传输一条Select语句,主要用来填充或刷新DataSet,返回值是影响DataSet的行数。
Fill()方法如下:
int Fill (DataSet dataset) dataset:需要更新的DataSet
根据匹配的数据源,添加或更新参数所指定的DataSet,返回值是影响的行数
int Fill (DataSet dataset, string srcTable) dataset:需要更新的DataSet;
srcTable:填充DataSet的dataTable名(就是别名,用户自己命名一个,可以与原表相同)
根据dataTable名填充DataSet
例子:前面已经有了,不再列出,参见:http://blog.csdn.net/dzweather/article/details/8564039
这是搬运工更新服务器数据库的情况。
调用Update()方法时,DataAdapter将检查参数DataSet每一行的RowState属性,根据RowState属性来检查DataSet里
的每一行是否改变及改变的类型,并依次执行所需的Insert,Update,Delete语句,再将改变提交到数据库中,同时
返回影响的DataSet的行数据。
例子:下面用一个添加一行记录,同时更新DataSet和数据库。
里面用到了DataRow,这个用于添加一个新行NewRow,然后给新行加值.
Imports System.Data.SqlClient Public Class Form1 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim cn As New SqlConnection("Data Source=(local);Initial Catalog=Sales;Integrated Security=False;User ID=sa;Password=123456;") Dim da As New SqlDataAdapter("select * from grade", cn) '搬运工拉好水 Dim ds As New DataSet() '本地内存准备好容器来装水 da.Fill(ds, "mytable") '装水 Dim drow As DataRow '定义行变量 drow = ds.Tables("mytable").NewRow '行变量是新的一个行 Try drow("学号") = TextBox1.Text '新行赋值 drow("姓名") = TextBox2.Text drow("语文") = TextBox3.Text drow("数学") = TextBox4.Text drow("英语") = TextBox5.Text ds.Tables("mytable").Rows.Add(drow) '新行内容加入到表中 Dim cmdb As New SqlCommandBuilder(da) '和数据库打个电话,本地内存有水要运过去 da.Update(ds, "mytable") '上面电话里已经说好了,现在把水运到数据库去 DataGridView1.DataSource = ds.Tables("mytable") '绑定到控件上显示当前结果 Catch ex As Exception MessageBox.Show(ex.ToString) End Try End Sub Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick '点击控件,其数据就显示在上面的文本框中 Dim a As Integer = e.RowIndex TextBox1.Text = DataGridView1.Rows(a).Cells(0).Value.ToString TextBox2.Text = DataGridView1.Rows(a).Cells(1).Value.ToString TextBox3.Text = DataGridView1.Rows(a).Cells(2).Value.ToString TextBox4.Text = DataGridView1.Rows(a).Cells(3).Value.ToString TextBox5.Text = DataGridView1.Rows(a).Cells(4).Value.ToString End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 'TODO: 这行代码将数据加载到表“SalesDataSet.grade”中。您可以根据需要移动或删除它。 Me.GradeTableAdapter.Fill(Me.SalesDataSet.grade) End Sub End Class