using System.Data.SqlClient;
ADO.net
一、ADO.net
—》ADO.net是.net框架的组成部分,是由一系列数据访问类库的集合。
二、ADO.net 的五大对象
1)sqlConnection
数据库连接对象,有两种重载方法:
| 函数定义 | 参数说明 | 函数说明 |
|---|---|---|
| SqlConnection() | 不带参数 | 创建SqlConnection对象 |
| SqlConnection(string connectionstring) | 连接字符串 | 根据连接字符串,创建SqlConnection对象 |
2)sqlCommand
—》数据库命令对象,有五个重载方法:
| 函数定义 | 参数说明 | 函数说明 |
|---|---|---|
| SqlCommand() | 不带参数 | 创建SqlCommand对象 |
| SqlCommand(string cmdText , SqlConnection connection) | sql , 连接字符串 | 创建SqlCommand对象 |
—》SqlCommand类的方法
1.ExecuteNonQuery();
它的返回值类型为int型。多用于执行增加,删除,修改数据。返回受影响的行数。当select操作时,返回-1。
2.ExecuteReader();
它的返回类型为SqlDataReader。此方法用于用户进行的查询操作。使用SqlDataReader对象的Read();方法进行逐行读取。
3.ExecuteScaler();
它的返回值类型多位int类型。它返回的多为执行select查询。得到的返回结果为第一个值(第一行第一列)的情况,比如使用count函数求表中记录个数或者使用sum函数求和等。
4、其他,防止sql注入写法,动态参数。
using (SqlConnection connection = new SqlConnection(connectionString)){SqlCommand command = new SqlCommand(commandText, connection);command.Parameters.Add("@ID", SqlDbType.Int);command.Parameters["@ID"].Value = customerID;// Use AddWithValue to assign Demographics.// SQL Server will implicitly convert strings into XML.command.Parameters.AddWithValue("@demographics", demoXml);try{connection.Open();Int32 rowsAffected = command.ExecuteNonQuery();Console.WriteLine("RowsAffected: {0}", rowsAffected);}catch (Exception ex){Console.WriteLine(ex.Message);}}
3)sqlDataReader
datareader对象提供只读单向数据的快速传递,单向:您只能依次读取下一条数据;只读:DataReader中的数据是只读的,不能修改;要想读取DataReader对象中的数据,就要用到DataReader对象的Read方法,由于DataReader对象每次只在内存缓冲区里存储结果集中的一条数据(这里需要注意,所以当在读取过程中的时候,不可以关闭数据库连接,否则会报错。),所以要读取DataReader对象中的多条数据,就要用到迭代语句。
常用方法:
| 属性或方法 | 描述 |
|---|---|
| FieldCount属性 | 表示记录中有多少字段 |
| HasRows属性 | 用来表示DataReader是否包含数据 |
| IsClosed属性 | 百世DataReader是否关闭 |
| Close方法 | 将DataReader对象关闭 |
| GetDataTypeName方法 | 取得指定字段的数据形态 |
| GetName方法 | 取得指定字段的字段名称 |
| GetOrdinal方法 | 取得指定字段名称在记录中的顺序 |
| GetValue方法 | 取得指定字段的数据 |
| GetValues方法 | 取得全部字段的数据 |
| IsNull方法 | 用来判断字段内是否为Null值 |
| Read方法 | 用来读取记录中的数据 |
4)sqlDataAdapter
SqlDataAdapter是 DataSet和 SQL Server之间的桥接器,也有叫做适配器的,用于检索和保存数据。SqlDataAdapter通过对数据源使用适当的Transact-SQL语句映射 Fill(它可更改DataSet中的数据以匹配数据源中的数据)和 Update(它可更改数据源中的数据以匹配 DataSet中的数据)来提供这一桥接。当SqlDataAdapter填充 DataSet时,它为返回的数据创建必需的表和列(如果这些表和列尚不存在)。他会自动打开与关闭数据库连接。
var sqlConnection = DbHelp.GetSqlConnection();string sqlString = "SELECT * FROM Student";SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlString,sqlConnection);DataSet dataSet = new DataSet();sqlDataAdapter.Fill(dataSet);
5)DataSet
DataSet相当于一个缓存,是一个本地映射数据库的一个内存数据库,包含许多DataTable(其中包含DataRaw和DataColum)
当遍历datable时,可以用foreach循环遍历每一行,然后封装到对象中。
总结:
①System.Data → DataTable,DataSet,DataRow,DataColumn,DataRelation,Constraint,DataColumnMapping,DataTableMapping
②System.Data.Coummon → 各种数据访问类的基类和接口
③System.Data.SqlClient → 对Sql Server进行操作的数据访问类
主要有: a) SqlConnection → 数据库连接器
b) SqlCommand → 数据库命名对象
c) SqlCommandBuilder → 生存SQL命令
d) SqlDataReader → 数据读取器
e) SqlDataAdapter → 数据适配器,填充DataSet
f) SqlParameter → 为存储过程定义参数
g) SqlTransaction → 数据库事物
三、数据库连接字符串
1、sqlserver
Data Source=.;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;
2、Access
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\myDatabase.mdb;User Id=admin;Password=;
3、MySQL
Server=myServerAddress;Database=myDatabase;Uid=myUsername;Pwd=myPassword;
4、DB2
Server=myAddress:myPortNumber;Database=myDatabase;UID=myUsername;PWD=myPassword;
5、Oracle
Data Source=TORCL;User Id=myUsername;Password=myPassword;
四、数据库访问的一般步骤
1、建立数据库连接,并打开,using语句可以自动关闭连接。
//创建连接对象1using (SqlConnection conn1 = new SqlConnection("连接字符串")){conn1.Open();}
2、创建SQL 命令
3、执行SQL命令,有Command主要有三个方法(上面有提到)
//新增
private void btnAdd_Click(object sender, EventArgs e)
{
//创建连接对象,并使用using释放(关闭),连接用完后会被自动关闭
using (SqlConnection conn=new SqlConnection("server=.;uid=sa;pwd=sa;database=MyCar"))
{
//打开连接
conn.Open();
//将执行的sql
String sql = "INSERT INTO Car([Title] ,[Speed] ,[Info]) VALUES('奇瑞' ,190,'国产轿车')";
//创建命令对象,指定要执行sql语句与连接对象conn
SqlCommand cmd = new SqlCommand(sql,conn);
//执行,返回影响行数
int rows=cmd.ExecuteNonQuery();
if (rows > 0) MessageBox.Show("新增成功!");
}
}
4、处理SQL命令结果
//查询
private void btnQuery_Click(object sender, EventArgs e)
{
//创建连接对象,并使用using释放(关闭),连接用完后会被自动关闭
using (SqlConnection conn = new SqlConnection("server=.;uid=sa;pwd=sa;database=MyCar"))
{
//打开连接
conn.Open();
//将执行的sql
String sql = "select Id,Title,Speed,Info from Car";
//创建命令对象,指定要执行sql语句与连接对象conn
SqlCommand cmd = new SqlCommand(sql, conn);
//执行查询返回结果集
SqlDataReader sdr = cmd.ExecuteReader();
//下移游标,读取一行,如果没有数据了则返回false
while (sdr.Read())
{
Console.WriteLine("编号:" + sdr["Id"] + ",车名:" + sdr["Title"] + ",速度:" + sdr["Speed"]);
}
}
}
4_1、防止sql注入的写法:
private void btnAdd_Click(object sender, EventArgs e)
{
//创建连接对象,并使用using释放(关闭),连接用完后会被自动关闭
using (SqlConnection conn=new SqlConnection("server=.;uid=sa;pwd=sa;database=MyCar"))
{
//打开连接
conn.Open();
//将执行的sql
String sql = "INSERT INTO Car([Title] ,[Speed] ,[Info]) VALUES(@Ttile,@Speed,@Info)";
//创建命令对象,指定要执行sql语句与连接对象conn
SqlCommand cmd = new SqlCommand(sql,conn);
//指定参数
cmd.Parameters.Add(new SqlParameter("@Ttile", txtTitle.Text));
cmd.Parameters.Add(new SqlParameter("@Speed", txtSpeed.Text));
cmd.Parameters.Add(new SqlParameter("@Info", txtInfo.Text));
//执行,返回影响行数
int rows=cmd.ExecuteNonQuery();
if (rows > 0) MessageBox.Show("新增成功!");
}
}
4_2、最后的封装
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;
namespace HR.Utils
{
/// <summary>
/// 用于访问SQLServer数据库的工具类
/// </summary>
public class SqlHelper
{
/// <summary>
/// 连接字符串 write once,only once!
/// </summary>
public static String connString = "server=.;uid=sa;pwd=sa;database=HR";
/// <summary>
/// 完成增,删,改
/// </summary>
/// <param name="sql">将要执行的sql</param>
/// <param name="ps">可变参数,指定sql中的参数</param>
/// <returns>影响行数</returns>
public static int Execute(String sql, params SqlParameter[] ps)
{
using (SqlConnection conn = new SqlConnection(connString))
{
//打开连接
conn.Open();
//创建命令对象,指定sql与连接对象conn
SqlCommand cmd = new SqlCommand(sql, conn);
//指定参数
if (ps != null) cmd.Parameters.AddRange(ps);
//执行sql命令,返回影响行数
return cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 执行查询,返回SqlDataReader,一定要关闭
/// </summary>
/// <param name="sql">将要执行的sql</param>
/// <param name="ps">可变参数,指定sql中的参数</param>
/// <returns>SqlDataReader结果集</returns>
public static SqlDataReader Reader(String sql, params SqlParameter[] ps)
{
//定义一个连接对象,指定连接字符串using,sa sa MyCar .
SqlConnection conn = new SqlConnection(connString);
//打开数据库
conn.Open();
//定义命令对象,指定要执行的sql与conn连接参数
SqlCommand cmd = new SqlCommand(sql, conn);
//指定参数
if (ps != null) cmd.Parameters.AddRange(ps);
//执行SQL查询,返回结果集给sdr,关闭reader时也关闭连接
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
}
}
5、常见错误
1、忘记关闭数据库。
2、循环中打开数据库连接。
3、打开数据库连接后,在数据库中做一些无用的事情。
4、使用Adapter的性能问题:在数据量很小的情况下是能改善一些性能,但是在数据量突破一定量的时候,内存问题就会显现出来,这个可能就会降低性能,所以使用的时候还需要分场景的。
数据库连接问题
虽然现在的ADO并不会使用太多,但是了解还是必要的,今天的问题是,数据库的连接。
在使用ADO时,总会面临着一系列的优化问题,比如一个连接可不可以多次使用,怎样重复使用,怎样判断什么时候关闭连接,等等一些问题,这些问题都是有优化的。
1、数据库连接可不可以多次使用
要分情况,首先明白数据库连接是什么?
注意:一个数据库连接对应着一个连接池。
SqlConnection sqlConnection = DbHelp.GetSqlConnection();
//这句话只是创建一个连接对象,为了减少重复创建对象的开销,当然可以重复使用。
sqlConnection.Open();
//这句话就是在数据库连接池中获取一条连接,也是真正的与数据库建立了连接,一个数据库连接不可以重复打开。
所以说,可不可以重复利用同一个连接呢?,答案当然是可以的,只要不关闭数据库连接,就可以一直在一个连接中接连执行不同操作或相同操作,这也就出现了问题,占用数据库连接资源。
2、怎样重复使用数据库连接
一个数据库连接当打开的时候,就会消耗一个数据库连接资源,所以在重复利用数据库连接是应该有情景的。(多线程的情况下就要更多的考虑一些资源争夺问题)
1)不同的功能不应该使用同一个连接资源
在一个项目中,有很多不同的功能模块,这些模块大多是相互独立的,所以在执行不同的模块功能操作时,不应该占用一个数据库连接,应改分别创建且执行完对应的功能方法时,应该即时释放数据库连接资源。
2)不同的操作不应该使用同一个连接资源
所谓不同的操作,就是增加与修改不应该使用同一个连接资源,依次类推。
3)同一种的重复操作可以使用同一个连接资源
当进行批量操作时,可以使用同一个连接资源,以实现资源利用的最大化。
3、数据库连接的关闭
数据库连接要即时关闭,因为数据库连接是有限的,当连接过多的时候就会出现异常,所以在不使用数据库连接的时候要及时释放连接。
4、这里建立连接的两种方法
//连接式:这种方式与数据库建立一个连接,并执行操作,执行完毕后断开连接
sqlConn.Open();
SqlDataReader dr=sqlComm.ExcuteReader();
while(dr.Read())
{
for(int i=0; i<dr.FieldCount; i++)
{
Console.Write(dr.GetValue(i).ToString()+" ");
}
Console.WriteLine();
}
dr.Close();
sqlConn.Close();
/*
优点:
因为连接式使用DataReader,每次只在内存中加载一条数据,所以占用的内存是很小的。由于DataReader的特殊性和高性能,所以DataReader是只进的,你读了第一条后就不能再去读取第一条了。
缺点:
需要你去维护建立起来的这个数据库连接,所以如果用户访问量大时,有可能导致连接池异常。
*/
//断开式:将数据一次性加载到内存DataSet,之后立即释放连接。
sqlConn.Open();
DataSet ds=new DataSet();
adapter.Fill(ds);
sqlConn.Close();
for (int i=0; i<ds.Tables[0].Rows.Count; i++)
{
for (int j=0; j<ds.Tables[0].Columns.Count; j++
{
Console.Write(ds.Tables[0].Rows[i][j]+" ");
}
Console.WriteLine();
}
/*
优点:
一次连接取得数据之后,即可断开,在用户非常多的情况下,不会占用太多的连接池资源。还有一点,就是一次性的从数据库中取得了数据之后,这些数据是存在内存中的,而不会再去操作数据库,所以你对这些数据做任何的操作,都只是修改内存,不会改变数据库中的内容。
缺点:
刚才提到了,这种方式是把数据一次性的读到内存中的,所以在数据量大的时候会非常消耗内存。
*/
事务操作
using (IDbTransaction transaction = sqlConnection.BeginTransaction())
{
//进行操作
try
{
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
}
