浪漫骑士必胜

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ADO.NET(内含存储过程讲解)

  在现在的很多IT企业当中,都会用到存储过程这个概念,那么,什么是存储过程呢?存储过程有什么好处呢?在实际的运用当中,我们怎么去用存储过程这个技术,这是我们今天文章讨论的主要内容。

 

首先我们说下用数据源绑定的方式实现省市联动.

                       

一、画好省市界面

  我们要把省市数据库里面的所有的省份和直辖市加载到第一个下拉菜单当中。

先确定下sql语句:select *from dbo.TblArea where AreaPid=0

添加配置文件和sqlHelper。

 

二、添加配置文件和sqlHelper

 

三、绑定省数据

下面实现下一个功能,选中一个省在下面对应显示市。

我们在省的下拉菜单的选择项改变事件写代码:

 

四、加载市的代码

下面我们看下问题代码:

 

五、错误代码剖析

如果我先绑定数据源,后设置下拉菜单。就报错了。

 

六、报错信息

 

七、把数据源放到前面的情况,想想为什么会报错呢?

调试一下,第一步,第二步都没有问题。

 

八、调试看到的错误一

 

九、调试看到的错误二

所以我们再看下sql语句执行的是什么?

可以打开事件探查器进行观测。

 

十、打开事件探查器

因为设置DataSouce的数据源对象的时候会触发SelectedIndexChanged事件

在这个事件中,要获取当前选中项的SelectedValue,但是,这时还没有设置ValueMember,所以SelectedValue现在还根本没有具体的列的值,所以就报错了。

 

如果我就是想先:设置数据源的话,那么,我需要这样修改代码。

 

十一、修改后的代码

 

十二、注意:用别名的时候统一用别名

接下来咱们说下:连接查询(join)

什么时候用连接呢?咱们之前说过联合union,联合是把多个结果集连在一起。连接是把多张表列给连接在一起。

连接基于笛卡尔积的。

 

十三、笛卡尔积图解

我们先看下交叉连接:

 

十四、快速创建两张表

 

十五、分别向学生表和成绩表中插入几条数据

 

十六、交叉连接

我们再说下:内连接

 

十七、内连接

多表内连接。无论几张表连接,每次执行都是两张表进行连接。

 

十八、多表进行连接

注意:on只用于主外建的条件筛选,其余条件都用where

那么下面我们就来处理怎么才能处理没有参加考试的同学。

 

十九、左外联

 

二十、没有参加考试的同学

在外连接判断是否为空的时候,建议使用主键。

 

二十一、右外联

左外联和右外联的执行的顺序,首先,拿到笛卡尔积-筛选出来相等的-添加外部行

 

二十二、外联接查询基本过程

下面我们看几个案例:

案例1:查询所有学生的姓名、年龄及所在班级

 

二十三、案例一

案例2:查询年龄超过20岁的学生的姓名、年龄及所在班级

作业

案例3:查询学生姓名、年龄、班级及成绩

作业

案例4:查询所有学生(参加及未参加考试的都算)及成绩

详细说明:

学号,姓名,英语成绩,是否参加了考试’是’、’否’

案例5:请查询出所有没有参加考试(在成绩表中不存在的学生的姓名)。

 

作业:练习1:查询所有英语及格的学生姓名、年龄及成绩

练习2:查询所有参加考试的,english分数不为null学生姓名、年龄及成绩(内联接)

练习3:查询所有学生(参加和未参加考试)的学生姓名、年龄、成绩,如果没有参加考试显示缺考,如果小于english&math60分显示不及格

 

接下来,我们再说个自连接的问题

 

二十四、自连接

如果上面的表中数据太多不好理解的话,请看下面的简单演示:

 

二十五、新建一张表并插入数据

 

二十六、自连接演示

面试题:

单张表A数据量过百万,关联表B数据过千万,如何查询优化

  1. 根据查询,建索引
  2. 先从A,B表中过滤出我要查的数据,存储到临时表里面
  3. 应该把B表分多张来存储

 

下面我们说说临时表

 

二十七、临时表的存储位置

建表的时候前面加个#

就表示这张表是张临时表。

 

二十八、创建临时表

我们创建的临时表,当断开连接的时候就没有了。

 

全局临时表

加##

可以在多个会话中共享,断开连接之后就没有了。

 

二十九、创建全局临时表

下面我们看下视图

