写了四年代码,然后管理了两年团队,每次面试我都想说为什么总是问书本知识,后来一想算了社会就是这样的,我们不要刻意的去纠结关于这些知识,但是我们要顺应时代也要把这些询问知识点掌握牢靠。开始我的表演
1、数据库方面的索引的作用,以及申明的方法?
我们暂时就用:“索引就像书的目录, 通过书的目录就准确的定位到了书籍具体的内容。”这句话来形容申明叫索引。
建表时候一定会有主键那么对应的就会有对应的聚集索引,从而就有了树状结构的数据表。通过每一个主键之间的主从关系的关联形成了一个临时性数据库(我们一般都会有主键,从而形成了对应的平衡树。)
那么问题了来了我们知道了聚集索引,从而就开始疑问什么叫非聚集索引呢?
非聚集索引叶节点仍然是索引节点,只是有一个指针指向对应的数据块,此如果使用非聚集索引查询,而查询列中包含了其他该索引没有覆盖的列,那么他还要进行第二次的查询,查询节点上对应的数据行的数据。
如有以下表t1:
id | username | score |
1 | 小明 | 90 |
2 | 小红 | 80 |
3 | 小华 | 92 |
.. | .. | .. |
256 | 小英 | 70 |
以及聚集索引clustered index(id), 非聚集索引index(username)。
使用以下语句进行查询,不需要进行二次查询,直接就可以从非聚集索引的节点里面就可以获取到查询列的数据。
select id, username from t1 where username = '小明'
select username from t1 where username = '小明'
但是使用以下语句进行查询,就需要二次的查询去获取原数据行的score:
select username, score from t1 where username = '小明'
复合索引(覆盖索引)
建立两列以上的索引,即可查询复合索引里的列的数据而不需要进行回表二次查询,如index(col1, col2),执行下面的语句
select col1, col2 from t1 where col1 = '213';
要注意使用复合索引需要满足最左侧索引的原则,也就是查询的时候如果where条件里面没有最左边的一到多列,索引就不会起作用。
在SQL Server中还有include的用法,可以把非聚集索引里包含的列包含进来,而不一定需要建立复合索引。
2、关于实际代码中c#接口与抽象类的区别?
接口和抽象类都具有
1、都可以被继承
2、都不能被实例化
3、都可以包含方法声明
4、派生类必须实现未实现的方法
接口就是接口(interface)就是一种规范,定义好了规范剩下的工作就会简单方便快捷。
这个是我2016年写的接口的实际例子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<IShow> list = new List<IShow>();
list.Add(new Map());
list.Add(new Voice());
list.Add(new Video());
list.Add(new ThreeD());
foreach (IShow ishow in list)
{
ishow.Show();
Console.ReadKey();
}
}
}
interface IShow
{
void Show();
}
public class Map : IShow
{
public void Show()
{
Console.WriteLine("显示图片");
}
}
public class Voice : IShow
{
public void Show()
{
Console.WriteLine("播放声音");
}
}
public class Video : IShow
{
public void Show()
{
Console.WriteLine("显示视频");
}
}
public class ThreeD : IShow
{
public void Show()
{
Console.WriteLine("3D交互");
}
}
}
public class Vm : IShow
{
public void Show()
{
Console.WriteLine("vm感观");
}
}
后来来了一个VM这个就是有了VR。
如果预计会出现版本问题,可以创建“抽象类”。例如,创建了狗(Dog)、鸡(Chicken)和鸭(Duck),那么应该考虑抽象出动物(Animal)来应对以后可能出现风马牛的事情。而向接口中添加新成员则会强制要求修改所有派生类,并重新编译,所以版本式的问题最好以抽象类来实现。
abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现。
接口和抽象类最本质的区别:抽象类是一个不完全的类,是对对象的抽象,而接口是一种行为规范。
抽象类:
public abstract class Fruit
{
public string vendor { get; set; } //默认为private
public abstract float Price { get; } //抽象属性必须是公有的
public abstract void GrowInArea(); //抽象方法必须是公有的
}
public class Apple : Fruit
{
public override float Price
{
get
{
if (vendor == "红富士")
return 100;
else
return 0;
}
}
public override void GrowInArea()
{
Console.WriteLine("我在南方北方都能生长,我的生产商是:" + vendor + ",我现在的价格
是:" + Price);
}
}
static void Main(string[] args)
{
Fruit f = new Apple();
f.vendor = "红富士";
f.GrowInArea();
f = new Orange();
f.vendor = "柑橘";
f.GrowInArea();
Console.ReadKey();
}
3、关于MVC中拦截器的使用?
在ASP.NET MVC中,有三种拦截器:Action拦截器、Result拦截器和Exception拦截器。我要用到第一种和第三种。其实所谓的ASP.NET MVC拦截器,也没什么神秘的,就是一个普通的类而已。只不过需要继承FilterAttribute基类,Action拦截器还要实现IActionFilter接口,而Exception拦截器需要实现IExceptionFilter接口。
我们先来看实现:让我们在Controllers目录下新建一个Filters目录,然后在Filters下新建两个类,一个叫LoggerFilter一个叫ExceptionFilter。首先是LoggerFilter的代码。
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.Mvc;
6using System.Web.Mvc.Ajax;
8namespace MVCDemo.Controllers.Filters
9{
public class LoggerFilter : FilterAttribute, IActionFilter
{
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData["ExecutingLogger"] = "正要添加公告,已以写入日志!时间:" + DateTime.Now;
}
17 void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.Controller.ViewData["ExecutedLogger"] = "公告添加完成,已以写入日志!时间:" + DateTime.Now;
}
}
22}
可以看到,这个类继承了FilterAttribute并实现了IActionFilter。其中关键是IActionFilter,它有两个方法,OnActionExecuting在被拦截Action前执行,OnActionExecuted在被拦截Action后执行。两个方法都有一个参数,虽然类型不同,但其实都是一个作用:被拦截Action的上下文。
这个地方我得解释一下,你拦截器拦截了Action,在做处理时难免要用到被拦截Action相关的东西,例如在我们的例子中,就需要想被拦截Action所在Controller的ViewData中添加内容,所以,拦截器方法有一个参数表示被拦截Action的上下文是顺理成章的事。
下面再看ExceptionFilter这个拦截器,它是在Action出现异常时发挥作用的。
ExceptionFilter.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MVCDemo.Controllers.Filters
{
public class ExceptionFilter : FilterAttribute,IExceptionFilter
{
void IExceptionFilter.OnException(ExceptionContext filterContext)
{
filterContext.Controller.ViewData["ErrorMessage"] = filterContext.Exception.Message;
filterContext.Result = new ViewResult()
{
ViewName = "Error",
ViewData = filterContext.Controller.ViewData,
};
filterContext.ExceptionHandled = true;
}
}
}
完整实例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using MVCDemo.Models;
using MVCDemo.Models.Interfaces;
using MVCDemo.Models.Entities;
using MVCDemo.Controllers.Filters;
namespace MVCDemo.Controllers
{
public class AnnounceController : Controller
{
public ActionResult Release()
{
ICategoryService cServ = ServiceBuilder.BuildCategoryService();
List<CategoryInfo> categories = cServ.GetAll();
ViewData["Categories"] = new SelectList(categories, "ID", "Name");
return View("Release");
}
[LoggerFilter()]
[ExceptionFilter()]
public ActionResult DoRelease()
{
AnnounceInfo announce = new AnnounceInfo()
{
ID = 1,
Title = Request.Form["Title"],
Category = Int32.Parse(Request.Form["Category"]),
Content = Request.Form["Content"],
};
IAnnounceService aServ = ServiceBuilder.BuildAnnounceService();
aServ.Release(announce);
ViewData["Announce"] = announce;
System.Threading.Thread.Sleep(2000);
ViewData["Time"] = DateTime.Now;
System.Threading.Thread.Sleep(2000);
return View("ReleaseSucceed");
}
}
}
4、session与cookie的差距,为什么要用session,cookie实际操作的具体每一个方法,并且还说下token?
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗 ,考虑到安全应当使用session。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
- 考虑到减轻服务器性能方面,应当使用COOKIE。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 所以个人建议:
- 将登陆信息等重要信息存放为SESSION
- 其他信息如果需要保留,可以放在COOKIE中
session 和 oauth token并不矛盾,作为身份认证 token安全性比session好,因为每个请求都有签名还能防止监听以及重放攻击,而session就必须靠链路层来保障通讯安全了。如上所说,如果你需要实现有状态的会话,仍然可以增加session来在服务器端保存一些状态
App通常用restful api跟server打交道。Rest是stateless的,也就是app不需要像browser那样用cookie来保存session,因此用session token来标示自己就够了,session/state由api server的逻辑处理。 如果你的后端不是stateless的rest api, 那么你可能需要在app里保存session.可以在app里嵌入webkit,用一个隐藏的browser来管理cookie session.
token就是登陆的令牌,避免重复登陆和反复获取session带给服务器的压力等。
5、对应页面相互之间传递参数有那些方法和对应这些方法的优缺点?
1、url方式 http://abc.com?name=xiaoming&age=18&gender=man
2、使用cookie保存:
//1、保存一条数据
document.cookie="name=abc";
document.cookie="age=18";
//2、获取所有数据
var cookie=document.cookie;
console.log(cookie); //"name=abc; age=18; PHPSESSID=fr1njdv6apf3neoj5nehntrps7"
//之后可以解析字符串,获取指定的数据内容
//3、设置cookie的有效期
document.cookie="id=666;expires="+new Date("2017-10-22 08:00");
//第一种类型:会话cookie
// //1、设置值
$.cookie("phone","13188886666");
$.cookie("email","123@qq.com");
// //2、获取值
var phone=$.cookie("phone");
console.log(phone);
var email=$.cookie("email");
console.log(email);
//第二种类型:设置长期cookie(具有指定有效期)
$.cookie("address","广东深圳市",{
expires:7 //expires不仅仅可以是日期类型的对象,也可以是以天为单位的数字
});
$.cookie("tel","0755-88888888",{
expires:1/24 //该cookie值就会保存一小时
});
$.cookie("birthday","1.1",{
expires:new Date("2018-01-01 08:00") //对于这样的过期时间,已经在内部处理好了时区问题
});
//删除指定的cookie
$.removeCookie("birthday");
3、使用h5的localStorage,或者sessionStorage存储对象类型
存储对象的正确的方式:
var p2={name:"周瑜",age:16};
var s2=JSON.stringify(p2); //将对象"序列化"为JSON数据(字符串格式)
localStorage.setItem("p2",s2); //以字符串格式存储信息
var s2_2=localStorage.getItem("p2"); //获取存储的信息,也是字符串格式
var p2_2=JSON.parse(s2_2); //将JSON数据反序列化为对象
localStroage和sessionStorage使用大致相同,他们的不同之处在于,localstroage是永久保存,而sessionstroage是会话存在,
当会话结束,sessionstroage保存值也会清空。