笔记02-.Net基础2

第五章:.Net常用基本类库

String 常用方法1

//bool Contains(String str):判断字符串对象是否包含给定的字符串。

//bool StartsWith(String str):判断字符串对象是否以给定的字符串开始。

//bool EndsWith(String str):判断字符串对象是否以给定的字符串结束。

            /*string s1 = "Hello";
            Console.WriteLine(s1.Contains("el"));
            Console.WriteLine(s1.Contains("abc"));
             */
            /*
            Console.WriteLine(s1.StartsWith("He"));
            Console.WriteLine(s1.StartsWith("he"));
             */

            /*
            string s = "http://www.rupeng.com";
            if (s.StartsWith("https://") &&
                (s.EndsWith(".com") || s.EndsWith(".cn")))
            {
                Console.WriteLine("合法网址");
            }
            else
            {
                Console.WriteLine("非法网址");
            }*/
            /*
            string email = "3333@173.com";
            string username = "领导";
            if (email.EndsWith("@qq.com"))
            {
                Console.WriteLine("本站不支持QQ邮箱");
                Console.ReadKey();
                return;
            }
            if (username.Contains("领导") || username.Contains("总书记"))
            {
                Console.WriteLine("用户名请勿使用敏感词汇");
                Console.ReadKey();
                return;
            }*/
View Code
int Length:获取字符串的长度属性

char ch = s[3];

int IndexOf(char ch):返回指定字符在此字符串中第一次出现的索引

int IndexOf(String str):返回指定字符串在此字符串中第一次出现的索引

LastIndexOf:最后一次出现的位置。

String Substring(int start):截取字符串。返回从指定位置开始截取后的字符串。

String substring(int start,int length)截取字符串。返回从指定位置开始截取指定长度length的字符串。

            string s1 = "hellooabcdaabe";
            int i = s1.IndexOf('l');
            Console.WriteLine(i);
            Console.WriteLine(s1.IndexOf("ab"));
            Console.WriteLine(s1.LastIndexOf('l'));

            string s2 = s1.Substring(4);
            Console.WriteLine(s2);
            Console.WriteLine(s1.Substring(4,3));
案例获取一个文件名的名称和扩展名部分:

            string filename = "[ADS-118]林志aaaaaa玲.avi";//
            int dotIndex = filename.IndexOf('.');//3
            string name = filename.Substring(0, dotIndex);
            Console.WriteLine(name);
            string ext = filename.Substring(dotIndex + 1);
            Console.WriteLine(ext);
View Code
String ToLower():把字符串变成小写;String ToUpper():把字符串变成大写

String Replace(char oldChar,char newChar):用新的字符去替换指定的旧字符;String Replace(String oldStr,String newStr):用新的字符串去替换指定的旧字符串

String trim():去除字符串两端空格, Trim(params char[] trimChars)去掉两端的给定字符。 TrimEnd、 TrimStart

String是不可变的,因此上面的操作都是生成新的字符串对象,要用返回值去取新的字符串。

String[] Split(...):重载方法很多,字符串按照分隔符切割。案例:把字符串用“,”分割
View Code
bool IsNullOrEmpty(string value):判断字符串是否为null或者是空字符串;

bool Equals(string a, string b, StringComparison. OrdinalIgnoreCase):不区分大小写比较。案例:验证码

string Join(string separator, params string[] value)把一个数组(集合)用分隔符separator连接为一个字符串。
View Code

 StringBuilder

1、使用反编译发现

String s7="111"+"222"+"333"+"444"+"555"  

会被优化为  String s7 = "111222333444555";

但是String s6 = s1 + s2 + s3 + s4 + s5;就没那么幸运了,每次+都会生成一个String对象,当连接字符串比较多的时候就会产生临时字符串对象。

2、使用StringBuilder拼接字符串则不会有临时字符串对象的问题:

StringBuilder sb = new StringBuilder();

sb.Append(s1);

sb.Append(s2);

sb.Append(s3);

因为Append方法把this返回了,还可以sb.Append(s1).Append(s2).Append(s3);

最后使用String s = sb.ToString()一次性生成拼接结果字符串即可

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CommonClassTest2
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
            string s1 = "aaa" +
                +"aaaaa"+"bbb";
            Console.WriteLine(s1);
             */
            string s1 = "aaa";
            string s2 = "bbb";
            string s3 = "ccc";
            string s4 = "ddd";
            string s5 = "afadsf";
            string s6 = s1 + s2 + s3 + s4 + s5;

            StringBuilder sb = new StringBuilder();
            /*
            sb.Append(s1);
            sb.Append(s2);
            sb.Append(s3);
            sb.Append(s4);
            sb.Append(s5);
            sb.Append(33);*/
           sb.Append(s1).Append(s2).Append(s3).Append(s4).Append(s5);
           sb.AppendLine("hello");
           sb.AppendLine("afasdfads");

            string s7 = sb.ToString();
            Console.WriteLine(s7);

            Person p1 = new Person();
            p1.Eat().Sleep().Dota();//链式编程 Jquery
            Console.ReadKey();
        }
    }

    class Person
    {
        public Person Eat()
        {
            Console.WriteLine("吃饭");
            return this;
        }
        public Person Sleep()
        {
            Console.WriteLine("睡觉");
            return this;
        }
        public Person Dota()
        {
            Console.WriteLine("打Dota");
            return this;
        }
    }
}
View Code

 可空的int(值类型)

int等是值类型,不能为null。有时想表达“不知道数字是多少”的时候,用int任何值表示都不合适。

C#中可以用“int?”表示“可空的int”。注意类型转换:

int? i1=5;

if(i1!=null)

{

    int i= (int)i1;

}

也可以通过i1.HasValue判断是否为null、i1.Value来获得值。

int? i = null;
int? i2 = 3;
if (i == null)
{
    Console.WriteLine("i为null");
}
if (i2 != null)//i2.HasValue
{
    //i2++;
    i2 = i2 + 3;
    //int i3 = i2;//把可能为null的int?赋值给
    //一定不为null的int
    int i3 = (int)i2;//i2.Value
    Console.WriteLine(i2);
}
long? l = null;
View Code

LED时钟

 private void timer1_Tick(object sender, EventArgs e)
        {
            string imgPath = 
    @"F:快盘NextBigNET课程5_不拖控件的.Net(.net常用基本类库)ledclock图片";

            DateTime now = DateTime.Now;
            int hour = now.Hour;
            int min = now.Minute;
            int sec = now.Second;

            int hourGe = hour % 10;//小时的个位
            int hourShi = hour / 10;//小时的十位

            int minGe = min % 10;
            int minShi = min / 10;

            int secGe = sec % 10;
            int secShi = sec / 10;

            pbHourShi.Load(imgPath+hourShi+".png");
            pbHourGe.Load(imgPath + hourGe + ".png");

            pbMinShi.Load(imgPath + minShi + ".png");
            pbMinGe.Load(imgPath + minGe + ".png");

            pbSecShi.Load(imgPath+secShi+".png");
            pbSecGe.Load(imgPath + secGe + ".png");

            //根据奇数秒还是偶数秒来决定“:”的闪烁
            if (sec % 2 == 0)
            {
                pbColon1.Load(imgPath + "colon.png");
                pbColon2.Load(imgPath + "colon.png");
            }
            else
            {
                pbColon1.Load(imgPath + "empty.png");
                pbColon2.Load(imgPath + "empty.png");
            }
        }
View Code

 把阿拉伯数字转换为中文金额数字:123→壹佰贰拾三圆