视图一般是不存储数据的,sql server有一种索引视图的可以存数据,视图就是用来看数据的。比如说刚才的复杂的子查询得写一堆的子查询,然后可以得到这些结果.别人想查的话每次都得执行一大堆的查询.我们能不能把查询结果保存起来,用户看的时候直接从视图里看就行了.

 

三十、创建视图

视图的好处:筛选表中的行,降低数据库的复杂程度

防止未经许可的用户访问敏感数据—操作表是得有些权限,创建完表以后,我再创建一些视图,如果用户只有查询的权限,那么我根本不授予你查询表的权限,而是只授予你查询视图的权限。即便是你攻破了数据库用户也是只能看到视图。

 

本身视图并不存储数据,它里的数据来源自查询的。表中数据改了,根据视图当中查询的数据也改了。

在视图中的查询不能使用order by,

 

三十一、视图中不能用order by

如果我就想让它排序怎么办呢?

 

三十二、正规的视图排序方法

为什么在视图里面不能用order by呢?order by把数据变成有序的了。视图变成别人的数据源,是集合不能有序。

 

三十三、指定top

为什么指定top就可以了呢?本身order by以后的数据是有序的,top查询完成以后,这个数据就又变成无序的了。又变成一个集合了,集合就能成为数据源的。

再基于视图进行升序排序就怎么样都行了。

 

接下来我们看下

在sql里面怎么声明变量,怎么写if语句,怎么写循环,怎么编程。

 

三十四、SQL编程声明变量并赋值

 

三十五、声明变量的第二种写法,打印出来是川川

 

三十六、声明和赋值常见的几种情况

 

三十七、set和select赋值时的区别

上面我们所说的这些都是局部变量,局部变量使用的时候前面加一个@符号,全局变量使用的时候前面加两个@符号。全局变量不是我们声明的,也不是我们赋值的,全局变量是系统有的那么几个。只能拿来用,我们没有资格对其声明或者赋值。

 

三十八、部分全局变量

大家想看所有的全局变量,可以在帮助里面-搜索

 

三十九、在帮助中搜索所有的全局变量

可以通过全局变量做以下的事情:

 

四十、几个常用的全局变量

下面说说if-else 还有循环

 

四十一、if-else, while

计算平均分数并输出,如果平均分数超过60分输出成绩最高的三个学生的成绩,否则输出后三名的学生

 

四十二、题目答案

作业:

1.如果english不及格的人超过半数(考试题出难了),则给每个人增加2分,循环加,直到不及格的人数少于一半。

 

 

2.把所有未及格的人的成绩都加及格(把所有小于60分的学生,变成60就成了)

 

下面我们说说事务:

什么叫事务呢?我们做一个事情,分好几个步骤,每个步骤都做完才认为是成功,否则的话失败。

如,转账问题:

假定钱从A转到B,至少需要两步:

A的资金减少

然后B的资金相应增加

 

事务的ACID特性:

事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。

原子性

事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。

一致性

事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。

隔离性

由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。

持久性

事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。

 

下面我们看看怎么在程序中怎么去写事务:

 

四十三、Sql sever默认是自动提交事务

案例:

 

四十四、案例

下面我们简单的看下锁

 

四十五、锁的问题

 

四十五2、隐士事务

下面我们讲解今天的重点:存储过程

我们先来说说为什么要用存储过程,怎么去写,怎么去调。在ADO里面怎么去用。

为什么要用存储过程呢?第一,我们以前写代码,要执行一堆的sql语句,得通过应用程序把sql语句发送给服务器,然后才能执行,sql语句越长,交互的数据量越大,性能越低.

这个时候我们把所有的代码封装到存储过程里面,就像函数一样封装起来.当我们要使用的时候,直接调一个存储过程的名称,就搞定了.

这样的话,减少了网络流通量.再一个,存储过程是提前在数据库里面建好的,已经编译过了,直接调用执行就行了,不需要在编译了.

再一个可以防止我们的sql注入攻击.

允许代码重用.在数据库里面建一个存储过程,只要用到这个功能,调它就行了.

 

系统中有些存储过程,我们也可以自己定义一些存储过程.

系统中的存储过程就以sp或xp开头.

                       

四十六、看下有多少个数据库

 

四十七、查看系统存储过程源代码

 

四十八、看下当前数据库里面有多少张表

 

四十九、看下存储过程的源代码

