1. 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注入写法,动态参数。

  1. using (SqlConnection connection = new SqlConnection(connectionString))
  2. {
  3. SqlCommand command = new SqlCommand(commandText, connection);
  4. command.Parameters.Add("@ID", SqlDbType.Int);
  5. command.Parameters["@ID"].Value = customerID;
  6. // Use AddWithValue to assign Demographics.
  7. // SQL Server will implicitly convert strings into XML.
  8. command.Parameters.AddWithValue("@demographics", demoXml);
  9. try
  10. {
  11. connection.Open();
  12. Int32 rowsAffected = command.ExecuteNonQuery();
  13. Console.WriteLine("RowsAffected: {0}", rowsAffected);
  14. }
  15. catch (Exception ex)
  16. {
  17. Console.WriteLine(ex.Message);
  18. }
  19. }

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时,它为返回的数据创建必需的表和列(如果这些表和列尚不存在)。他会自动打开与关闭数据库连接。

  1. var sqlConnection = DbHelp.GetSqlConnection();
  2. string sqlString = "SELECT * FROM Student";
  3. SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlString,sqlConnection);
  4. DataSet dataSet = new DataSet();
  5. 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

  1. Data Source=.;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;

2、Access

  1. Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\myDatabase.mdb;User Id=admin;Password=;

3、MySQL

  1. Server=myServerAddress;Database=myDatabase;Uid=myUsername;Pwd=myPassword;

4、DB2

  1. Server=myAddress:myPortNumber;Database=myDatabase;UID=myUsername;PWD=myPassword;

5、Oracle

  1. Data Source=TORCL;User Id=myUsername;Password=myPassword;

四、数据库访问的一般步骤

1、建立数据库连接,并打开,using语句可以自动关闭连接。

  1. //创建连接对象1
  2. using (SqlConnection conn1 = new SqlConnection("连接字符串"))
  3. {
  4. conn1.Open();
  5. }

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;
    }
}