不管学习什么知识,基础最重要,一切要从基础开始,否则只会是空中楼阁。以下是我看《.net程序设计技术内幕》数据库篇的读书笔记。
.net框架对数据库的操作主要是靠ADO.NET完成的,而ADO.NET的数据库访问是通过被称为数据提供程序(data provider)的软件模块来进行的。
.net框架的1.0版本有两个数据提供程序:
1,SQL Server .NET提供程序 它是于Microsoft SQL Server数据库的接口,不需要任何非托管提供程序的帮助。
2,OLE DB .NET提供程序 它是通过OLE DB提供程序访问数据库的接口。
其中OLE DB.NET提供程序允许我们通过从托管代码中调用现有的OLE DB提供程序来使用它们:
1,SQLOLEDB提供程序 它是与SQL Server数据库的接口
2,MSDAORA提供程序 它是与Oracle数据库的接口
3,Microsoft.jet,OLEDB.4.0提供程序 它是与通过Microsoft Jet数据库引擎驱动的数据库的接口
如果应用程序会使用Microsoft SQL 7.0或者以上的版本,则使用SQL Server .NET提供程序。它比OLE DB提供程序快。它在访问数据库时候不离开托管代码的领域,相反,OLE DB .NET提供程序使用 .NET框架的Platform Invoke机制调用非托管的OLE DB提供程序;如果应用程序使用Microsoft SQL 6.5或者是以前版本,选择OLE DB.NET提供程序;如果应用程序使用非SQL Server数据库,比如Oracle 8i,选择OLE DB.NET提供程序。
以下是操作SQL Server 7.0,使用SQL Server .NET提供程序或OLE DB .NET提供程序的数据库操作实例代码
使用SQL Server .NET提供程序:
using System.Data.SqlClient
...
SqlConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.open();
SqlCommand cmd=new SqlCommand("select * from titles",conn);
SqlDataReader reader=cmd.ExecuteReader();
while(reader.read())
{
Console.WriteLine(reader["title"]);
}
catch(SqlException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
conn.close();
}
}
使用OLE DB .NET提供程序:
using System.Data.OleDb;
...
OleDbConnection conn=new OleDbConnection("provider=sqloledb;server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.open();
OleDbCommand cmd=new OleDbCommand("select * from titles",conn);
OleDbDataReader reader=cmd.ExecuteReader();
while(reader.read())
{
Console.WriteLine(reader["title"]);
}
catch(OleDbException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
conn.close();
}
}
可以看到除了类名和连接字符串以外,两个提供程序之间对操作sql server 7没有什么其他的不同,说明了ADO.NET为不同的类型的数据库提供了一个通用的API,这个API的细节有些会不同,这取决于我们使用的托管提供程序。
1,连接
SqlConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
此为一个SqlConnection有参数的构造函数,参数其实可以是连接conn的一个属性ConnectionString,其中这个字符串的格式要正确
在打开连接的时候会验证这个字符串,如果不通过会产生一个异常。
server=localhost可以写成server=(local)或Data Source=(local);database参数可以写成Initial Catalog,uid可以写成user id,pwd可以写成password。
对于oledb提供程序也是类似的连接方式:OleDbConnection conn=new OleDbConnection("provider=sqloledb;server=localhost;database=pubs;uid=sa;pwd='');
Provider参数标识了用于和数据库交互的Ole Db提供程序-这里是SQLOLEDB,它是微软面向SQL Server的OLE DB提供程序。把提供程更改成MSDARA就会把目标改成Oracle数据库。
创建了一个SqlConnection或OleDbConnection对象和提供一个连接字符串并没有打开一个指向数据库的物理连接,必须调用对象的Open方法才能做到这点。用Open打开的连接最好用Close关闭。
如果不能建立一个指向数据库的连接,Open方法会引发异常,而且打开连接在数据库上执行的操作如果失败,也会引发异常,应该对异常进行捕捉。
所以一般对数据库的操作代码一般为:
SqlConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.open();
//TODO:使用连接
}
catch(SqlException ex) //我们有必要关心一下SqlException的属性
{
//TODO:处理异常
}
finally
{
conn.close();
}
}
对OLE DB .NET提供程序的等价代码如下:
OleDbConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.open();
//TODO:使用连接
}
catch(OleDbException ex)
{
//TODO:处理异常
}
finally
{
conn.close();
}
}
2.使用命令(类为SqlCommand或OleDbCommand)
使用ExecuteNonQuery方法,此方法用来执行INSERT,UPDATE,DELETE和其他没有返回值的SQL命令(比如CREATE DATABASE和CREATE TABLE命令)
此方法返回被命令影响的行数。要使用ExecuteNonQuery创建名为MyDatabase的新数据库,只需要将命令对象的命令为本改为"create database MyDatabase",接着使用create table和insert命令来建立表和插入数据了。
如果ExecuteNonQuery失败,也会产生SqlException或OleDbException对象异常。注意:带有无效字段的update命令和违反主键约束规则的insert命令会引起异常,但是以不存在的记录为目标update和delete命令不够成错误,只是ExecuteNonQuery
返回o.
使用ExecuteScalar方法,此方法执行一个SQL命令并返回结果集的第一列的第一行,而忽视其他的列和行。它最常用来执行Sql的count,avg,min,max和sum等集函数,因为这些函数都是返回单行单列的结果集。
值得我们注意的是ExecuteScalar方法返回的是一个Object类型,所以我们在使用的时候要把它返回的结果强制转换成所需要的类型。如果转换不正确,.net框架就会引发InvalidCastException异常。
这个方法还有一个比较普遍的用法是从数据库中检索BLOB(二进制大对象).看如下代码:
MemoryStream stream=new MemoryStream();
SqlConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.Open();
SqlCommand cmd=new SqlCommand("select logo from pub_info where pub_info='0763'",conn);
byte[] blob=(byte[])cmd.ExecuteScalar();
stream.Write(blob,0,blob.Length);
Bitmap bitmap=new Bitmap(stream);
bitmap.Dispose();
}
catch(SqlException ex)
{
//TODO:处理异常
}
finally
{
stream.Close();
conn.Close();
}
这样就创建了一个位图。
随便写出如何将blob写入数据库的代码:
SqlConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.Open();
SqlCommand cmd=new SqlCommand("insert into pub_info (pub_id,logo) values('9937',@logo)",conn)//使用参数化命令
cmd.Parameters("@logo",blob);
cmd.ExecuteNonQuery();
}
catch(...)
{
...
}
finally
{
conn.Close();
}
变量blob是单独定义和初始化的,下面是从logo.jpg文件中读取图像:
FileStream stream=new FileStream("logo.jpg",FileMode.Open);
Byte[] blob=new byte[stream.Length];
stream.Read(blob,0,(int)stream.Length);
stream.Close();
使用ExecuteReader方法,此方法存在的目的只有一个,尽可能快的对数据库进行查询并得到结果,返回一个DataReader对象。它是一个快速枚举数据库查询结果的机制,
是只读、只进的。生成的DataRead对象是一个开始指向记录集的空项数据的,必须使用Read()方法进行指针的移动来显示数据。
如:
SqlConnection conn=new SqlConnection("server=localhost;database=pubs;uid=sa;pwd='');
try
{
conn.open();
SqlCommand cmd=new SqlCommand("select * from titles",conn);
SqlDataReader reader=cmd.ExecuteReader();
while(reader.read()) ///读到最后一条数据以后再reader.read()返回值就会为false退出循环
{
Console.WriteLine(reader["title"]); ///也可以使用索引reader[0]表示此行第一列的数据
}
catch(SqlException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
conn.close();
}
}
而且在用DataReader查询数据库之前不需要预先知道它的架构,可以使用这个对象来获得架构信息。使用函数DataReader对象的属性FieldCount来获得该行的列的数目,然后使用方法GetName(int i)来返回索引为i的列的名字。还可以使用GetSchemaTable()方法来获得构架信息,该方法返回一个DataTable对象。
int index=DataReader.GetOrdinal("属性名")来返回该属性名对应的索引。
GetDecimal(index)获得该行索引值为index的属性列的值。
值得注意的是DataReader对象必须在数据库处于连接状态下才能运行的,所以在查询语句之前不可能出现conn.Close(),而且如果你用一个命令创建了一个DataReader对象以后,又想用那个命令
对象作别的事情,那么必须现关闭创建的DataReader对象Reader.close(),然后再进行其他的操作。
还可以使用DataReader关闭底层连接,代码:reader=cmd.ExecuteReader(CommandBehavior.CloseConnection);此时必须把reader.Close()放在finally块中以防止由于泄露连接引发异常。
不好意思,写得有点乱望斧正。
为什么我不能插入代码??