第七节:语法总结(1)(自动属性、out参数、对象初始化器、var和dynamic等)
一. 语法糖简介
语法糖也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
需要声明的是“语法糖”这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换;而且可以提高开发编码的效率,在性能上也不会带来损失。
在编译器发展早期,编译器科学家门一直在想方设法的优化编译器生成的代码,这个时候,编译器做的主要是对机器优化,因为那个时候机器的时间非常宝贵,机器运算速度也不快,今天我们有了足够好的机器了(但并不是说我们可以不关注性能的编写程序),而且作为编写软件的人来说,比机器的时间宝贵得多,所以今天的编译器也在向人优化了,从编程语言的发展之路来讲,今天的编程语言比昨天的语言更高级,也更人性化了,我们只要编写更少的代码,更符合人的思维的代码,而只要关注我们值的关注的地方。体力活儿就交给编译器吧。
二. 常用语法糖
1. 自动属性
(1). 传统的方式在类中声明一个属性,需要先声明一个私有变量的字段,然后在配合公有属性,如下面的:userId属性。
(2). 利用自动属性:不需要字段,声明一个空属性,直接get,set(快捷键:prop),编译时编译器为我们生成存取数据的字段. 如下面的:userName属性。
1 public class userInfor 2 { 3 //私有字段 4 private string _userId; 5 //公有属性 6 public string userId 7 { 8 get 9 { 10 return _userId; 11 } 12 set 13 { 14 _userId = value; 15 } 16 } 17 18 public string useName { get; set; } 19 20 21 /// <summary> 22 /// 为了后面的反射调用 23 /// </summary> 24 public void Test() 25 { 26 Console.WriteLine("我是一个方法"); 27 } 28 29 }
2. var和dynamic
(1). var类型:声明变量的时候可以不指定类型,由编译器编译的时候来指定类型。
①:必须在定义的时候初始化
②:必须是局部变量
③:一旦初始化完成,不能再给变量赋与初始值不同类型的值了,但是可以赋相同类型的不同值.
④:var在效率是和使用强类型方式定义变量是一样的
(2). dynamic类型:编译期间不做任何检查,运行期间才确定类型。
①:定义的时候可以不必初始化
②:可以是全局变量,也可以是局部变量
dynamic在反射中的应用:通过反射拿到类后,赋值给dynamic类型,该类型的对象可以直接点来调用方法
缺点:dynamic在运行的时候才进行检测,导致编译的时候即使有错误也不会被发现; 不能用dynamic类型给确定类型的变量进行赋值
1 public class CompareTwo 2 { 3 //2. 可使用的范围 4 // var b1 = 1; //报错,var必须定义在方法呃逆 5 // dynamic b2 = 2; //正常 6 public static void Show() 7 { 8 { 9 //1. 初始化比较 10 //var a1; //报错,定义的时候必须初始化 11 //dynamic a2; //正常 12 } 13 { 14 //3. 赋值问题 15 var c1 = 2; 16 //c1 = "2"; //报错,初始化完成不能赋值不同类型的变量 17 c1 = 3; //正常,初始化完成可以赋值相同类型的变量的不同值 18 19 dynamic d1 = 2; 20 d1 = "2"; //正常,运行时检查进行类型指定,所以在编译的时候不会报错 21 d1 = 3; //正常 22 23 24 var userInfor = new userInfor(); 25 userInfor.useName = "1"; 26 userInfor.userId = "2"; 27 // userInfor.fk123(); //报错,编译不通过 28 29 dynamic userInfor2 = new userInfor(); 30 userInfor2.userId = "1"; 31 userInfor2.useName = "ypf"; 32 //调用不存在的方法 (因为编译的时候根本不检查,所以不会报错,运行的时候报错) 33 //userInfor2.fk123(); //编译期间不报错,运行的时候报错 34 35 } 36 { 37 //4. dynamic在反射中的应用 38 //4.1 常规反射调用方法 39 Type type1 = typeof(userInfor); 40 object oStudent = Activator.CreateInstance(type1); 41 MethodInfo method = type1.GetMethod("Test"); 42 method.Invoke(oStudent,null); 43 44 //4.2 利用dynamic简化调用 45 //定义和编译的时候可以是任何类型,运行的时候进行转换 46 dynamic oStudent2 = Activator.CreateInstance(type1); 47 oStudent2.Test(); 48 49 } 50 } 51 }
3. 可选参数
给方法的参数可以指定默认值,如果在调用该方法的时候,不传入该参数,则走默认值,传入的话,则覆盖默认参数.
(1). 有默认值的参数必须定义在没有默认值的参数之后
(2). 默认参数必须是常量,不能是变量
(3). ref和out参数不能指定默认值
1 public class OptionalParas 2 { 3 public static void Test(string useName,string userPwd,int userAge=16,string userSex="男") 4 { 5 Console.WriteLine("userName:{0},userPwd:{1},userAge:{2},userSex:{3}", useName, userPwd, userAge, userSex); 6 } 7 }
1 //3.可选参数 2 Console.WriteLine("----------------------3.可选参数-------------------------"); 3 OptionalParas.Test("ypf1", "123456"); 4 OptionalParas.Test("ypf2", "654321", 56, "女");
4. 对象(集合)初始化器
1 public class ObjectInitilize 2 { 3 public static void Test() 4 { 5 6 //一.对象初始化 7 //1. 传统初始化对象的方式 8 userInfor uInfor1 = new userInfor(); 9 uInfor1.userId = "1"; 10 uInfor1.useName = "ypf1"; 11 12 //2.对象初始化器 13 userInfor uInfor2 = new userInfor() 14 { 15 userId="2", 16 useName="ypf2" 17 }; 18 userInfor uInfor3 = new userInfor() 19 { 20 userId = "3", 21 useName = "ypf3" 22 }; 23 24 //二. 集合初始化 25 //1. 传统方式 26 List<userInfor> uList = new List<userInfor>(); 27 uList.Add(uInfor1); 28 uList.Add(uInfor2); 29 30 //2. 集合初始化器 31 List<userInfor> uList2 = new List<userInfor>(){ 32 uInfor1, 33 uInfor2, 34 new userInfor(){ 35 userId="4", 36 useName="ypf4" 37 } 38 }; 39 40 } 41 }
5. ref和out
二者共同的使用场景,将ref或out参数传入方法中,执行完方法后,可以直接使用ref或out参数值。
(1). ref必须在使用前赋值,即传入方法前进行定义并赋值
(2). out必须在方法中赋值然后使用,在调用方法前声明两个未实例化的变量,用来传入和接收使用
举例:有两个int类型的值num1和num2,分别使用ref和out传入对应的方法中,进行值交换。
1 public class CompareRO 2 { 3 /// <summary> 4 /// ref的使用 5 /// </summary> 6 public static void TestRef() 7 { 8 int num1 = 5; 9 int num2 = 10; 10 Func1(ref num1, ref num2); 11 Console.WriteLine("num1的值为:{0},num2的值为:{1}", num1, num2); 12 } 13 14 public static void TestOut() 15 { 16 int num1; 17 int num2; 18 Func2(out num1, out num2); 19 Console.WriteLine("num1的值为:{0},num2的值为:{1}", num1, num2); 20 } 21 22 #region ref版参数值交换 23 public static void Func1(ref int n1, ref int n2) 24 { 25 int a = n1; 26 n1 = n2; 27 n2 = a; 28 } 29 #endregion 30 31 #region out版参数值交换 32 public static void Func2(out int n1,out int n2) 33 { 34 n1 = 5; 35 n2 = 10; 36 int a = n1; 37 n1 = n2; 38 n2 = a; 39 } 40 #endregion 41 42 }
6. 匿名类/匿名方法
7. 扩展方法
图片放大镜
css:jquery.jqzoom.css
插件:jquery.jqzoom-core.js
<a class="big" href="image/big.jpg"> <img src="image/small.jpg"/> </a> //编写脚本 $(".big").jqzoom();
配置参数:
zooType,默认值:‘standard’,另一个值是‘reverse’,是否将原图用半透明图层遮盖
zoomWidth,默认值:2000,放大窗口的宽度
zoomHeight,默认值:200,放大窗口的高度
xOffset,默认值:10,放大窗口相对于原图的X轴偏移值,可以为负
yOffset,默认值:0,放大窗口相对于原图的y轴偏移值,可以为负
position,默认值:‘right’,放大窗口的位置,值还可以是‘right’、‘left’,‘top’,‘bottom’
lens,默认值:true,若为false,则不在原图上显示镜头
imageOpacity,默认值:0.2,当zoomType的值为‘reverse’时,这个参数用于指定遮罩层的透明度
title,默认值:true,在放大窗口中显示标题,值可以为a标记的title值,若无,则为原图的title值
showEffect,默认值:‘show’,显示放大窗口时的效果,值可以为:‘show’,‘fadein’
hideEffect,默认值:‘hide’,隐藏放大窗口时的效果,值可以为:‘hide’,‘fadeout’
fadeinSpeed,默认值:‘fast’,放大窗口的渐显速度(‘fast’,‘slow’,‘medium’)
fadeoutSpeed,默认值:‘slow’,放大窗口的渐隐速度(‘fast’,‘slow’,‘medium’)
showPreload,默认值:true,是否显示加载提示Loading zoom(‘true’,‘false’)
preloadText,默认值:‘Loading zoom’,自定义加载提示文本
preloadPosition,默认值:‘center’,加载提示的位置,值也可以为‘bycss’,以通过css指定位置
JavaScript-基础
Date
date.toString() 获取世界时间,会提示当前时区
var data = new Date(); alert(date.toString());
date.toLocaleString() 获取当前时区的当前时间
超链接不跳转
一、让js函数返回false,在click也返回false
function hi(){ alert("你好") ; return false; } <a href="http://www.baidu.com" οnclick="return hi();">打招呼</a>
二、将href指定成一段脚本
<a href="javascript:hi();">打招呼</a>
数据类型
boolean 布尔
number 数字
string 字符串
Undefined 未定义
Null 空对象
Object 对象类型
Undefined类型、Null类型都是只有一个值的数据类型,值分别为undefined与null
null是一个object的值
查看变量的类型typeof 变量名或typeof(变量名),返回变量类型的字符串
//返回的是function alert(typeof(date)) //返回的是string alert(typeof(date()))//调用方法返回字符串
类型转换:类型名(变量名)或parse***(变量名)
//当变量被声明后,没有初始化,值为undefined
判等
双等号==判断值是否相等
三等号===先判断类型是否相同,再判断值是否相等
undefined==null true
undefined===null false
123==“123” true
123===“123” false
如何判断变量是否可用?
先判断类型是否为undefined,再判断值是否为null,否则可用
isNan() 非数字判断
alert(isNaN('123')) //false 能转成数字的都是false alert(isNaN('abc'))
eval() 将一段字符串当做js代码执行
应用场景:当从文本框中获取值时,得到的是字符串,希望那段字符串当做js执行,则使用eval()
eval('alert("abc")')
方法
使用关键字arguments获取所以的参数,是一个数组
//可变参数 function sum(){ var res=0; for(var i=0;i<arguments.length;i++) { res+=argument[i]; } } sum(1,2,3,4,5);
js不支持方法重载,如果方法重名,后写的函数会把之前的覆盖掉
匿名函数
一、可以将方法赋值给一个变量,这个变量表示一个方法
var fn = function(a,b){alert(a+b);}; //调用 fn(1,2);
二、定义时完成调用
(function(){})()
三、赋值给一个变量完成调用
new Function("a","b","return a+b");
闭包(主要作用是类的定义)
支持在函数内部调用函数之前声明过的变量
作用域链:变量的作用域在当前函数中,及当前函数内部定义的函数中,形成了一个链条(缺点:会让变量的值在内存中长期存放,无法释放,尽量避免闭包的发生)
//定义一个函数say function say(name){ //返回一个函数 return function(){ //输出name的值 alert("我是"+name) } } //调用say函数,将返回值赋值给fn var fn = say("小明"); //调用fn fn();
window.οnlοad=function(){ var btn = document.getElementsByName("happy"); for(var i=0;i<btn.length;i++){ //逐个为按钮注册点击事件 btn[i].οnclick=function(){ //正确写法 //this.value="noHappy"; //错误原因,i的闭包,当调用此方法时,由于该方法没有i,所以去外层方法寻找,但由于当时已经循环完,所以i为7,也就是说,不管点击哪个按钮,执行的都是第8个(也就是i为7)按钮的事件 document.getElementById(i).value="noHappy"; } } }
<input type="button" name="happy" id="0" value="happy"/>
<input type="button" name="happy" id="1" value="happy"/>
<input type="button" name="happy" id="2" value="happy"/>
<input type="button" name="happy" id="3" value="happy"/>
<input type="button" name="happy" id="4" value="happy"/>
<input type="button" name="happy" id="5" value="happy"/>
<input type="button" name="happy" id="6" value="happy"/>
<input type="button" name="happy" id="7" value="happy"/>
模拟面向对象
//第一种方式 //为类增加成员 function Person(gender){ //在类内部声明一个Gender属性,初始化为gender值 this.Gender=gender; this.say=function(){ alert("我是"+this.Gender+"的"); } } //使用构造方法创建对象 var women=new Person("女"); //调用方法 person.say(); alert(typeof(women));//object alert(typeof(Person("女")));//undefined,因为Person作为函数时,没有返回值,所以是undefined alert(typeof(Person));//function,Person就是一个函数,类型是function //第二种方式 //为对象增加属性 function Person(){} var p=new Person(); p.Name="小明";//为对象p新增了一个Name属性 p.say=function(){ alert(p.Name); } p.say(); //新建的对象,是没有Name属性的,因为类Person中没有Name属性 var p1=new Person(); alert(p1.Name)
原型
//原型:对象的类型 function Person(){ this.Age=18; } var p = new Person(); //访问原型,为原型注册数据成员,下面两种结果一样 p.__proto__.Name="小红";//两个下划线 Person.prototype.Name="小紫";
集合
//使用[]定义数组 var arr=[1,'a',"小明"]; arr[0] //键值对{键:值} var arr2={name:"小明",age:18,gender:'男'}; arr2["name"]//将arr2认为是集合,铜鼓键访问值 arr2.name//将arr2任务是json,通过属性访问值 //定义json数组 var temp=[{ name:"小明", age:17 },{ name:"小红", age:18 },{ name:"小紫", age:18 }]; //输出对象的name for(var item in temp){ alert(temp[item].name)//temp[item]["name"]与前面结果相同 }
用javascript写原生ajax(笔记)
AJAX 的全名叫做 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。它最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,优化用户体验。平时自己使用 ajax 做请求都是用的 jquery 里封装好的 ajax 函数,下面用javascript来写一写原生的ajax请求。
(
插播一条ajax的知识点:
ajax请求头中特有的字段:X-Requested-With: XMLHttpRequest; 你可以在服务端通过这个字段来判断一个http请求是否为ajax请求。
)
大致分为以下四个步骤:
1、创建ajax对象 (考虑各个浏览器的兼容性)
2、连接到服务器
3、发送请求
4、接收返回值进行处理
<script> window.οnlοad=function() { //由一个按钮来触发发送ajax请求的动作 var btn = document.getElementById("btn"); btn .onclick = function() { //1.创建ajax对象,考虑浏览器的兼容性 var xhr; //ajax对象 if(window.XMLHttpRequest) //如果有XMLHttpRequest,那就是非IE6版本以下的浏览器。 { //创建ajax对象 var xhr= new XMLHttpRequest(); } else //如果没有XMLHttpRequest,那就是IE6版本一下的浏览器 { //IE6浏览器创建ajax对象 var xhr= new ActiveXObject("Microsoft.XMLHTTP"); } //2.连接服务器 //open(方法、文件名、是否异步传输) //方法: //传输方式是get方式还是post方式。 //文件名 //告诉服务器要读哪个文件 //异步传输 //基本上都是用异步 /*请求为GET方式*/ /*GET请求方式会首先找浏览器中的缓存,加上t='+new Date().getTime()"的目的是为了消除缓存,每次的t的值不一样。*/ xhr.open("GET","/quest?t='+new Date().getTime()",true); //3.发送请求 /*POST请求时可以带参数,作为请求的参数*/ xhr.send(); //4.接收返回 //客户端和服务器端有交互的时候会调用onreadystatechange xhr.onreadystatechange=function() { //xhr.readyState //浏览器和服务器,进行到哪一步了。 //0->(未初始化):还没有调用 open() 方法。 //1->(载入):已调用 send() 方法,正在发送请求。 //2->(载入完成):send() 方法完成,已收到全部响应内容。 //3->(解析):正在解析响应内容。 //4->(完成):响应内容解析完成,可以在客户端调用。 if(xhr.readyState==4) { if(xhr.status==200)//判断是否成功,如果是200,就代表成功 { alert("成功"+xhr.responseText); /*xhr.responseText 是服务器返回的文本信息*/ } else { alert("失败"); } } }; } }; </script>
以上就是简单的使用javascript写原生ajax请求的代码。
最后补充:ajax是不能进行跨域请求的,这也是局限性所在,如果想要进行跨域请求,可以使用jsonp来实现,它利用的是请求js文件时可以进行跨域请求的原理。
初遇 Asp.net MVC 数据库依赖缓存那些事儿
声明:本文为作者原创文章,转载请注明出处 https://www.cnblogs.com/MaMaNongNong/p/8904022.html
问题背景:
最近做一个非常简单的功能,就是使用ajax请求的方式从服务端请求一段下拉表的数据。
以前也有做过这个功能,只不过这次做这个功能的时候冒出了一个想法:
我请求的这段数据它是一段相对比较固定的数据,也就是说它不怎么改变,也许几个月才会改变一次。由于这种数据的变化周期很长,所以以前做这种功能的时候,会使用缓存进行优化,可以直接从缓存中读取数据,避免每一次接收了ajax请求后都要向数据库要数据,减少服务器与数据库之间的交互,减轻数据库服务器的压力。但是问题来了,数据的变化周期再长终究是要变化的,当数据库中的数据变化的时候你就要对旧有的缓存内容进行移除(remove)操作,好的,以前我是这样做的:
public ActionResult GetAllFJs() { //尝试从缓存中取出数据 var FJIdNames = HttpContext.Cache["FJIdNames"]; if (null == FJIdNames) //缓存中没有数据 { //从数据库中查询出数据 FJIdNames = FJService.GetAll().Select(fj => new { Id = fj.Id, Name = fj.Name }).ToArray(); //将数据缓存起来下一次用(设置一个缓存有效时间,使用绝对过期,到达指定过期时间,缓存失效) HttpContext.Cache.Insert( "FJIdNames", //缓存项的键(string) FJIdNames, //缓存项的值(object) null, DateTime.UtcNow.AddMinutes(30), //绝对到期时间(DateTime) System.Web.Caching.Cache.NoSlidingExpiration //滑动到期间隔时间(TimeSpan) ); } //将得到的数据转化成json格式字符串 string jsonResult = CommonHelper.ConvertToJsonStr(FJIdNames); //返回给浏览器的结果字符串 return Content(jsonResult); }
说明:这是一个 asp.net MVC 中处理一个请求的action方法,其中有一个重要的方法
public void Insert(
string key, --> 缓存项的键
object value, --> 缓存项的值
CacheDependency dependencies, --> 缓存依赖项(这里不用,后面会用,是重头戏)
DateTime absoluteExpiration, --> 绝对过期时间点
TimeSpan slidingExpiration --> 滑动过期时间间隔
);
在这里是利用了缓存的过期时间来对缓存数据进行更新操作,每当缓存数据经过了30分钟后就要重新从数据库中拿一次数据来更新缓存中的内容,来看一下执行的结果 (为了便于展示结果,将绝对过期时间调为30s):
第一次请求:
(数据库表中此刻的数据):
(执行结果):
第一次请求的话肯定缓存中是没有数据的,所以要向数据库要数据;
第二次请求:
(请求之前改变一下数据库中相应表的数据)
(执行结果):
第二次请求,由于没有到缓存项的绝对过期时间,缓存中还有数据,不用向数据库要数据,从缓存中取出来就行;
过30s后再请求:
(数据库表中此刻的数据):
(执行结果):
缓存中数据已经过期被移除,需要重新向数据库请求;
从以上三次请求可以看到,最后的确是实现了缓存数据的更新。
但同样可以看到这样做有一个坏处:在还没到达过期时间的这段时间里,请求的数据依然是原来的缓存中数据,和数据库中的数据并不一致。
其中设置的绝对过期时间点要根据实际的数据刷新的可容忍度来进行设定,而恰好在我的这个应用场景中的可容忍度最不能把握,它要求的是 当数据库中的数据改变以后,缓存中对应的数据在下一次请求结束后一定要马上跟着改变,当然你也可以把过期时间尽可能的调小,调到一秒。当然,这样的话还是要频繁的向数据库进行请求,那不是背离了我们原本使用缓存优化的目的了吗?
所以现在的问题是:有没有一种方法能让数据库和服务器程序建立一种联系,这种联系好比是一种“心灵感应”,当数据库表中的数据发生变化的时候,马上就能让服务器中的对应的缓存项“感应”到这个变化,从而让原来的缓存项失效呢?答案当然是,有的。
数据库依赖缓存,对,是它,就是它。
ASP.NET 有 3 种类型的依赖:
- 缓存项目依赖
- 文件或文件夹依赖
- 数据库依赖
本文要讲的是数据库依赖:数据库缓存依赖是一项当数据库中的相关数据被修改时自动使缓存的数据对象失效的技术。
以前不知道有 数据库依赖 的时候,有想过使用文件或文件夹依赖来实现类似于数据库依赖缓存的功能,大概的思路就是:用某个文件作为媒介,在进行了对数据库表的数据改动后,同时改动一下该文件来触发缓存的失效。还好我在看了大神们写的博文以后,马上停止了我“愚蠢”的想法,那样做其实是画蛇添足,而且并不能很好的实现,有现成的数据库依赖不用干嘛。
我们来看一下如何使用它:
1、配置:
1)在当前网站mvc项目下的Web.config文件中加入
<!--(数据库连接字符串)<configuration> 结点下配置-->
<connectionStrings> <add name="connStr" connectionString="server=127.0.0.1; user id=sa; password=root; database=LZXF" providerName="System.Data.SqlClient" /> </connectionStrings>
<!--(缓存数据库依赖配置)<system.web> 结点下配置--> <caching> <sqlCacheDependency enabled="true"> <databases> <add name="LZXF" pollTime="5000" connectionStringName="connStr" /> </databases> </sqlCacheDependency> </caching>
2)在 Application_Start() 中加入
//配缓存数据库依赖 string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ToString(); //启动数据库的数据缓存依赖功能 SqlCacheDependencyAdmin.EnableNotifications(connectionString); //启用数据表缓存 SqlCacheDependencyAdmin.EnableTableForNotifications(connectionString, "(表名)"); //第二个参数可以是单个表名或表名的数组
2、代码部分
public ActionResult GetAllFJs() { //尝试从缓存中取出数据 var FJIdNames = HttpContext.Cache["FJIdNames"]; if (null == FJIdNames) //缓存中没有数据 { //从数据库中查询出数据 FJIdNames = FJService.GetAll().Select(fj => new { Id = fj.Id, Name = fj.Name }).ToArray(); //将数据缓存起来下一次用(使用数据库依赖的缓存,当数据库中对应的表的数据发生改变时,缓存失效) HttpContext.Cache.Insert("FJIdNames", FJIdNames, new SqlCacheDependency("LZXF", "T_FJs")); } //将得到的数据转化成json格式字符串 string jsonResult = CommonHelper.ConvertToJsonStr(FJIdNames); //返回给浏览器的结果字符串 return Content(jsonResult); }
其中的 SqlCacheDependency(数据库缓存依赖类) 是最重要的一个类,就是它建立起了数据库和服务器程序之间 “沟通的桥梁” ,
使用它的一个构造方法:
public SqlCacheDependency(string databaseEntryName, string tableName) 来创建一个数据库缓存依赖类对象,传给创建缓存项的方法Insert, 这样来建立该缓存项的数据库依赖,每当该指定表中发生数据的变动时都会销毁该缓存项。
看一下执行结果:
没改变数据库表数据之前:
(执行结果):
改变数据库表数据之后:
(执行结果):
改变了数据库表的数据以后再去请求数据,请求到最新的数据,说明旧的缓存被移除了
既然都会用了,那接下来要看的就是原理,(原理,原理最重要)
用完了以后就会很疑惑,它是怎么实现的呢?
思考:首先是改动了数据库表中的数据,这一步操作以后必定要引发某种操作。在数据库中改变表中数据会触发操作?讲的不就是触发器吗。
来看一下数据库中多了些什么:
打开sqlServerManagement查看数据库发现
多了一个 AspNet_SqlCacheTablesForChangeNotification 表,表中内容:
要找的触发器在这里:
看一下触发器里面的内容:
说的就是:当 T_FJs 表中发生了 INSERT, UPDATE, DELETE 这些操作,就去执行 dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure 这个存储过程,这个存储过程是我们开启sql server的缓存依赖自动生成的
找一下存储过程 dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure,在这里:
内容是:
所以最后对原理的总结,我就引用一篇大神博客(https://www.lanhusoft.com/Article/290.html)里的总结:
当sql server启用缓存依赖之后,就会在对应的数据库添加相应的表、触发器和一些存储过程。它是利用触发器来监测表的数据的变化,如果有增、删、改就插入数据到通知表,然后通知订阅这个通知的网站此缓存项失效。
最后要说的是使用缓存依赖也有限制:必须用ASP.Net和SQL Server开发应用,也就是SqlCacheDependency是基于微软的那套体制。
参考博文地址:
https://www.cnblogs.com/SkySoot/archive/2012/08/15/2640559.html
https://www.lanhusoft.com/Article/290.html
这是我的第一篇博文,以前想过为什么要写博文这个问题?现在网上随便一搜都有自己想要的内容,而且有些大神写的很不错。后来慢慢的发现每一次遇到问题都要上网搜博客看,而且很多时候遇到的是同一个问题,可能以前就已经思考过了,现在又要浪费时间去从头找着看已经看过的东西,那我为什么不自己写好了整理好了存着呢。当然,方便自己的同时,希望也能方便到正在阅读本文的你。谢谢!
前端JS 与 后台C# 之间JSON序列化与反序列化(笔记)
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
首先,我们来看一下一个C#的类变量数据是怎么从后端C#走向前端Javascript的。
源码如下:
(C#对象 ==> json字符串)
/// <summary> /// Json字符转换的配置对象,设置了基本Json配置的信息 /// </summary> private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { //忽略循环引用,如果设置为Error,则遇到循环引用的时候报错(建议设置为Error,这样更规范) ReferenceLoopHandling = ReferenceLoopHandling.Ignore, //日期格式化,默认的格式也不好看 DateFormatString = "yyyy-MM-dd HH:mm:ss", //json中属性开头字母小写的驼峰命名 ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() }; //根据配置规则得到json转换类 private static JsonSerializer scriptSerializer = JsonSerializer.Create(Settings); /// <summary> /// 将任意一个对象转换为json字符串的表示形式 /// </summary> /// <param name="obj">要转换成json字符串的对象</param> /// <returns>转换后的json字符串,失败则返回null</returns> public static string ConvertToJsonStr(object obj) { try { StringWriter stringWriter = new StringWriter(); scriptSerializer.Serialize(stringWriter, obj); return stringWriter.ToString(); } catch { return null; } }
(json字符串 ==> javascript对象)
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
然后,再反过来看一下一个Javascript的变量数据又是怎么一步步走向C#后端的。
源码如下:
(json字符串 ==> c#对象)
/// <summary> /// 将json字符串转换成对象 /// </summary> /// <typeparam name="T">要转换成的类型</typeparam> /// <param name="jsonStr">json字符串</param> /// <returns>成功转换返回对象,否则返回null</returns> public static T JsonStrToObject<T>(string jsonStr) { try { JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); return javaScriptSerializer.Deserialize<T>(jsonStr); } catch { return default(T); } }
(javascript对象 ==> json字符串)
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
补充: