2018年11月2日關於面試中的實際問題
寫了四年程式碼,然後管理了兩年團隊,每次面試我都想說為什麼總是問書本知識,後來一想算了社會就是這樣的,我們不要刻意的去糾結關於這些知識,但是我們要順應時代也要把這些詢問知識點掌握牢靠。開始我的表演
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","[email protected]");
// //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儲存值也會清空。