//附录:阿拉伯数字转换为中文

        static void Main(string[] args)

        {

            Console.WriteLine(ConvertInt("123"));

            Console.WriteLine(ConvertInt("1003"));

            Console.ReadKey();

        }



        public static string ConvertInt(string str)

        {



            string[] hanNums={"","","","","", "", "","","",""};

            string[] weiStrs={"","","","","","","","","","","","",""};

            int len = str.Length;

            int i;

            string tmpstr, rstr;

            rstr = "";

            for (i = 1; i <= len; i++)

            {

                tmpstr = str.Substring(len - i, 1);

                rstr = string.Concat(hanNums[Int32.Parse(tmpstr)] + weiStrs[i], rstr);

            }

            rstr = rstr.Replace("拾零", "");

            rstr = rstr.Replace("零拾", "");

            rstr = rstr.Replace("零佰", "");

            rstr = rstr.Replace("零仟", "");

            rstr = rstr.Replace("零萬", "");

            for (i = 1; i <= 6; i++)

            { 

                rstr = rstr.Replace("零零", "");

            }

            rstr = rstr.Replace("零萬", "");

            rstr = rstr.Replace("零億", "");

            rstr = rstr.Replace("零零", "");

            rstr += "圆整";



            rstr = rstr.Replace("零圆", "");

            return rstr;

        }
View Code

 异常的概念和捕获

//1、异常的根类为Exception。异常类一般都继承自Exception

//2、

try

{

    String s = null;

    s.ToString();

}

catch (NullReferenceException ex)

{

    Console.WriteLine("为空"+ex.Message);

} 

//e就是发生异常的异常类对象,变量名只要不冲突就任意。

//3、在异常处理中,一旦try里面有问题了。放弃try代码块中之后的代码,直接跳到catch里面执行。如果try代码后还有代码,则处理完catch后还会继续执行。

//4、多个异常的处理

try
{
    int a = 10;
    int b = 0;
    Console.WriteLine(a / b);
    int[] arr = { 1, 2, 3 };
    Console.WriteLine(arr[3]);
}
catch (DivideByZeroException ae)
{
    Console.WriteLine("除数不能为0");
}
catch (IndexOutOfRangeException ae)
{
    Console.WriteLine("数组越界异常");
}
//可以catch住父类异常,这样就可以抓住所有子类异常了,但是强烈不建议大家这样做,特别是不要没理由的catch(Exception ex)

//5、好的异常处理习惯:

//不要只是把异常catch住什么都不做或者只是打印一下,这不是正常的“异常处理”。

//不知道怎么处理就不要catch,出错比“把错误藏起爱”好。这样以为“不会出错了”,其实是把异常“吃掉了”,会让程序陷入逻辑混乱状态,要科学合理的处理异常(以后经常用就明白了)。
View Code

 tryfinally

try{
//有可能有问题代码
}catch(异常类型 异常变量){
//处理方式
}finally{
//无论“有可能有问题代码”是否出错都要执行的代码
}
//注意:在vs调试的情况下,finally的执行可能看不到,因为vs会把异常抛出阻断代码执行,如果想验证是否都会进入finall,可以按CTRL+F5执行程序。
View Code
finally 的执行条件只有这一个。
很可能在 try-catch 里直接 returnbreakcontinue ,导致跳出 try-catch 结构。你可能会想当然的认为既然我 return 了直接返回结果 finally 里的代码就不会执行。这是错误的!因为 finally 执行条件只是【try-catch 结构执行完】,即使 try-catchreturn 了,依然还是会先执行 finally 里的代码,然后才会真的 return。
而你要是不用 finally,直接把最后要统一执行的代码放在 try-catch 外面,那 try-catchreturn,你的代码就不会被执行了。
所以 finally 最常用的地方是在里面释放对象占用的资源的。
View Code

 File类

File是静态类(无法被new)中的主要静态方法:

void Delete(string path):删除文件;

bool Exists(string path):判断文件是否存在;

string[] ReadAllLines(string path):将文本文件中的内容读取到string数组中;

string ReadAllText(string path):将文本文件读取为一个字符串

void WriteAllLines(string path, string[] contents):将string[]写入到文件中;

void WriteAllText(string path, string contents):将字符串contents写入到文件path中。

AppendAllText:向文件中附加内容;Copy复制文件;Move移动文件

/*
if(File.Exists(@"d:	empa.pnproj"))
{
    File.Delete(@"d:	empa.pnproj");
}*/

/*
string[] lines = File.ReadAllLines(@"d:	empmy.txt",
    Encoding.Default);
for (int i = 0; i < lines.Length; i++)
{
    Console.WriteLine("第"+i+"行:"+lines[i]);
}*/
/*
String s = File.ReadAllText(@"d:	empmy.txt");
Console.WriteLine(s);
    */
// File.WriteAllText(@"d:	emp	est.txt", "欢迎你");
//File.AppendAllText(@"d:	emp	est.txt", "afasfsafadsf");
View Code

 Directory

CreateDirectory(string path):创建文件夹全路径

void Delete(string path, bool recursive):删除文件夹path, recursive表示是否也删除子文件及子文件夹。如果文件夹不为空, recursive=false,则抛异常;

bool Exists(string path):判断文件夹是否存在

EnumerateFiles、 EnumerateDirectories遍历文件和文件夹;

// Directory.CreateDirectory(@"d:	empac");
//Directory.Delete(@"d:	emp");//目录=文件夹,只能删除空文件夹
//Directory.Delete(@"D:	emp
edissessiontest", true); //递归删除

IEnumerable<string> files1 =
    //Directory.EnumerateFiles(@"d:	emp");
    //Directory.EnumerateFiles(@"d:	emp","*.*",SearchOption.AllDirectories);
    Directory.EnumerateFiles(@"d:	emp", "*.avi", SearchOption.AllDirectories);
IEnumerator<string> filesEnum1 = files1.GetEnumerator();
while (filesEnum1.MoveNext())//在结果中向下移动一条
{
    Console.WriteLine(filesEnum1.Current);//获得当前结果
}
View Code

 FileStream

FileStream fs = new FileStream(@"d:	emp1.txt",FileMode.Create);
byte[] bytes1 = Encoding.Default.GetBytes("你好
");
//任何数据都是以byte为单位写入的。GetBytes获得字符串的byte表示形式
fs.Write(bytes1,0,bytes1.Length);

byte[] bytes2 = Encoding.Default.GetBytes("www.baidu.com");
fs.Write(bytes2,0,bytes2.Length);//在上一个Write的结尾继续写入
fs.Close();//一定要用完了关闭
Stream写入的单位是byte(字节),char转换为byte时候,一个英文char转换为一个byte(对应的ASCII码),一个中文char转换为两个byte(*采用GBK编码时),试着输出bytes的长度。

采用Default、UTF8、UTF32得到的字符串的byte[]长度不一样,因此说明不同类型编码在计算机中存储的不一样。用什么编码写入就用什么编码读取,否则会有乱码的问题。

不要往C盘写,因为Win7、Win8默认普通程序没有权限读写C盘。
View Code

 FileStream资源正确的释放Dispose

            FileStream f = null;
            FileStream f2 = null;//避免来不及创建就已经出异常(可能初始化就失败)
            try
            {
                f = new FileStream("",FileMode.OpenOrCreate);//可能初始化异常
                //很多代码
                //如果这个过程里异常 f2还未初始化.
                f2 = new FileStream("",FileMode.Append);
            }
            finally
            {
                if(f!=null)
                {
                    f.Dispose();
                }
                if (f2 != null)
                {
                    f2.Dispose();
                }
            }
View Code

 using简化资源释放

定义一个实现了IDisposable接口的类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IOTest2
{
    class MyFileStream:IDisposable
    {
        public MyFileStream()
        {
            //throw new Exception("初始化出错");
        }

        public void Write(int i)
        {
            throw new Exception("Write出错");
            Console.WriteLine("写入了"+i);
        }

        public void Dispose()
        {
            Console.WriteLine("Dispose被调用了,开始释放资源,虽然没什么可释放的");
        }
    }
}


使用:

using (MyFileStream fs1 = new MyFileStream())
{
    using (MyFileStream fs2 = new MyFileStream())
    {
        fs2.Write(333);
        fs1.Write(5);
    }
}


可以同时声明多个资源:

using (MyFile f1 = new MyFile())

using (MyFile f2 = new MyFile())

{

}

using其实就是编译器简化的try……finally操作,通过ILSpy反编译成IL可以看出来。

using只是try……finally,如果需要catch,只要catch就是了。
View Code

 FileStream读取文本文件以及乱码问题(可以用StreamReader)

using (FileStream fs = new FileStream(@"D:	emp1.txt", FileMode.Open))
{

    byte[] bytes = new byte[4];
    //fs.Read(bytes, 0, bytes.Length);//每次读取4个字节,下次Read的时候再读取最多4个byte
    //返回值为真正读取的字节数
    int len;
    /*
    len = fs.Read(bytes, 0, bytes.Length);
    Console.WriteLine(len);
    len = fs.Read(bytes, 0, bytes.Length);
    Console.WriteLine(len);
    len = fs.Read(bytes, 0, bytes.Length);
    Console.WriteLine(len);
        */

    //判断是否已经读到了最后
    while ((len = fs.Read(bytes, 0, bytes.Length)) > 0)
    {
        //Console.WriteLine(len);
        //把byte数组转化为字符串
        //string s = Encoding.Default.GetString(bytes);
        string s = Encoding.Default.GetString(bytes, 0, len);
        Console.WriteLine(s);
    }

}
View Code

 FileStream实现文件的拷贝

Stopwatch sw = new Stopwatch();
sw.Start();
using (Stream inStream = 
    new FileStream(@"d:	empDevCpp.zip", FileMode.Open))
using (Stream outStream =
    new FileStream(@"e:	emp1.zip", FileMode.Create))
{
    //byte[] bytes = new byte[100];//100字节
    //1024字节=1k,1024k=1m
    byte[] bytes = new byte[1024*50];//1M
    //缓冲区(buffer)的大小:过小:降低速度;过大:占用内存
    int len;
    while ((len = inStream.Read(bytes, 0, bytes.Length)) > 0)
    {
        outStream.Write(bytes, 0, len);//类似于GetString
    }
}
sw.Stop();
Console.WriteLine("拷贝完成,耗时" + sw.ElapsedMilliseconds+"毫秒");
View Code

 封装Copy流的方法并开发下载器

static void Copy(Stream inStream, Stream outStream)
{
    Copy(inStream, outStream, 1024 * 1024);
}

static void Copy(Stream inStream,Stream outStream,int bufferSize)
{
    byte[] bytes = new byte[bufferSize];
    int len;
    while ((len = inStream.Read(bytes, 0, bytes.Length)) > 0)
    {
        outStream.Write(bytes, 0, len);
    }
}

using (Stream inStream = new FileStream(@"d:	empDevCpp.zip",FileMode.Open))
using (Stream outStream = new FileStream(@"d:	emp1.zip", FileMode.Create))
{
    Copy(inStream, outStream);
}


文件下载器:

WebRequest req = WebRequest.Create("http://www.baidu.com/img/bd_logo1.png");
using (WebResponse res = req.GetResponse())
using (Stream inStream = res.GetResponseStream())
using(Stream outStream = new FileStream(@"d:	emp2.png",FileMode.Create))
{
    //inStream.CopyTo(
    Console.WriteLine(inStream.GetType());//Object o = new Person();
    //Copy(inStream, outStream);
    inStream.CopyTo(outStream);
}
View Code

 StreamReader和StreamWriter

直接用Stream进行文本文件的读写会比较麻烦,因为要考虑文件的编码、中文字符等的问题。

StreamReader、StreamWriter是用来读写字符流(character stream)的类,会帮着自动处理麻烦的问题。

using (Stream outStream = 
    new FileStream(@"d:	emp1.txt", FileMode.Create))
using(StreamWriter sw = 
    new StreamWriter(outStream,Encoding.Default))
{
    sw.Write("你好a");
    sw.WriteLine("hehe");
    sw.WriteLine("1111");
}
using (Stream inStream = new FileStream(@"d:	emp1.txt",
    FileMode.Open))
using (StreamReader reader =
    new StreamReader(inStream, Encoding.Default))
{
    /*
    string s = reader.ReadToEnd();
    Console.Write(s);*/
    /*
    string s1 = reader.ReadLine();
    Console.WriteLine(s1);

    string s2 = reader.ReadLine();
    Console.WriteLine(s2);
        */
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}
View Code

 泛型List

1、数组长度是固定的,List<T>可以动态增删内容。List<T>是泛型的,可以在声明的时候指定放什么类型的数据。

List<int> list = new List<int>();

list.Add(1);

list.Add(2);

list.AddRange(new int[] { 1, 2, 3, 4, 5, 6 });

list.AddRange(list);//另一个list



2、如何遍历?

for (int i = 0; i < list1.Count; i++)

{

    int num = list1[i];

    Console.WriteLine(num);

}



3int[] nums = list.ToArray(); //List泛型集合可以转换为数组

List<string> listStr = new List<string>();

string[] str = listStr.ToArray();
View Code

 字典Dictionary

Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("zs", "张三");
dict.Add("ls", "李四");
dict.Add("ww", "王五");
dic["ls"] = "小赵";
String s = dict["ww"];
dict.ContainsKey();

//<k,v>k是键的类型(根据谁查),v是值的类型(查什么)
/*
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("abc", 123);//往字典中放数据(k,v)
dict.Add("aaa", 222);
int i = dict["abc"];//根据key从字典中查数据
Console.WriteLine(i);
Console.WriteLine(dict["aaa"]);*/

/*
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("zs","张三");
dict.Add("ls", "李四");
// dict.Add("ls","李斯");// 如果key已经存在,则抛异常
dict["ls"] = "李斯";//如果不存在key,则添加;如果存在则替换
dict["ww"] = "王五";
            
string name = dict["ls"];
Console.WriteLine(dict.ContainsKey("ls"));
Console.WriteLine(dict.ContainsKey("abc"));
Console.WriteLine(name);
View Code

 foreach

注意:使用MoveNext()的方法讲解IEumerable只是在讲原理,实际开发中还是使用foreach



除了使用for遍历,实现了IEumerable接口的对象还可以使用foreach遍历:

string[] strs = { "fasdfa","fsadf","222"};
foreach (string s in strs)
{
    Console.WriteLine(s);
}
List<T>、 Dictionary<K,V> 等一切实现了IEumerable接口的对象都可以:

Dictionary<string, object> dict = new Dictionary<string, object>();
dict["rupeng"] = 888;
dict["sina"] = "hehe";
dict["baidu"] = true;
foreach (KeyValuePair<string, object> kv in dict)
{    
   Console.WriteLine(kv.Key+"="+kv.Value);
}
View Code

 ASCII介绍和char转换为int

char和int各种转换

namespace ConsoleApplication7
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
            Console.WriteLine(int.MaxValue);
            Console.WriteLine(int.MinValue);

            Console.WriteLine((int)char.MaxValue);//65535,显式转换,以便于匹配WriteLine的int类型的重载
            Console.WriteLine((int)char.MinValue);//0

            char c='a';
            Console.WriteLine(c);
            int i = c;//把char隐式转换为int(int范围比char大)
            //只要把char数据隐式或者显式转换为int,得到的int就是char的ASCII码
            Console.WriteLine(i);
            */

            /*
            char c = (char)97;
            Console.WriteLine(c);

            int i = 98;
            char c1 = (char)i;
            Console.WriteLine(c1);*/

            /*
            //'1'和1的区别
            char c1 = '1';//49
            int i1 = 1;//1
            int i2 = c1;
            Console.WriteLine(i2);
            Console.WriteLine(c1==i1);
            */

            /*
            char c1 = '0';
            char c2 = (char)(c1 + 2);//不能(char)c1+1
            Console.WriteLine(c2);

            char c3 = '5';
            char c4 = (char)(c3-2);
            Console.WriteLine(c4);
            */

            //Console.WriteLine(intToChar(5));

            //Console.WriteLine(charToInt('3'));
            Console.WriteLine(toUpper('d'));

            Console.ReadKey();
        }

        /// <summary>
        /// 把1转换为'1',2转换为'2'
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>        
        static char intToChar(int i)
        {
            if (i < 0 || i > 9)
            {
                throw new Exception("i必须在0-9之间");
            }
            return (char)('0' + i);//i=3
        }

        /// <summary>
        /// 把'1'转换为1
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        static int charToInt(char c)
        {
            //'0','1'....'9'
            if (c < '0' || c > '9')//判断是否是数字字符
            {
                throw new Exception("不是合法的数字字符");
            }
            return c - '0';
        }

        //'a'→'A'
        static char toUpper(char c)
        {
            if (c < 'a' || c > 'z')
            {
                throw new Exception("不是小写字符");
            }
            //'a':97,'A':65;'c':99,'C':67
            //研究发现小写字符比大写字符大32
            //return c
            //return (char)(c - 32);
            return (char)(c-('a'-'A'));
        }

        //任务:写一个转换为小写的方法
    }
}
View Code

 第六章MYSQL

