1. 程式人生 > >2018年11月2日關於面試中的實際問題

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?

  1. cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。
  2. cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙 ,考慮到安全應當使用session。
  3. session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能
  4. 考慮到減輕伺服器效能方面,應當使用COOKIE。
  5. 單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20個cookie。
  6. 所以個人建議:
  7.    將登陸資訊等重要資訊存放為SESSION
  8.    其他資訊如果需要保留,可以放在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儲存值也會清空。