自定义的存储过程我们以usp开头

 

五十、没有参数,没有返回值的存储过程

 

五十一、自定义存储过程求和

 

五十二、修改存储过程

 

五十三、修改存储过程二

 

五十四、修改存储过程三

接下来我们介绍下输出参数

                       

五十五、输出参数

输出参数也非常的重要,很多时候参数执行完后要拿到一个值,就可以通过输出参数拿到这个值。

还记得我们之前的博文中说过带参数的sql语句么?带参数的sql语句最终执行的时候,就是调的存储过程来执行的.下面执行的时候给大家看一下.

我们之前的案例,像给学生提分的案例就可以拿存储过程来做.

 

 

编写存储过程

作业:考试题出难了,降低及格分数线,(将该题目封装为一个存储过程。)

编写存储过程usp_upGrade

要求传入参数:@pass float

  调用存储过程,及格分数线,给没及格的人提分

 

接下来我们说下怎么通过ADO.net来调用存储过程。

写段简单的代码,向bank表中插入条记录:

                       

五十六、通过ADO.net调用存储过程---画个界面

 

五十七、常规的方法

但是这样写报错了,大家看看是什么错?

 

五十八、系统报的错误

 

五十九、再加个参数,报错就没了,原因是少给了一个参数

 

六十、修改后的代码

下面我们写调存储过程进行插入,首先数据库里面得有存储过程。所以,在数据库里面建个存储过程。

 

六十一、建好存储过程

 

六十二、打开对象资源管理器,记下存储过程名

 

六十三、带参数的sql语句调的存储过程

 

六十四、告诉command对象执行的是什么

 

六十五、使用存储过程实现插入代码

 

六十六、执行的过程当中又报错了

没给它写参数,很多刚入行的程序员都会出现这样的问题,其实,老程序员也会出现这样的问题。大家在遇到这样的问题的时候,请不要紧张,静下心来找找,就行了。

 

六十七、执行之前增加参数

下面我们通过存储过程写下存储过程版的增,删,查,改。

 

六十八、添加配置文件

 

六十九、需要插入的表

这是我们需要插入数据的表,后两列是默认值,所以插入前两列就行了。

 

七十、画好我们需要的界面

在写之前还是需要观察一下我们上面写的存储过程版的增加和带参数的Sql语句有什么不一样的地方呢?

 

七十一、存储过程版的增加和带参数的Sql语句有什么不一样的地方

 

七十二、新建存储过程SqlHelper添加命名空间

 

七十三、执行insert、delete、update的存储过程版SqlHelper

 

七十四、执行返回单个值的方法

 

七十五、执行返回Reader

 

七十六、执行返回DataTable

插入代码:SqlHelperProc位置:

View Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Configuration;
  6 using System.Data;
  7 using System.Data.SqlClient;
  8 
  9 namespace _03SqlHelper加配置文件加存储过程实现表的增删查改
 10 {
 11     /// <summary>
 12     /// 通过存储过程来实现SqlHelper
 13     /// </summary>
 14     public static class SqlHelperProc
 15     {
 16         //需要添加引用
 17         private static readonly string constr = ConfigurationManager.ConnectionStrings["sql"].ConnectionString;
 18         #region 执行insert、delete、update
 19 
 20         public static int ExecuteNonQuery(string sql, CommandType cmdType, params SqlParameter[] pms)
 21         {
 22             using (SqlConnection con = new SqlConnection(constr))
 23             {
 24                 using (SqlCommand cmd = new SqlCommand(sql, con))
 25                 {
 26                     cmd.CommandType = cmdType;
 27                     if (pms != null)
 28                     {
 29                         //添加参数
 30                         cmd.Parameters.AddRange(pms);
 31                     }
 32                     con.Open();
 33                     //当执行存储过程的时候到底要调哪个ado.net方法,依赖于存储过程中封装的是什么sql语句,如果是增删改则调ExecuteNonQuery();,返回单个值的则调ExecuteScalar()如果是查询大量数据则调ExecuteReader().
 34                     //当存储过程中封装的代码较为复杂时,可以考虑根据最终存储过程调用完毕后需要的返回值来决定,如果最后存储过程查询出了大批数据需要获取,则用Reader,单个值还是用ExecuteScalar(),如果执行完毕存储过程不需要什么返回值,则可以直接调用ExecuteNonQuery()来执行。
 35                     return cmd.ExecuteNonQuery();
 36                 }
 37             }
 38         }
 39         #endregion
 40 
 41         #region 执行返回单个值的方法
 42         public static object ExecuteScalar(string sql, CommandType cmdType, params SqlParameter[] pms)
 43         {
 44             using (SqlConnection con = new SqlConnection(constr))
 45             {
 46                 using (SqlCommand cmd = new SqlCommand(sql, con))
 47                 {
 48                     cmd.CommandType = cmdType;
 49                     if (pms != null)
 50                     {
 51                         cmd.Parameters.AddRange(pms);
 52                     }
 53                     con.Open();
 54                     return cmd.ExecuteScalar();
 55                 }
 56             }
 57         }
 58         #endregion
 59 
 60         #region 执行返回Reader
 61         public static SqlDataReader ExecuteReader(string sql, CommandType cmdType, params SqlParameter[] pms)
 62         {
 63             SqlConnection con = new SqlConnection(constr);
 64             using (SqlCommand cmd = new SqlCommand(sql, con))
 65             {
 66                 cmd.CommandType = cmdType;
 67                 if (pms != null)
 68                 {
 69                     cmd.Parameters.AddRange(pms);
 70                 }
 71                 try
 72                 {
 73                     con.Open();
 74                     return cmd.ExecuteReader(CommandBehavior.CloseConnection);
 75                 }
 76                 catch
 77                 {
 78                     con.Close();
 79                     con.Dispose();
 80                     throw;
 81                 }
 82             }
 83         }
 84         #endregion
 85 
 86         #region 执行返回DataTable
 87         public static DataTable ExecuteDataTable(string sql, CommandType cmdType, params SqlParameter[] pms)
 88         {
 89             using (SqlDataAdapter adapter=new SqlDataAdapter(sql,constr))
 90             {
 91                 adapter.SelectCommand.CommandType = cmdType;
 92                 if (pms!=null)
 93                 {
 94                     adapter.SelectCommand.Parameters.AddRange(pms);
 95                 }
 96                 DataTable dt = new DataTable();
 97                 adapter.Fill(dt);
 98                 return dt;
 99             }
100         }
101         #endregion
102     }
103 }

下面我们试着用下:

我们发现上面的SqlHelper不光可以执行存储过程,如果把cmdType变成Test的话,也可以执行sql语句,这个存储过程和sql语句都是可以执行的。

在写存储过程的时候有个输出参数,在调用的时候可以拿到,当通过ADO调的时候怎么拿到那个输出参数呢?

 

七十七、写好执行插入的存储过程

 

七十八、最后插入的代码

 

七十九、最后的报错,什么原因呢?

我的代码没有问题,体统就是报这个错,大家见过么?帮我解答一下子。

 

作者近期文章列表:

C#基础教程(完全免费,献给代码爱好者的最好礼物。注:本作者分享自己精心整理的C#基础教程,无任何商业目的。
希望与更多的代码爱好者交流心得,也请高手多多指点!!!)
三层及其它内容 递归
三层(一)
三层相关案例(及常见的错误)
三层实例(内涵Sql CRUD)
手写代码生成器
SQL数据库 ADO.net 数据库的应用图解一
数据库的应用详解二
ADO.NET(内涵效率问题)
ADO.NET实例教学一
面向过程,面向对象中高级 面向过程,面向对象的深入理解一
面向过程,面向对象的深入理解二
面向对象的深入理解三
winform基础 Winform基础
winform中常用的控件
面向过程 三种循环的比较
C#中的方法(上)
我们常见的数组
面向对象 思想的转变
C#中超级好用的类
C#中析构函数和命名空间的妙用
C#中超级好用的字符串
C#中如何快速处理字符串
值类型和引用类型及其它
ArrayList和HashTable妙用一
ArrayList和HashTable妙用二
文件管理File类
多态
C#中其它一些问题的小节
GDI+ 这些年我收集的GDI+代码
这些年我收集的GDI+代码2
HTML概述以及CSS 你不能忽视的HTML语言
你不能忽视的HTML语言2精编篇
你不能忽视的HTML语言3
CSS基本相关内容--中秋特别奉献
CSS基本相关内容2
JavaScript基础 JavaScript基础一
jQuery jQuery(内涵: jquery选择器)
posted on 2012-12-07 17:43  小事好  阅读(4718)  评论(10编辑  收藏  举报