安装运行

绿色版MYSQL Server的安装:

1)解压到没有中文、空格的文件夹下

2)双击mysqld.exe,如果进程中有了mysqld.exe就ok了

3)上面的方式需要每次重启电脑都要手动运行,特别是如果运行在服务器上,那么不能在登录前就启动。可以注册为系统服务:以管理员身份运行命令行,cd到mysql的bin文件夹,执行“mysqld -install”;卸载服务:mysqld -remove。

注意在“mysqld”后面有个空格,不要写成“mysqld-install”



绿色版MYSQL的用户名、密码都是:root
View Code

 主键

主键有两种选用策略:业务主键和逻辑主键。业务主键是使用有业务意义的字段做主键,比如身份证号、银行账号等;逻辑主键是使用没有任何业务意义的字段做主键,完全给程序看的,业务人员不会看的数据。因为很难保证业务主键不会重复(身份证号重复)、不会变化(帐号升位),因此推荐用逻辑主键。
View Code

 外键

B表中的字段指向A表的字段,叫外键.比如2个表关联主键

建数据库立表的方法(表名命名:T_Student)

1、根节点点右键“新建数据库”,数据库名字取得有意义,比如“study1”、字符集建议用"UTF-8"。复习:读写编码一致就不会乱码。

2、在study1下的“表”节点下点右键“新建表”,“栏位”其实指的就是列(Column)/列,翻译的不好。Id(主键,潜规则的名称,int、不允许为空、点右键“主键”)、Name(varchar,长度为10,不允许为空)、Gender(bit,不允许为空),保存为“T_Persons”(我习惯的表命名规则T_名词复数)

3、建表常见错误:列名/表名不要用可能的关键字、不要有空格(包括前后,一不小心输错试试)、不要有特殊字符

双击生成的表,手工插入两条数据,注意点“提交”按钮

4、MYSQL的存储引擎有很多,最常用的是InnoDB和MyISAM,MyISAM效率较高,但是不支持事务、外键约束等特性,因此一般建议用InnoDB,新版本默认也是InnoDB。怎么设:建表时“选项”→“引擎”。建好了如何看引擎:表上点右键“对象信息”。
View Code

 MYSQL常用数据类型

文本:

CHAR(*):最多255个字节的定长字符串,它的长度必须在创建时指定

VARCHAR(*):最多255个字节的可变长度字符串,它的长度必须在创建时指定

TEXT:最大长度为64K字符的变长文本

TINYTEXT:最大长度为255字符的变长文本

MEDUIMTEXT:最大长度为16K字符的变长文本

LONGTEXT:最大长度为4GB字符的变长文本



整数(考虑数据取值后选择尽可能小的类型)

tinyint:1字节。有符号值:-128 到127;无符号值:0到255

smallint:2字节。有符号值:-32768 到32767;无符号值:0到65535

mediumint:3字节。

int:4字节

bigint:8字节



小数(需要指定长度和小数点,也就是显示宽度和小数位数):

decimal:精确存储的小数,在内部用字符串存储,适合金额等要求精确的类型。别名:NUMERIC

float:4字节,单精度。会近似存储(*),效率比decimal高。

double:8字节,双精度。会近似存储(*),效率比decimal高。



日期时间:

DATE:4字节。范围:1000-01-01——9999-12-31

TIME:3字节。范围:-838:59:59——838:59:59

DATETIME:8字节。范围:1000-01-01 00:00:00——9999-12-31 23:59:59



二进制大数据:

TITYBLOB:最大长度为255字节

BLOB:最大长度为64KB

MEDIUMBLOB:最大长度为16MB

LONGBLOB:最大长度为4GB
View Code

 SQL简介

1、SQL语句中字符串一般用单引号。

2、SQL语句是大小写不敏感的。

3、NavCat中找到执行SQL语句的地方“查询”→“新建查询”,编写SQL后点击【运行】执行SQL语句。

补充:如果只想执行NavCat中编写的一部分代码,而不是执行全部代码,只要选中要执行的代码,点击鼠标右键,选择“运行已经选择的”即可。

4、最简单的SQL:查看一个表的全部数据:select * from T_Persons

5、简单的插入数据的SQL语句:INSERT INTO T_Persons(Id,Name,Age,Gender) VALUES(5,'Jim',20,1)

Insert语句可以省略表名后的列名,但是强烈不推荐

6、如果插入的行中有些字段的值不确定,那么Insert的时候不指定那些列即可。不“允许为空”的列在插入时不能省略。Navicat有一个bug:某些情况下没有给字段设定值,最后的结果竟然不是null,咱们不用管这个bug。

7、自动递增/自增(Auto Increment):字段自增可以避免并发等问题,不要程序员代码控制自增。用自增字段在Insert的时候不用指定值。修改表结构的方法【设计表】。
View Code

 UPDATE

1、更新一个列:UPDATE T_Persons Set Age=30

2、更新多个列: UPDATE T_Persons Set Age=30,Name='tom'

3、表达式:UPDATE T_Persons Set Age=Age+1

4更新一部分数据: UPDATE T_Persons Set Age=30 where Name='tom',用where语句表示只更新Name是'tom'的行,注意SQL中等于判断用单个=,而不是==5、Where中还可以使用复杂的逻辑判断UPDATE T_Persons Set Age=30 where Name='tom' or Age<25,or相当于Java中的||

where (Age>20 and Age<30) or(Age=80)

6、Where中可以使用的其他逻辑运算符:orandnot<>>=<=!=(或<>)等
View Code

 Delete

删除表中全部数据:DELETE FROM T_Persons。

Delete 也可以带where子句来删除一部分数据:DELETE FROM T_Persons WHERE Age > 20

Delete只是删除数据,表还在。(*)Drop table T_Persons
View Code

数据初始化和select语法1

T_Employees初始数据:

INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('DEV001','Tom',25,8300);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('DEV002','Jerry',28,9300.80);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('SALES001','John',23,5000);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('SALES002','Kerry',28,6200);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('SALES003','Stone',22,1200);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('HR001','Jane',23,2200.88);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('HR002','Tina',25,5200.36);
INSERT INTO T_Employees(Number,Name,Age,Salary) VALUES('IT001','Smith',28,3900);
INSERT INTO T_Employees(Number,Age,Salary) VALUES('IT002',27,2800);


1、简单的数据检索 :SELECT * FROM T_Employees

2、只检索需要的列 :SELECT Number FROM T_Employees 、SELECT Name,Age FROM T_Employees

3、列别名:SELECT Number AS 编号,Name AS 姓名,Age AS Age111 FROM T_Employees  写不写AS都行

4、计算列:SELECT Number 编号,Name 姓名,Age Age111,Age+10 十年后的年龄,1+1,now() FROM T_Employees

5、使用where检索符合条件的数据:SELECT Name FROM T_Employees WHERE Salary<5000。故事:新员工的数据检索噩梦

6、还可以检索不与任何表关联的数据:select 1+1;select now();
View Code

 聚合函数

1、SQL聚合函数:MAX(最大值)、MIN(最小值)、AVG (平均值)、SUM (和)、COUNT(数量)

2、大于25岁的员工的最高工资 :SELECT MAX(Salary) FROM T_Employees WHERE Age>25 

3、最低工资和最高工资:SELECT MIN(Salary),MAX(Salary) FROM  T_Employees

4、大于25岁的员工人数:SELECT COUNT(*) FROM  T_Employees  WHERE Age>25 

5、全体员工的工资总和平均工资:SELECT SUM(Salary),AVG (Salary) FROM  T_Employees
View Code

 OrderBy

1ORDER BY子句位于SELECT语句的末尾,它允许指定按照一个列或者多个列进行排序,还可以指定排序方式是升序(从小到大排列,ASC)还是降序(从大到小排列,DESC) 

2、按照年龄升序排序所有员工信息的列表:SELECT * FROM  T_Employees ORDER BY Age ASC 

3、按照年龄从大到小排序,如果年龄相同则按照工资从大到小排序 :SELECT * FROM  T_Employees ORDER BY Age DESC,Salary DESC

4ORDER BY子句要放到WHERE子句之后 :SELECT * FROM T_Employees WHERE Age>23 ORDER BY Age DESC,Salary DESC 
View Code

 Like

通配符过滤使用LIKE 。

1、单字符匹配的通配符为半角下划线“_”,它匹配单个出现的字符。以任意字符开头,剩余部分为“erry” :SELECT * FROM T_Employees WHERE Name LIKE '_erry' 

2、多字符匹配的通配符为半角百分号“%”,它匹配任意次数(零或多个)出现的任意字符。 “k%”匹配以“k”开头、任意长度的字符串。检索姓名中包含字母“n”的员工信息 :SELECT * FROM T_Employees WHERE Name LIKE '%n%' 

3、Like性能较差,很容易造成全表扫描,谨慎使用。后面会讲数据库优化(索引等),项目中做搜索用全文检索。
View Code

 null

1、数据库中,一个列如果没有指定值,那么值就为null,数据库中的null表示“不知道”,而不是表示没有。因此select null+1结果是null,因为“不知道”加1的结果还是“不知道”。

2SELECT * FROM T_Employees WHERE NAME=nullSELECT * FROM T_Employees WHERE NAME!=null ;

都没有任何返回结果,因为数据库也“不知道”。

3、提问:如果T_Employees表中Name列的值是null的话,那么下面查询结果是什么?Select Name+"a" FROM T_Employees 。



答案:还是null,因为null和任何的东西做任何的运算都是null,null+"a"还是null。

4、SQL中使用is nullis not null来进行空值判断: 

SELECT * FROM T_Employees WHERE NAME is nullSELECT * FROM T_Employees WHERE NAME is not null
View Code

 LIMIT

1、LIMIT关键字用来限制返回的结果集, LIMIT放在SELECT语句的最后位置,语法为“LIMIT  首行行号,要返回的结果集的最大数目” 。比如下面的SQL语句将返回Name不为空的、按照工资降序排列的从第二行开始(行号从0开始)的最多五条记录:

SELECT * FROM T_Employees

where Name is not null 

ORDER BY Salary DESC  

LIMIT 2,5



2、limit一定要放到所有的语句的最后。
View Code

 Groupby分组查询

1、数据分组用来将数据分为多个逻辑组,从而可以对每个组进行聚合运算。SQL语句中使用GROUP BY子句进行分组,使用方式为“GROUP BY  分组字段”。分组语句一般和聚合函数一起使用,GROUP BY子句负责将数据分成逻辑组,而聚合函数则对每一个组进行统计计算。

2、查看公司员工有哪些年龄段的:

SELECT Age FROM T_Employees GROUP BY Age 

将Age相同的数据行放到一组,分组后的数据可以看作一个临时的结果集,而SELECT  Age语句则取出每组的Age字段的值,这样我们就得到上表的员工年龄段表了。

3、如果SELECT语句有WHERE子句,则GROUP BY子句必须放到WHERE语句的之后。

4GROUP  BY子句将检索结果划分为多个组,每个组是所有记录的一个子集。上面的SQL例子在执行的时候数据库系统将数据分成了下面的分组:

5、

分组后就可以对组内的数据采用聚合函数进行统计了:

1)计算每个分组中的员工平均工资

SELECT Age,AVG(Salary) FROM T_Employees

GROUP BY Age

2)查看每个年龄段的员工的人数:

SELECT Age,COUNT(*)  FROM T_Employees

GROUP BY Age
View Code

 left join

初始数据:

INSERT INTO T_Customers(Id,Name,Age)
VALUES(1,'TOM',21);
INSERT INTO T_Customers(Id,Name,Age)
VALUES(2,'MIKE',24);
INSERT INTO T_Customers(Id,Name,Age)
VALUES(3,'JACK',30);
INSERT INTO T_Customers(Id,Name,Age)
VALUES(4,'TOM',25);
INSERT INTO T_Customers(Id,Name,Age)
VALUES(5,'LINDA',30);

INSERT INTO T_OrderTypes(Id,Name)
VALUES(1,'现货订单');
INSERT INTO T_OrderTypes(Id,Name)
VALUES(2,'预订订单');
INSERT INTO T_OrderTypes(Id,Name)
VALUES(3,'预购订单');
INSERT INTO T_OrderTypes(Id,Name)
VALUES(4,'内部');

INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(1,'K001',100,1,1);
INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(2,'K002',200,1,1);
INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(3,'T003',300,1,2);
INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(4,'N002',100,2,2);
INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(5,'N003',500,3,4);
INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(6,'T001',300,4,3);
INSERT INTO T_Orders(Id,Number,Price,CustomerId, TypeId)
VALUES(7,'T002',100,1,1);


1、查询每张订单的订单号、价格、对应的客户姓名以及客户年龄

SELECT o.Number,o.Price,c.Name,c.Age

FROM T_Orders o

LEFT JOIN T_Customers c

ON o.CustomerId=c.Id

2、添加where语句(显示价格>=150元的订单)

SELECT o.Number,o.Price,o.CustomerId,

c.Name,c.Age  FROM T_Orders o

LEFT JOIN T_Customers c  ON o.CustomerId=c.Id

WHERE o.Price>=150

3、可以join多张表:

SELECT o.Number 订单号,o.Price 价格, c.Name 客户姓名,c.Age 客户年龄,t.Name 订单类型  FROM T_Orders o

LEFT JOIN T_Customers c  ON o.CustomerId=c.Id

LEFT JOIN T_OrderTypes t ON o.TypeId=t.Id
View Code

 外键约束

1、如果删除/更新T_Customers一行记录,那么就可能会导致T_Orders中存在CustomerId为非法值的数据,使得程序逻辑错误。一般不会更新主键Id的值,所以谈外键约束的时候只谈“删除T_Customers时”。

2、外键约束:当删除T_Customers中一条数据的时候,如何处理T_Orders等存在指向T_Customers外键的行。外键约束建立在外键字段***Id的表上(t_orders)。

3、建外键约束的方法:新建或者修改表的时候“外键”→“添加外键”。名:自动命名即可;栏位名:CustomerId;参考表:t_customers;外栏位名:Id;删除时、更新时:一般默认RESTRICT(CASCADE:删除T_Customers一行时把它的订单也删除了;SET NULL:删除T_Customers一行时把它的订单CustomerId设置为NULL;NO ACTION/RESTRICT:拒绝删除)。

4、有的公司不习惯建外键,而是通过程序进行数据合法性控制,对于初学者先不建议这样,都把外键加上。
View Code

 第七章ADO.NET

ADO.NET是.NET中提供的标准访问数据库的接口,访问不同的DBMS的底层方法是不一样的,ADO.NET把访问数据库的方法进行了统一,访问MYSQL,Oracle,SQLServer等不同的数据库的用法几乎一模一样.

ADO.NET是规范,被不同的数据库厂商提供ADO.NET的实现,称之为ADO.NET驱动,每个厂商提供的驱动可以用来操作自己的数据库.

MYSQL的.Net驱动mysql-connector-net-***.msi下载地址:

1)https://dev.mysql.com/get/Downloads/Connector-Net/mysql-connector-net-6.9.9.msi 



新建项目,添加引用→“扩展”,添加Mysql.Data;如果是直接解压版,然后直接添加对MySql.Data.dll文件的引用;

using (MySqlConnection conn =
    new MySqlConnection("Server=localhost;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand())
{
    conn.Open();//一定要在执行前Open数据库连接
    cmd.CommandText = "Insert into T_Users(UserName,Password) values('中国人','123')";
    int rowCount = cmd.ExecuteNonQuery();
    Console.WriteLine("受影响的行数"+rowCount);
}
解释一下代码:

MySqlConnection、MySqlCommand实现了IDisposable接口,因此使用using进行资源释放;

"Server=localhost;Database=study1;uid=root;pwd=root;Charset=utf8"叫连接字符串,Server是Mysql服务器的地址,Database是连接的数据库,uid、pwd是用户名和密码,采用utf8编码。

conn.Open():在执行MySqlCommand之前一定要先打开数据库连接,否则会报错。

ExecuteNonQuery是执行Update、Insert、Delete等非查询语句,返回值为受影响的行数。



如果运行的时候报错AccessViolationException,一般是由于你电脑装了一些乱七八糟的软件把winsock组件搞坏了的原因,你以管理员模式运行命令行,然后执行 netsh winsock reset 然后重启电脑试试。
View Code

 执行insert语句

using (MySqlConnection conn =
    new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
using(MySqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "Insert into T_Users(UserName,Password) values('aaa','123')";
    int rc = cmd.ExecuteNonQuery();
    Console.WriteLine("插入成功,影响行数"+rc);
}
ExecuteNonQuery是执行Update、Insert、Delete等非查询语句,返回值为受影响的行数。
View Code

 ExecuteScalar

ExecuteScalar:执行查询,并返回查询所返回的结果集中第一行的第一列,忽略其他行列。一般用来简单的获得只有一行一列的查询结果的值。

案例1:

cmd.CommandText = "Select count(*) from T_Users";

long count = (long)cmd.ExecuteScalar();

案例2:

cmd.CommandText = "Select Password from T_Users where UserName='admin'";

string pwd = (string)cmd.ExecuteScalar();

if (string.IsNullOrEmpty(pwd))

{   

   Console.WriteLine("找不到admin");

}

else

{    

   Console.WriteLine("admin的密码:" + pwd);

}
View Code

 ExecuteReader

cmd.CommandText = "select * from T_Users";
using (MySqlDataReader reader = cmd.ExecuteReader())
{
    while (reader.Read())
    {
        long id = reader.GetInt64("Id");
        string userName = reader.GetString("UserName");
        string password = reader.GetString("Password");

        Console.WriteLine("id=" + id + ";UserName=" + userName + ";Password=" + password);
    }
}
注意:Reader的遍历、读取时需要Connection保持连接,如果关闭了Connection,使用Reader会出错。

也可以根据列序号获取列的值,效率略高,不过程序不容易读;通过reader.GetOrdinal("Age")获得列名对应的列序号。
View Code

 SQL注入漏洞攻击,,开发一定得注意

 参数化查询

/*
using(MySqlConnection conn = new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "Insert into @p(UserName,Password) values(@un,@pwd)";
    cmd.Parameters.Add(new MySqlParameter { ParameterName = "@p", Value = "t_users" });
    cmd.Parameters.Add(new MySqlParameter { ParameterName="@un",Value="rueng"});
    cmd.Parameters.Add(new MySqlParameter { ParameterName="@pwd",Value="123456"});
    cmd.ExecuteNonQuery();
}*/

/*
using(MySqlConnection conn = new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "Insert into T_Users(UserName,Password,Age) values(@un,@pwd,@Age)";
    cmd.Parameters.Add(new MySqlParameter("@un","test1"));
    cmd.Parameters.Add(new MySqlParameter("@pwd", "321"));

    //int i = 0;
    //cmd.Parameters.Add(new MySqlParameter("@Age", i));
    // cmd.Parameters.Add(new MySqlParameter("@Age", 0));
    cmd.Parameters.Add(new MySqlParameter("@Age",(object)0));
    cmd.ExecuteNonQuery();
}*/
View Code

 读取数据库中的null值

使用IsDBNull获取指定序号的列的值是否为null

int? age=null;

if (!reader.IsDBNull(reader.GetOrdinal("Age")))

{

    age = reader.GetInt32("Age");

}

using (MySqlConnection conn =
new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "select * from T_Users;";
    using (MySqlDataReader reader = cmd.ExecuteReader())
    {
        while (reader.Read())
        {
            string username = reader.GetString("UserName");
        // string password = reader.GetString("Password");
            string password;
            if (reader.IsDBNull(reader.GetOrdinal("Password")))
            {
                password = null;
            }
            else
            {
                //GetString/GetInt32 无法读取数据库中的null值
                //需要提前用IsDBNull判断
                password = reader.GetString("Password");
            }
            int? age;
            if (reader.IsDBNull(reader.GetOrdinal("Age")))
            {
                age = null;
            }
            else
            {
                age = reader.GetInt32("Age");
            }
        // int age = reader.GetInt32("Age");
            Console.WriteLine("用户名:"+username+";密码:"+
                (password==null?"不知道密码":password)+";年龄:"+
                (age==null?"不知道年龄":age.ToString()));
        }
    }
}
View Code

 离线结果集入门

DataReader是服务器结果集游标的体现,所有查询出来的数据都在MySQL服务器上。好处是:当查询结果数据量大的时候避免占用本地内存。不过大部分项目中都会避免大查询结果,因此缺点就明显了:读取的时候必须保持Connection,不仅用起来麻烦,而且会较长时间占用MySQL服务器的连接资源。

DataSet是一个离线结果集容器,它把结果数据放到本地内存中。因为查询结果可能会包含多个表,因此DataSet包含若干DataTable(ds.Tables)、DataTable包含若干DataRow(dt. Rows)。

用法1:

DataSet ds = new DataSet();
MySqlDataAdapter adapter = new MySqlDataAdapter(cmd);
adapter.Fill(ds);
DataTable table = ds.Tables[0];


DataSet 可以盛放多个查询结果集到DataTable ;DataAdapter还可以对结果进行傻瓜化更新、删除、修改。我们一般查询结果集就一个DataTable, DataAdapter的傻瓜化更新不适合于正式的项目,因此有更简单的用法

DataTable dt = new DataTable();

dt.Load(reader);

把DataTable声明到using外,using外再使用查询结果。

遍历DataTable:

for (int i = 0; i < dt.Rows.Count; i++)
{
    DataRow row = dt.Rows[i];
    string name = row.IsNull("Name")?null:(string)row["Name"];//NULL处理
    Console.WriteLine("name"+name);
}


案例代码:

/*
    using (MySqlConnection conn =
    new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
    using (MySqlCommand cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = "select * from t_users";
        using (MySqlDataReader reader = cmd.ExecuteReader())
        {
            DataTable dt = new DataTable();
            dt.Load(reader);
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                DataRow row = dt.Rows[i];
                int id = (int)row["Id"];//下标方式获得是object
                string username = (string)row["UserName"];

                //做很复杂的io操作,把username存到文件中
                //这样就会长期占据Connection

            // object obj = row["Password"];
                //if(row["Password"]==DBNull.Value)//返回的不是null,而是DBNull
                         
                //string password = (string)row["Password"];
                //int age = (int)row["Age"];
                string password = row.IsNull("Password") ? null : (string)row["Password"];
                int? age = row.IsNull("Age") ? (int?)null : (int)row["Age"];

                Console.WriteLine("id=" + id + ";Username=" + username
                    +";username="+username+";age="+age);
            }
        }
    }*/

/*
DataTable table  = new DataTable();
using (MySqlConnection conn =
    new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand())
{
    conn.Open();
    cmd.CommandText = "select * from t_users";
    using (MySqlDataReader reader = cmd.ExecuteReader())
    {
        table.Load(reader);//加载到table中
    }
}

for (int i = 0; i < table.Rows.Count; i++)
{
    DataRow row = table.Rows[i];
    int id = (int)row["id"];
    string username = (string)row["UserName"];
    Console.WriteLine(id+":"+username);
}
*/
View Code

 MySqlHelper

连接字符串一般配置到App.config(网站是Web.config)中的<connectionStrings>段中

使用ConfigurationManager类(添加对System.Configuration的引用)读取

string connstr =

           ConfigurationManager.ConnectionStrings["connstr"].ConnectionString

注意:

1、注意不要修改App.config的名字为App1.config之类的,必须叫App.config(网站是Web.config)

2、配置文件中只能有一个connectionstrings段,不能配置多个

3、一定要保证代码中的名字和配置文件中的名字一致(初学者容易犯错的,一般提示“初始化代码错误”这个错误就是因为两者名字不一致造成的)



using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ADONETTest2
{
    class MySqlHelper
    {
        private static readonly string connstr =
            ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;

        public static MySqlConnection CreateConnection()
        {
            //using (MySqlConnection conn = new MySqlConnection(connstr))
            MySqlConnection conn = new MySqlConnection(connstr);
            conn.Open();
            return conn;
        }

        public static int ExecuteNonQuery(MySqlConnection conn, string sql,
            params MySqlParameter[] parameters)
        {
            using (MySqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                /*
                foreach (MySqlParameter p in parameters)
                {
                    cmd.Parameters.Add(p);
                }*/
                cmd.Parameters.AddRange(parameters);
                return cmd.ExecuteNonQuery();
            }
        }

        public static int ExecuteNonQuery(string sql,
            params MySqlParameter[] parameters)
        {
            using (MySqlConnection conn = CreateConnection())
            {
                return ExecuteNonQuery(conn, sql, parameters);
            }
        }

        public static object ExecuteScalar(MySqlConnection conn, string sql,
            params MySqlParameter[] parameters)
        {
            using (MySqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);
                return cmd.ExecuteScalar();
            }
        }

        public static object ExecuteScalar(string sql,
           params MySqlParameter[] parameters)
        {
            using (MySqlConnection conn = CreateConnection())
            {
                return ExecuteScalar(conn, sql, parameters);
            }
        }

        public static DataTable ExecuteQuery(MySqlConnection conn, string sql,
           params MySqlParameter[] parameters)
        {
            DataTable table = new DataTable();
            using (MySqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);
                using (MySqlDataReader reader = cmd.ExecuteReader())
                {
                    table.Load(reader);                    
                }
            }
            return table;
        }

        public static DataTable ExecuteQuery(string sql,
           params MySqlParameter[] parameters)
        {
            using (MySqlConnection conn = CreateConnection())
            {
                return ExecuteQuery(conn, sql, parameters);
            }
        }
    }
}
View Code

 获取自动增长字段的值

1、使用LAST_INSERT_ID()获取“最后一次插入的自动递增列的值”

2、需要注意Insert语句和select LAST_INSERT_ID()一定要在要在同一个连接中。

using (MySqlConnection conn = MySqlHelper.CreateConnection())
{
    MySqlHelper.ExecuteNonQuery(conn,
        "insert into t_users(UserName,Password) values('我几时我','123')");
    object o = MySqlHelper.ExecuteScalar(conn, "select Last_Insert_Id()");
    //Last_Insert_Id()是获取当前连接中,最近一次自动递增字段的值
    ulong id = (ulong)o;//无符号的long
    Console.WriteLine(id);
}
可以Insert、LAST_INSERT_ID()在同一个连接中单独执行,也可以把LAST_INSERT_ID()放到insert语句后面用;分割(使用ExecuteScalar执行即可)

ulong id = (ulong)MySqlHelper.ExecuteScalar("insert into t_users(UserName,Password) values('我几时我','123');select last_insert_id()");
Console.WriteLine(id);
View Code

 事物的原子性

事务的几个关键环节:

1)要在一个连接中;

2)启动事务:MySqlTransaction tx = conn.BeginTransaction(); 

3)操作结束后执行tx.Commit() 提交事务;

4)如果执行出错,则tx.Rollback()回滚(当前事务的操作全部取消)。

 MySqlTransaction tx = conn.BeginTransaction();
    try
    {
        MySqlHelper.ExecuteNonQuery(conn, "Update t_accounts Set Amount=Amount-1000 where Number='0001'");
        string s = null;        s.ToLower();
        MySqlHelper.ExecuteNonQuery(conn, "Update t_accounts Set Amount=Amount+1000 where Number='0002'");
        tx.Commit();
    }
    catch (Exception ex)
    {
        tx.Rollback();
     }
View Code

SQLServer2008R2

1、ADO.Net如何连接SQLServer:SQLServer驱动.Net内置(亲生的);把MySqlConnection换成SqlConnection,MySql***换成Sql***2、连接字符串: 

 server=ip;user id=sa;password=密码;database=db1

3、SQLHelper:把MySql查找替换成Sql就可以了。

4、获得自动增长列的值:Insert into t1(...) output inserted.Id values(.........)

5、(*)如果基于接口编程,只要改动CreateConnection就可以(查询参数以Dictionary<string,object>传递;如果使用Provider,连代码都不用改,改配置文件即可。

6、需要特别注意:SqlServer的事务和mysql事务使用有一点不一样的地方是“需要把BeginTransaction返回的SqlTransaction对象赋值给SqlCommand的Transaction属性”
View Code

 SQLHelper

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SQLHelper
{

    class SQLHelper
    {
        private static readonly string connStr = ConfigurationManager.ConnectionStrings["heiyo"].ConnectionString;
        public static SqlConnection CreateConnection()
        {
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            return conn;
        }

        public static int ExecuteNonQuery(SqlConnection conn, string sql, params SqlParameter[] parameters)
        {
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);
                return cmd.ExecuteNonQuery();
            }
        }
        public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters)
        {
            using (SqlConnection conn = CreateConnection())
            {
                return ExecuteNonQuery(conn, sql, parameters);
            }
        }
        public static object ExecuteScalar(SqlConnection conn, string sql, params SqlParameter[] parameters)
        {
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);
                return cmd.ExecuteScalar();
            }
        }
        public static object ExecuteScalar(string sql, params SqlParameter[] parameters)
        {
            using (SqlConnection conn = CreateConnection())
            {
                return ExecuteScalar(conn, sql, parameters);
            }
        }
        public static DataTable ExecuteQuery(SqlConnection conn, string sql, params SqlParameter[] parameters)
        {
            DataTable table = new DataTable();
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    table.Load(reader);
                }
            }
            return table;
        }
        public static DataTable ExecuteQuery(string sql, params SqlParameter[] parameters)
        {
            DataTable table = new DataTable();
            using (SqlConnection conn = CreateConnection())
            {
                return ExecuteQuery(conn, sql, parameters);
            }

        }
    }
}
View Code

varchar,不带中文,nvarchar带中文,自增主键用bigint

DBHelper通过接口编程使用ADO.Net感受多态的强大

using MySql.Data.MySqlClient;
using System;
using System.Data;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;

namespace DBHelper
{
    class DBHelper
    {
        private static readonly string connStr = ConfigurationManager.ConnectionStrings["a1"].ConnectionString;
        public static IDbConnection CreateConnection()
        {
            SqlConnection conn = new SqlConnection(connStr);
           // MySqlConnection conn = new MySqlConnection(connStr);
            conn.Open();
            return conn;
        }

        public static int ExecuteNonQuery(IDbConnection conn, string sql,Dictionary<string,object> parameters)
        {
            using (IDbCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                foreach (KeyValuePair<string,object> kvp in parameters)
                {
                    IDbDataParameter parameter = cmd.CreateParameter();
                    parameter.ParameterName = kvp.Key;
                    parameter.Value = kvp.Value;
                    cmd.Parameters.Add(parameter);
                }
                return cmd.ExecuteNonQuery();
            }
        }
        public static int ExecuteNonQuery(string sql, Dictionary<string, object> parameters)
        {
            using (IDbConnection conn = CreateConnection())
            {
                return ExecuteNonQuery(conn, sql, parameters);
            }
        }
        public static object ExecuteScalar(IDbConnection conn, string sql, Dictionary<string, object> parameters)
        {
            using (IDbCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                foreach (KeyValuePair<string, object> kvp in parameters)
                {
                    IDbDataParameter parameter = cmd.CreateParameter();
                    parameter.ParameterName = kvp.Key;
                    parameter.Value = kvp.Value;
                    cmd.Parameters.Add(parameter);
                }
                return cmd.ExecuteScalar();
            }
        }
        public static object ExecuteScalar(string sql, Dictionary<string, object> parameters)
        {
            using (IDbConnection conn = CreateConnection())
            {
                return ExecuteScalar(conn, sql, parameters);
            }
        }
        public static DataTable ExecuteQuery(IDbConnection conn, string sql, Dictionary<string, object> parameters)
        {
            DataTable table = new DataTable();
            using (IDbCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                foreach (KeyValuePair<string, object> kvp in parameters)
                {
                    IDbDataParameter parameter = cmd.CreateParameter();
                    parameter.ParameterName = kvp.Key;
                    parameter.Value = kvp.Value;
                    cmd.Parameters.Add(parameter);
                }
                using (IDataReader reader = cmd.ExecuteReader())
                {
                    table.Load(reader);
                }
            }
            return table;
        }
        public static DataTable ExecuteQuery(string sql, Dictionary<string, object> parameters)
        {
            DataTable table = new DataTable();
            using (IDbConnection conn = CreateConnection())
            {
                return ExecuteQuery(conn, sql, parameters);
            }

        }
    }
}
View Code

 Like和In中查询参数的问题

 Console.WriteLine("请输入要查询的姓名");

            string name = Console.ReadLine();

            //'%@Name%'是一个整体,无法“部分当成查询参数”

           //DataTable dt =  SqlHelper.ExecuteQuery("select * from T_Persons where Name like '%@Name%'",

            //DataTable dt = SqlHelper.ExecuteQuery("select * from T_Persons where Name like '%'+@Name+'%'",

                //new SqlParameter("@Name",name));

            DataTable dt = SqlHelper.ExecuteQuery("select * from T_Persons where Name like @Name",

                new SqlParameter("@Name","%"+name+"%"));

           foreach (DataRow row in dt.Rows)

           {

               Console.WriteLine(row["Name"]);

           }



           string line =  Console.ReadLine();

            

            foreach(char ch in line)

            {

                if(!char.IsDigit(ch)&&ch!=',')

                {

                    Console.WriteLine("输入非法");

                    Console.ReadKey();

                    return;

                }

            }



            //DataTable dt = SqlHelper.ExecuteQuery("select * from T_Persons where Age in(@Age)",

              //  new SqlParameter("@Age",line));

          // DataTable dt = SqlHelper.ExecuteQuery("select * from T_Persons where Age in(" + line+")");

            DataTable dt = SqlHelper.ExecuteQuery("exec('select * from T_Persons where Age in('+@Age+')')",

                new SqlParameter("@Age",line));

           foreach (DataRow row in dt.Rows)

           {

               Console.WriteLine(row["Name"]+"="+row["Age"]);

           }
View Code

 SQLServer中事物

using (SqlConnection conn = new SqlConnection(connstr))

            {

                conn.Open();

                using (SqlTransaction tx = conn.BeginTransaction())

                {



                    try

                    {

                        //using是保证资源一定会被回收的,离开using范围后自动调用Dispose方法(无论是否有异常)

                        //using==try...finally...

                        //using不会进行异常的catch

                        using (SqlCommand cmd1 = conn.CreateCommand())

                        using (SqlCommand cmd2 = conn.CreateCommand())

                        {

                            cmd1.Transaction = tx;//在SQLServer中必须把BeginTransaction返回的对象赋值给SqlCommand的

                            //Transaction属性

                            cmd1.CommandText = "insert into T_Persons(Name,Age) values('a',1)";

                            cmd1.ExecuteNonQuery();



                            cmd2.Transaction = tx;

                            cmd2.CommandText = "insert into T_Persons(Name,Age) values('b',2)";

                            cmd2.ExecuteNonQuery();

                        }

                        tx.Commit();

                    }

                    catch (Exception ex)

                    {

                        tx.Rollback();

                    }

                }

            }
View Code

 SqlBulkCopy 批量插入

DataTable dt = new DataTable();

             dt.Columns.Add("Name");

             dt.Columns.Add("Age");

             for (int i = 0; i < 80000; i++)

             {

                DataRow row =  dt.NewRow();

                row["Name"] = "aa" + i;

                row["Age"] = i * i;

                dt.Rows.Add(row);

             }



             using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connstr))

             {

                 bulkCopy.DestinationTableName = "T_Persons";

                 bulkCopy.ColumnMappings.Add("Name", "Name");

                 bulkCopy.ColumnMappings.Add("Age", "Age");

                 bulkCopy.WriteToServer(dt);

             }
View Code

 MySQL的批量数据插入

Stopwatch sw = new Stopwatch();

            sw.Start();

            using (MySqlConnection conn = new MySqlConnection("server=127.0.0.1;database=study1;uid=root;pwd=root"))

            {

                conn.Open();

                using (MySqlCommand cmd = conn.CreateCommand())

                {

                    //一条SQL数据的长度有限

                    //拼接出1000条数据就批量插入一次

                    List<string> listSql = new List<string>();

                    for (int i = 0; i < 100000; i++)

                    {

                        listSql.Add("('test"+i+"','"+i+"')");

                        if (listSql.Count > 1000)

                        {

                            string sql = "insert into t_users(UserName,Password) values" + string.Join(",", listSql);

                            cmd.CommandText = sql;

                            cmd.ExecuteNonQuery();

                            listSql.Clear();

                        }

                    }

                    if (listSql.Count > 0)

                    {

                        //处理残留的数据

                        string sql1 = "insert into t_users(UserName,Password) values" + string.Join(",", listSql);

                        cmd.CommandText = sql1;

                        cmd.ExecuteNonQuery();

                    }                   

                }

            }

            sw.Stop();

            Console.WriteLine(sw.ElapsedMilliseconds);
View Code
原文地址:https://www.cnblogs.com/wangyinlon/p/6921808.html