一 python基礎
1. 解釋一下Python中的三元運算
如果表達式爲True,就執行[on true]中的語句。否則,就執行[on false]中的語句
2. 解釋GIL全局解釋器鎖
GIL的全稱是:Global Interpreter Lock,意思就是全局解釋器鎖,
CPython在執行多線程的時候並不是線程安全的,所以爲了程序的穩定性,加一把全局解釋鎖,能夠確保任何時候都只有一個Python線程執行
3. 解釋一下Python中的繼承
注意:基類就是父類,派生類就是子類
當一個類繼承另一個類,它就被稱爲一個子類/派生類,繼承父類/基類/超類。
繼承能讓我們重新使用代碼,也能更容易的創建和維護應用
-
單繼承:一個類繼承單個基類
-
多繼承:一個類繼承多個基類
-
多級繼承:一個類繼承自單個基類,後者繼承自另一個基類
-
分層繼承:多個類繼承自單個基類
-
混合繼承:兩種或多種類型繼承的混合
4. 解釋Python中的help()和dir()函數
help函數是一個內置函數,用於查看函數或模塊用途的詳細說明
dir()函數時python的內置函數,dir()函數不帶參數時,返回當前範圍內的變量、方法和定義的類型列表,帶參數時,返回參數的屬性、方法列表
5. 什麼是猴子補丁?
屬性在運行時的動態替換,叫做猴子補丁(Monkey Patch)。
注意:運行時刻是指一個程序在運行(或者在被執行)的狀態
6. 請解釋使用args和*kwargs的含義
-
當我們不知道向函數傳遞多少參數時,比如我們向傳遞一個列表或元組,我們就使用*args。
-
在我們不知道該傳遞多少關鍵字參數時,使用**kwargs來收集關鍵字參數。
7. 什麼是負索引?
負索引和正索引不同,它是從右邊開始檢索。
8. 解釋Python中的join()和split()函數
-
Join()能讓我們將指定字符添加至字符串中。
-
Split()能讓我們用指定字符分割字符串。
9. 怎麼移除一個字符串中的前導空格?
-
我們使用方法lstrip()可以將它從字符串中移除。
-
後導空格 rstrip
10. Python中的pass語句是什麼?
- 佔位符
11. Python中的閉包是什麼?
當一個嵌套函數在其外部區域引用了一個值時,該嵌套函數就是一[個閉包。其意義就是會記錄這個值。
12. 解釋一下Python中的邏輯運算符
- And
- or
- not
13.什麼是切片?
切片是Python中的一種方法,能讓我們只檢索列表、元素或字符串的一部分。在切片時,我們使用切片操作符[]。
14. 解釋lambda表達式,什麼時候會用到它?
如果我們需要一個只有單一表達式的函數,我們可以匿名定義它。拉姆達表達式通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用,也就是指匿名函數。
15. 什麼是遞歸?
在調用一個函數的過程中,直接或間接地調用了函數本身這個就叫遞歸。但爲了避免出現死循環,必須要有一個結束條件
16. 什麼是生成器?
生成器會生成一系列的值用於迭代,這樣看它又是一種可迭代對象。它是在for循環的過程中不斷計算出下一個元素,並在適當的條件結束for循環。
17. 什麼是迭代器?
迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退。我們使用inter()函數創建迭代器。
18. 請說說生成器和迭代器之間的區別?
-
在創建生成器時,我們創建一個函數;
-
在使用迭代器時,我們使用內置函數iter()和next()。
在生成器中,我們使用關鍵字‘yield’來每次生成/返回一個對象。 生成器中有多少‘yield’語句,你可以自定義。 每次‘yield’暫停循環時,生成器會保存本地變量的狀態。而迭代器並不會使用局部變量,它只需要一個可迭代對象進行迭代。 使用類可以實現你自己的迭代器,但無法實現生成器。 生成器運行速度快,語法簡潔,更簡單。 迭代器更能節約內存。
19. 詮釋Python中的yield用法
yield簡單說來就是一個生成器,這樣函數它記住上次返 回時在函數體中的位置。對生成器第 二次(或n 次)調用跳轉至該函 次)調用跳轉至該函數。
20. 解釋Python的參數傳遞機制
Python使用按引用傳遞(pass-by-reference)將參數傳遞到函數中。如果你改變一個函數內的參數,會影響到函數的調用。這是Python的默認操作。不過,如果我們傳遞字面參數,比如字符串、數字或元組,它們是按值傳遞,這是因爲它們是不可變的。
python不允許程序員選擇採用傳值還是傳引用。Python參數傳遞採用的肯定是“傳對象引用”的方式。這種方式相當於傳值和傳引用的一種綜合。如果函數收到的是一個可變對象(比如字典或者列表)的引用,就能修改對象的原始值--相當於通過“傳引用”來傳遞對象。如果函數收到的是一個不可變對象(比如數字、字符或者元組)的引用,就不能直接修改原始對象--相當於通過“傳值’來傳遞對象。
21. 值傳遞和引用傳遞的區別?
-
值傳遞僅僅傳遞的是值
-
引用傳遞,傳遞的是內存地址,修改後會改變內存地址對應儲存的值。
22. 如何在Python中創建自己的包?
Python中創建包是比較方便的,只需要在當前目錄建立一個文件夾,文件夾中包含一個init.py文件和若干個模塊文件,其中init.py可以是一個空文件,但還是建議將包中所有需要導出的變量放到all中,這樣可以確保包的接口清晰明瞭,易於使用。
23. 什麼是python的元類
元類是類的類對象,換言之類是元類的實例,Python中默認的元類爲type,可以通過自定義元類的方式實現對類創建的控制。
24. 如何評價python的自省機制
自省就是面向對象的語言所寫的程序在運行時,能夠知道對象的類型。簡單一句就是,運行時能夠獲知對象的類型。
25. 談談希爾和歸併排序的異同
- 希爾排序
希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本。
希爾排序是非穩定排序算法。該方法因DL.Shell於1959年提出而得名。
希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;
隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。
- 歸併排序
歸併排序是採用分治法的一個非常典型的應用。
歸併排序的思想就是先遞歸分解數組,再合併數組。
將數組分解最小之後,然後合併兩個有序數組,基本思路是比較兩個數組的最前面的數,誰小就先取誰,取了後相應的指針就往後移一位。
然後再比較,直至一個數組爲空,最後把另一個數組的剩餘部分複製過來即可。
26. 請手寫一個折半查找
def binary_chop(alist, data):
"""
非遞歸解決二分查找
"""
n = len(alist)
first = 0
last = n - 1
while first <= last:
mid = (last+first)//2
if alist[mid] > data:
last = mid - 1
elif alist[mid] < data:
first = mid + 1
else:
return True
return False
def binary_chop2(alist, data):
"""
遞歸解決二分查找
"""
n = len(alist)
if n < 1:
return False
mid = n // 2
if alist[mid] > data:
return binary_chop2(alist[0:mid], data)
elif alist[mid] < data:
return binary_chop2(alist[mid+1:], data)
else:
return True
if __name__ == "__main__":
lis = [2,4, 5, 12, 14, 23]
if binary_chop(lis, 12):
print('ok')
else:
print('false')
27. 給定一個排好序(升序)的列表與待查找的關鍵字,成功則返回其索引,失敗則返回-1。
def search(list, key):
left = 0 # 左邊界
right = len(list) - 1 # 右邊界
while left <= right:
mid = (left + right) // 2 # 取得中間索引
if key > list[mid]:
left = mid + 1
elif key < list[mid]:
right = mid - 1
else:
return mid
else:
return -1
list = [2, 5, 13, 21, 26, 33, 37]
print(search(list, 5))
28. 談談類方法和靜態方法以及實例方法的區別和異同
-
調用方式上
靜態方法依賴於類,通過類.靜態方法調用;實例方法依賴於類的對象,需要創建對象後,對象.實例方法使用
-
使用上
實例方法內部不能定義靜態變量,會出現編譯錯誤;實例方法可以直接調用靜態方法;靜態方法內部可以定義和使用實例變量,靜態方法無法直接調用實例方法(因靜態方法加載時類還沒有實例化,實例方法依賴於類的對象)
29. 談談上下文管理
- 概念:實現了上下文協議的對象即爲上下文管理器。
上下文協議:enter、exit
- 作用:用於資源的獲取和釋放。
30. 簡單說說高階函數
像map()函數這種能夠接收函數作爲參數的函數,稱之爲高階函數
31. 說說你用過的設計模式
-
Factory Method(工廠方法)
-
Abstract Factory(抽象工廠)
-
Builder(建造者)
-
Prototype(原型)
-
Singleton(單例)
-
Prototype(原型)
- 意圖:
用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。
- 意圖:
-
單例
-
意圖:
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。 -
適用性:
當類只能有一個實例而且客戶可以從一個衆所周知的訪問點訪問它時。
-
32. 談談python單元測試
傳統測試無非就是自己運行一下程序查看結果,或者前後端服務進行聯調,這裏要說的是走正規流程的單元測試,那到底什麼是單元測試呢?
顧名思義,只測試當前單元的程序或者代碼,也可以理解當前模塊的代碼塊,單元測試假設所有的內部或外部的依賴應該是穩定的, 已經在別處進行測試過的。
使用mock 就可以對外部依賴組件實現進行模擬並且替換掉, 從而使得單元測試將焦點只放在當前的單元功能。
簡單地說,mock就是幫我們解決測試依賴的一個模塊,在Python3中,mock已經被集成到了unittest單元測試框架中,所以不需要單獨安裝,可以直接使用。
33. 談談python特殊方法的區別
-
__new__ 和 __init__
__new__ 爲類方法,__init__ 爲實例方法。__new__ 類方法創建實例對象,__init__ 實例方法初始化實例對象。
-
__get__, __getattr__, __getattribute__ 的區別
均是訪問屬性的方法,注意是屬性 __getattr__(self, name)
當訪問屬性無法找到時,默認異常,可以自定義其返回值或者 AttributeError 異常 __getattribute__(self, name):
2.7 在新式類中引入,如果定義,則無條件執行,如果實行不存在時,也不執行 __getattr__(相當於被屏蔽掉) __get__ (self, instance, owner) :
如果class定義了它,則這個class就可以稱爲descriptor。
owner是所有者的類,instance是訪問descriptor的實例,如果不是通過實例訪問,而是通過類訪問的話,instance則爲None。
(descriptor的實例自己訪問自己是不會觸發__get__,而會觸發__call__,只有descriptor作爲其它類的屬性纔有意義。)
34. 談談插值查找
插值查找,有序表的一種查找方式。插值查找是根據查找關鍵子與查找表中最大最小記錄關鍵字比較後的查找方法。插值查找基於二分查找,將查找點的選擇改進爲自適應選擇,提高查找效率。
35. 請實現在鏈表中查找閉環
class LNode:
def __init__(self, elem):
self.elem = elem
self.pnext = None
def exitLoop(LList):
p1 = p2 = LList
while p2 and p2.pnext: #當鏈表爲空或者只有一個結點時,就不執行循環體裏的程序,返回False
p1 = p1.pnext
p2 = p2.pnext.pnext
if p1 == p2:
return True
return False
if __name__=="__main__":
LList = LNode(1)
p1 = LNode(2)
p2 = LNode(3)
p3 = LNode(4)
p4 = LNode(5)
p5 = LNode(6)
LList.pnext = p1
p1.pnext = p2
p2.pnext = p3
p3.pnext = p4
p4.pnext = p5
p5.pnext = p2
36. 談談紅黑樹與mysql索引的關係
其實紅黑樹也可以作爲索引的,但是出於某種原因,最終還是沒有選擇它,某種原因肯定是效率的問題了,沒有選擇它,肯定是有比它更
37. 談談btree和b+tree的區別
-
所有關鍵字存儲在葉子節點,非葉子節點不存儲真正的data
-
爲所有葉子節點增加了一個鏈指針
38. 談談async await 以及yield的用法
async表示函數裏有異步操作,await表示緊跟在後面的表達式需要等待結果。
async函數返回一個 Promise 對象,可以使用then方法添加回調函數。
當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,再接着執行函數體內後面的語句。
yield 語句只能出現在 iterator 塊中,這種塊可作爲方法、運算符或訪問器的主體實現
39. 談談python原生協程,Greenlet & Generator
python 爲了將語義更加明確, 就引入了async和await關鍵詞用於定義原生的協程
-
await 只能出現在 async裏面
-
async裏面不能有yield
Greenlet是python的一個C擴展,來源於Stackless python,旨在提供可自行調度的‘微線程’, 即協程。
generator實現的協程在yield value時只能將value返回給調用者(caller)。
而在greenlet中,target.switch(value)可以切換到指定的協程(target), 然後yield value。greenlet用switch來表示協程的切換,從一個協程切換到另一個協程需要顯式指定。
40. Dict是有序的嗎?爲什麼?
-
沒有
-
根據hash值排序的
二 Django
1. Django 、Flask、Tornado的對比
-
Django走的是大而全的方向,開發效率高。它的MTV框架,自帶的ORM,admin後臺管理,自帶的sqlite數據庫和開發測試用的服務器 給開發者提高了超高的開發效率
-
Flask是輕量級的框架,自由,靈活,可擴展性很強,核心基於Werkzeug WSGI工具和jinja2模板引擎
-
Tornado走的是少而精的方向,性能優越。它最出名的是異步非阻塞的設計方式
Tornado的兩大核心模塊: 1.iostraem:對非阻塞式的socket進行簡單的封裝 2.ioloop:對I/O多路複用的封裝,它實現了一個單例
2. 什麼是wsgi?
-
WSGI,描述web server如何與web application通信的一種規範
-
WSGI協議主要包括server和application兩部分:
-
WSGI server負責從客戶端接收請求,將request轉發給application,將application返回的response返回給客戶端; WSGI application接收由server轉發的request,處理請求,並將處理結果返回給server。
-
application中可以包括多個棧式的中間件(middlewares),這些中間件需要同時實現server與application,因此可以在WSGI服務器與WSGI應用之間起調節作用:
對服務器來說,中間件扮演應用程序,對應用程序來說,中間件扮演服務器。
3. 簡述什麼是FBV和CBV?
FBV(function base views) 基於函數的視圖
CBV(class base views) 基於類的視圖
-
使用fbv的模式,在url匹配成功之後,會直接執行對應的視圖函數
-
使用cbv模式,在url匹配成功之後,會找到視圖函數中對應的類,然後這個類回到請求頭中找到對應的
Request Method
用戶發送url請求,Django會依次遍歷路由映射表中的所有記錄,
一旦路由映射表其中的一條匹配成功了,就執行視圖函數中對應的函數名,這就是fbv的執行流程。
當服務端使用cbv模式的時候,用戶發給服務端的請求包含url和method,這兩個信息都是字符串類型
服務端通過路由映射表匹配成功後會自動去找dispatch方法,然後Django會通過dispatch反射的方式找到類中對應的方法並執行。
類中的方法執行完畢之後,會把客戶端想要的數據返回給dispatch方法,由dispatch方法把數據返回經客戶端
4. gunicorn和uwsgi的區別是什麼?底層原理是什麼?
uWSGI是C語言編寫,Gunicorn是Python,性能上前者要高。
對於Django項目用uWSGI就夠了,不用在去研究Gunicorn
5. django請求的生命週期
-
瀏覽器向django服務器發起請求
-
urls.py
- 正則匹配url
- 拋給 views.py, 調用對應的方法處理數據
-
中間件
- 全局生效(所有方法均需要先由中間件處理)
-
views.py
- 是否需要根據post get請求, 區分處理方式
- 處理數據
- 返回結果
-
templates
- 直接返回頁面
- 數據處理後返回頁面
-
層層返回給瀏覽器
6. 說一下Django,MIDDLEWARES中間件的作用和應用場景?
-
process_request : 請求進來時,權限認證
-
process_view : 路由匹配之後,能夠得到視圖函數
-
process_exception : 異常時執行
-
process_template_responseprocess : 模板渲染時執行
-
process_response : 請求有響應時執行
7. 使用orm和原生sql的優缺點?
使用 ORM 最大的優點就是快速開發,讓我們將更多的精力放在業務上而不是數據庫上,下面是 ORM 的幾個優點
-
隱藏了數據訪問細節,使通用數據庫交互變得簡單易行。
-
同時 ORM 避免了不規範、冗餘、風格不統一的 SQL 語句,可以避免很多人爲的 bug,方便編碼風格的統一和後期維護。
-
將數據庫表和對象模型關聯,我們只需針對相關的對象模型進行編碼,無須考慮對象模型和數據庫表之間的轉化,大大提高了程序的開發效率。
-
方便數據庫的遷移。當需要遷移到新的數據庫時,不需要修改對象模型,只需要修改數據庫的配置。
ORM 的最令人詬病的地方就是性能問題,不過現在已經提高了很多,下面是 ORM 的幾個缺點
-
性能問題 自動化進行數據庫關係的映射需要消耗系統資源 程序員編碼 在處理多表聯查、where 條件複雜的查詢時,ORM 可能會生成的效率低下的 SQL 通過 Lazy load 和 Cache 很大程度上改善了性能問題 SQL 調優。
-
SQL 語句是由 ORM 框架自動生成,雖然減少了 SQL 語句錯誤的發生,但是也給 SQL 調優帶來了困難。
-
越是功能強大的 ORM 越消耗內存,因爲一個 ORM Object 會帶有很多成員變量和成員函數。 對象和關係之間並不是完美映射 一般來說 ORM 足以滿足我們的需求。
如果對性能要求特別高或者查詢十分複雜,可以考慮使用原生 SQL 和 ORM 共用的方式 使用原生sql優點:
- 進行復雜的查詢時更加靈活 可以根據需要編寫特殊的sql語句
使用原生sql缺點:
- 需要對輸入進行嚴格的檢測 自己寫的sql語句,很多時候使用的是字符串拼接,可能會有sql注入的漏洞 不能使用django orm相關的一些特性
8. 列舉django orm 中所有的方法(QuerySet對象的所有方法)
QuerySet | 從數據庫中查詢出來的結果一般是一個集合,這個集合叫做 |
---|---|
filter | 過濾 |
exclude | 排除 |
annotate | 聚合 |
order_by | 排序 |
reverse | 反向排序 |
distinct | 去除查詢結果中重複的行 |
values | 迭代時返回字典而不是模型實例對象 |
values_list | 迭代時返回元組而不是字典 |
dates | 表示特定種類的所有可用日期 |
datetimes | 表示特定種類的所有可用日期 |
none | 不返回任何對象 |
all | 返回所有結果 |
select_related | 外鍵查詢 |
prefetch_related | 在單個批處理中自動檢索每個指定查找的相關對象 |
defer | 告訴django不要查詢某些字段 |
using | 多個數據庫時控制 QuerySet在哪個數據庫上求值 |
9. Django本身提供了runserver,爲什麼不能用來部署?( 與uWSGI的區別)
-
runserver 方法是調試 Django 時經常用到的運行方式,它使用Django自帶的 WSGI Server 運行,主要在測試和開發中使用,並且 runserver 開啓的方式也是單進程 。
-
uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http 等協議。注意uwsgi是一種通信協議,而uWSGI是實現uwsgi協議和WSGI協議的 Web 服務器。
uWSGI具有超快的性能、低內存佔用和多app管理等優點,並且搭配着Nginx就是一個生產環境了,能夠將用戶訪問請求與應用 app 隔離開,實現真正的部署 。相比來講,支持的併發量更高,方便管理多進程,發揮多核的優勢,提升性能。
10. 談談你對restful規範的認識?
-
restful 提倡面向資源編程,在url接口中儘量要使用名詞,不要使用動詞
-
在url接口中推薦使用Https協議,讓網絡接口更加安全 https://baidum/v1/mycss?page=3 (Https是Http的安全版,即HTTP下加入SSL層,HTTPS的安全 基礎是SSL, 因此加密的詳細內容就需要SSL(安全套接層協議))
-
在url中可以體現版本號 https://v1.bootcss.com/mycss
不同的版本可以有不同的接口,使其更加簡潔,清晰 -
url中可以體現是否是API接口 https://baidum/api/mycss
-
url中可以添加條件去篩選匹配 https://baidum/v1/mycss?page=3
-
可以根據Http不同的method,進行不同的資源操作 (5種方法:GET / POST / PUT / DELETE / PATCH)
-
響應式應該設置狀態碼
-
有返回值,而且格式爲統一的json格式
-
返回錯誤信息
-
返回結果中要提供幫助鏈接,即API最好做到接口文檔
三 數據庫
1. 談談mysql集羣主從庫讀寫分離的原理
高負載高併發環境下,數據業務層、數據訪問層,如果還是傳統的數據結構,或者只是單單靠一臺服務器負載,如此多的數據庫連接操作,數據庫必然會崩潰,數據庫如果宕機的話,後果更是不堪設想。
這時候,我們會考慮如何減少數據庫的連接,一方面採用優秀的代碼框架,進行代碼的優化,採用優秀的數據緩存技術如:redis,如果資金豐厚的話,必然會想到架設mysql服務集羣,來分擔主數據庫的壓力。
總結一下利用MySQL主從配置,實現讀寫分離,減輕數據庫壓力。
mysql主從同步的原理很簡單,
-
從庫生成兩個線程,一個I/O線程,一個SQL線程;
-
i/o線程去請求主庫 的binlog(二進制日誌),並將得到的binlog日誌寫到relay log(中繼日誌) 文件中;
-
主庫會生成一個 log dump 線程,用來給從庫 i/o線程傳binlog;
-
SQL 線程,會讀取relay log文件中的日誌,並解析成具體操作,來實現主從的操作一致,而最終數據一致。
2.說說mysql binlog日誌的存儲格式
binlog是二進制日誌文件,用於記錄mysql的數據更新或者潛在更新(比如DELETE語句執行刪除而實際並沒有符合條件的數據)
3. 怎樣解決主從同步延遲問題?
- 架構方面
- 業務的持久化層的實現採用分庫架構,mysql服務可平行擴展,分散壓力。
- 單個庫讀寫分離,一主多從,主寫從讀,分散壓力。這樣從庫壓力比主庫高,保護主庫。
- 服務的基礎架構在業務和mysql之間加入memcache或者Redis的cache層。降低mysql的讀壓力。
- 不同業務的mysql物理上放在不同機器,分散壓力。
- 使用比主庫更好的硬件設備作爲slave
總結,mysql壓力小,延遲自然會變小。
- 硬件方面
- 採用好服務器,比如:4u比2u性能明顯好,2u比1u性能明顯好。
- 存儲用ssd或者盤陣或者san,提升隨機寫的性能。
- 主從間保證處在同一個交換機下面,並且是萬兆環境。
總結,硬件強勁,延遲自然會變小。一句話,縮小延遲的解決方案就是花錢和花時間。
- mysql主從同步加速
- sync_binlog在slave端設置爲0
- –logs-slave-updates 從服務器從主服務器接收到的更新不記入它的二進制日誌。
- 直接禁用slave端的binlog
- slave端,如果使用的存儲引擎是innodb,innodb_flush_log_at_trx_commit = 2
4. 說說悲觀鎖和樂觀鎖
- 樂觀鎖
樂觀鎖不是數據庫自帶的,需要我們自己去實現。
樂觀鎖是指操作數據庫時(更新操作),想法很樂觀,認爲這次的操作不會導致衝突,在操作數據時,並不進行任何其他的特殊處理(也就是不加鎖),而在進行更新後,再去判斷是否有衝突了。
- 悲觀鎖
每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖
5. 觸發器如何使用以及使用場景
觸發程序是與表有關的命名數據庫對象,當該表出現特定事件時,將激活該對象
監聽:記錄的增加、修改、刪除。
6. 談談事務
事務是指邏輯上的一組操作,組成這組操作的各個單元,要不全成功要不全失敗
7. 說收事務的特性
-
原子性(Atomicity)
事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
-
一致性(Consistency)
事務前後數據的完整性必須保持一致。
- 事務開始和結束時,外部數據一致
- 在整個事務過程中,操作是連續的
-
隔離性(Isolation)
多個用戶併發訪問數據庫時,一個用戶的事務不能被其它用戶的事物所幹擾,多個併發事務之間的數據要相互隔離。
-
持久性(Durability)
一個事務一旦被提交,它對數據庫中的數據改變就是永久性的。
8. 事務的原理是什麼
事務是指邏輯上的一組操作,組成這組操作的各個單元,要不全成功要不全失敗。
-
支持連續SQL的集體成功或集體撤銷。
-
事務是數據庫在數據晚自習方面的一個功能。
-
需要利用 InnoDB 或 BDB 存儲引擎,對自動提交的特性支持完成。
-
InnoDB被稱爲事務安全型引擎。
9. 併發事務帶來的幾個問題:更新丟失,髒讀,不可重複讀,幻讀分別解釋問題成因以及怎麼解決?
事務隔離級別:
未提交讀(Read uncommitted),已提交讀(Read committed),可重複讀(Repeatable read),可序列化(Serializable)
-
Read Uncommitted(讀取未提交內容)
在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。
本隔離級別很少用於實際應用,因爲它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之爲髒讀(Dirty Read)。 -
Read Committed(讀取提交內容)
這是大多數 數據庫系統的默認隔離級別(但不是MySQL默認的)。
它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別 也支持所謂的不可重複讀(Nonrepeatable Read),因爲同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。
-
Repeatable Read(可重讀)
這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在併發讀取數據時,會看到同樣的數據行。
不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。
簡單的說,幻讀指當用戶讀取某一範圍的數據行時,另一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的數據行時,會發現有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。 -
Serializable(可串行化)
這是最高的隔離級別,它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
這四種隔離級別採取不同的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。例如:
髒讀(Drity Read):
某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由於某些原因,
前一個RollBack了操作,則後一個事務所讀取的數據就會是不正確的。
不可重複讀(Non-repeatable read):
在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的數據。
幻讀(Phantom Read):
在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,
先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。
1、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據
2、不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,
導致事務A多次讀取同一數據時,結果 不一致。
3、幻讀:系統管理員A將數據庫中所有學生的成績從具體分數改爲A B C D E等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,
當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。
'小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表'
低級別的隔離級一般支持更高的併發處理,並擁有更低的系統開銷。
10. 談談鎖表
表鎖定只用於防止其它客戶端進行不正當地讀取和寫入
MyISAM 支持表鎖,InnoDB 支持行鎖
-
鎖定 LOCK TABLES tbl_name [AS alias]
-
解鎖 UNLOCK TABLES
11. 說說聯合索引&最左原則
- 聯合索引的好處:
覆蓋索引,這一點是最重要的,重所周知非主鍵索引會先查到主鍵索引的值再從主鍵索引上拿到想要的值,這樣多一次查詢索引下推。但是覆蓋索引可以直接在非主鍵索引上拿到相應的值,減少一次查詢。
在一張大表中如果有 (a,b,c)聯合索引就等於同時加上了 (a) (ab) (abc) 三個索引減少了存儲上的一部分的開銷和操作開銷
梯度漏斗,比如 select *from t where a = 1 and b = 2 and c = 3; 就等於在滿足 a = 1 的一部分數據中過濾掉b = 2 的 再從 a = 1 and b = 2 過濾掉 c = 3 的,越多查詢越高效。
- 最左原則:最左優先,在檢索數據時從聯合索引的最左邊開始匹配,類似於給(a,b,c)這三個字段加上
聯合索引就等於同時加上了 (a) (ab) (abc) 這三種組合的查詢優化
12. 說說索引底層實現,爲什麼它能加快查詢效率
- 底層數據結構:b+tree
BTREE 每個節點都是一個二元數組: [key, data],所有節點都可以存儲數據。key爲索引key,data爲除key之外的數據。
查找算法:首先從根節點進行折半查找,如果找到則返回對應節點的data,否則對相應區間的指針指向的節點遞歸進行查找,直到找到節點或未找到節點返回空指針
B+Tree有以下不同點:
- 非葉子節點不存儲data,只存儲索引key;
- 只有葉子節點才存儲data,而Mysql中B+Tree:
- 在經典B+Tree的基礎上進行了優化,增加了順序訪問指針。
- 在B+Tree的每個葉子節點增加一個指向相鄰葉子節點的指針,就形成了帶有順序訪問指針的B+Tree。這樣就提高了區間訪問性能
總結:B+Tree 在 B-Tree 的基礎上有兩點變化:
- 數據是存在葉子節點中的;
- 數據節點之間是有指針指向的。
13. 談談梯度漏斗
14. 說說連接池的用法以及使用場景
連接池基本的思想是在系統初始化的時候,將數據庫連接作爲對象存儲在內存中,
當用戶需要訪問數據庫時,並非建立一個新的連接,而是從連接池中取出一個已建立的空閒連接對象。
使用完畢後,用戶也並非將連接關閉,而是將連接放回連接池中,以供下一個請求訪問使用。
而連接的建立、斷開都由連接池自身來管理。
同時,還可以通過設置連接池的參數來控制連接池中的初始連接數、連接的上下限數以及每個連接的最大使用次數、最大空閒時間等等。
也可以通過其自身的管理機制來監視數據庫連接的數量、使用情況等。
有點類似單例模式的概念
15. mysql 如何存儲ip
inet_aton()算法
16. mysql 如何優化
設計數據庫時:
- 數據庫表
- 字段的設計
- 存儲引擎 利用好MySQL自身提供的功能,如索引等
- 橫向擴展:MySQL集羣、負載均衡、讀寫分離 SQL語句的優化(收效甚微)
存儲引擎如何選擇?
早期問題:如何選擇MyISAM和Innodb? 現在不存在這個問題了,Innodb不斷完善,從各個方面趕超MyISAM,也是MySQL默認使用的。
存儲引擎Storage engine:MySQL中的數據、索引以及其他對象是如何存儲的,是一套文件系統的實現。
功能差異 show engines EngineSupportCommentInnoDBDEFAULTSupports transactions, row-level locking, and foreign keysMyISAMYESMyISAM storage engine
存儲差異 MyISAMInnodb文件格式數據和索引是分別存儲的,數據.MYD,索引.MYI數據和索引是集中存儲的,
.ibd文件能否移動能,一張表就對應.frm、MYD、MYI3個文件否,
因爲關聯的還有data下的其它文件記錄存儲順序按記錄插入順序保存按主鍵大小有序插入空間碎片(刪除記錄並flush table 表名之後,表文件大小不變)產生。
定時整理:使用命令optimize table 表名實現不產生事務不支持支持外鍵不支持支持鎖支持(鎖是避免資源爭用的一個機制,MySQL鎖對用戶幾乎是透明的)
表級鎖定行級鎖定、表級鎖定,鎖定力度小併發能力高
鎖擴展
表級鎖(table-level lock):lock tables ,... read/write,unlock tables ,...。其中read是共享鎖,一旦鎖定任何客戶端都不可讀;
write是獨佔/寫鎖,只有加鎖的客戶端可讀可寫,其他客戶端既不可讀也不可寫。
鎖定的是一張表或幾張表。
行級鎖(row-level lock):鎖定的是一行或幾行記錄。
共享鎖:select fromwhere <條件> LOCK 鬼故事8 IN SHARE MODE;,
對查詢的記錄增加共享鎖;select from where <條件> FOR UPDATE;,
對查詢的記錄增加排他鎖。
這裏值得注意的是:innodb的行鎖,其實是一個子範圍鎖,依據條件鎖定部分範圍,而不是就映射到具體的行上,因此還有一個學名:間隙鎖。
比如select * from stu where id < 20 LOCK IN SHARE MODE會鎖定id在20左右以下的範圍,你可能無法插入id爲18或22的一條新紀錄。
選擇依據 如果沒有特別的需求,使用默認的Innodb即可。
MyISAM:以讀寫插入爲主的應用程序,比如博客系統、新聞門戶網站。
Innodb:更新(刪除)操作頻率也高,或者要保證數據的完整性;併發量高,支持事務和外鍵保證數據完整性。比如OA自動化辦公系統。
17. 說說索引的缺點
- 創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加
- 需佔用額外的物理空間
- 當對錶中數據進行增加、刪除和修改的時候,
索引也要動態的維護,降低了數據的維護速度
18. 談談執行計劃explain
我們可以通過explain selelct來分析SQL語句執行前的執行計劃: 執行計劃是:當執行SQL語句時,首先會分析、優化,形成執行計劃,在按照執行計劃執行。
19. 說說索引使用場景(重點)
where
order by 當我們使用order by將查詢結果按照某個字段排序時,如果該字段沒有建立索引,
那麼執行計劃會將查詢出的所有數據使用外部排序(將數據從硬盤分批讀取到內存使用內部排序,最後合併排序結果),
這個操作是很影響性能的,因爲需要將查詢涉及到的所有數據從磁盤中讀到內存(如果單條數據過大或者數據量過多都會降低效率),更無論讀到內存之後的排序了。
但是如果我們對該字段建立索引alter table 表名 add index(字段名),那麼由於索引本身是有序的,
因此直接按照索引的順序和映射關係逐條取出數據即可。
而且如果分頁的,那麼只用取出索引表某個範圍內的索引對應的數據,
而不用像上述那取出所有數據進行排序再返回某個範圍內的數據。(從磁盤取數據是最影響性能的)
join
對join語句匹配關係(on)涉及的字段建立索引能夠提高效率
like查詢,不能以通配符開頭 比如搜索標題包含mysql的文章:
select * from article where title like '%mysql%'; 這種SQL的執行計劃用不了索引(like語句匹配表達式以通配符開頭),
因此只能做全表掃描,效率極低,在實際工程中幾乎不被採用。而一般會使用第三方提供的支持中文的全文索引來做。
但是 關鍵字查詢 熱搜提醒功能還是可以做的,比如鍵入mysql之後提醒mysql 教程、mysql 下載、mysql 安裝步驟等。用到的語句是:
select * from article where title like 'mysql%'; 這種like是可以利用索引的(當然前提是title字段建立過索引)。
20. 什麼是 MongoDB ?
MongoDB 是一個介於關係數據庫和非關係數據庫之間的開源產品,是最接近於關係型數據庫的 NoSQL 數據庫。
它在輕量級JSON 交換基礎之上進行了擴展,即稱爲 BSON 的方式來描述其無結構化的數據類型。
儘管如此它同樣可以存儲較爲複雜的數據類型。它和Redis有異曲同工之妙。雖然兩者均爲 NoSQL ,
但是 MongoDB 相對於 Redis 而言,MongoDB 更像是傳統的數據庫。
早些年我們是先有了 Relation Database (關係型數據庫),然後出現了很多很複雜的query ,裏面用到了很多嵌套,很多 join 操作。
所以在設計數據庫的時候,我們也考慮到了如何應用他們的關係,使得寫 query 可以使 database 效率達到最高。
後來人們發現,不是每個系統,都需要如此複雜的關係型數據庫。有些簡單的網站,比如博客,比如社交網站,完全可以斬斷數據庫之間的一切關係。
這樣做帶來的好處是,設計數據庫變得更加簡單,寫 query 也變得更加簡單。然後,query 消耗的時間可能也會變少。
因爲 query 簡單了,少了許多消耗資源的 join 操作,速度自然會上去。
正如所說的, query 簡單了,很有以前 MySQL 可以找到的東西,現在關係沒了,通過 Mongo 找不到了。
我們只能將幾組數據都抓到本地,然後在本地做 join ,所以在這點上可能會消耗很多資源。
這裏我們可以發現。如何選擇數據庫,完全取決於你所需要處理的數據的模型,即 Data Model 。
如果它們之間,關係錯綜複雜,千絲萬縷,這個時候 MySQL 一定是首選。如果他們的關係並不是那麼密切,那麼, NoSQL 將會是利器。
MongoDB 和 Redis 一樣均爲 key-value 存儲系統,它具有以下特點:
- 面向集合存儲,易存儲對象類型的數據。
- 模式自由。
- 支持動態查詢。
- 支持完全索引,
- 包含內部對象。
- 支持查詢。
- 支持複製和故障恢復。
- 使用高效的二進制數據存儲,包括大型對象(如視頻等)。
- 自動處理碎片,以支持雲計算層次的擴展性 支持
'Python , PHP , Ruby , Java , C , C# , Javascript ,Perl 及 C++ 語言的驅動程序,'
'社區中也提供了對 Erlang 及 .NET 等平臺的驅動程序。 文件存儲格式爲 BSON (一種 JSON 的擴展)。 可通過網絡訪問。'
21. MongoDB 與 MySQL 性能比較?
像 MySQL 一樣, MongoDB 提供了豐富的遠遠超出了簡單的鍵值存儲中提供的功能和功能。
MongoDB 具有查詢語言,功能強大的輔助索引(包括文本搜索和地理空間),數據分析功能強大的聚合框架等。
相比使用關係數據庫而言,使用MongoDB ,您還可以使用這些功能,跨越更多樣化的數據類型和數據規模。
MySQLMongoDB豐富的數據模型否是動態 Schema否是數據類型是是數據本地化否是字段更新是是易於編程否是複雜事務是否審計是是自動分片 否是
MySQL 中的許多概念在 MongoDB 中具有相近的類比。本表概述了每個系統中的一些常見概念。
MySQLMongoDB表集合行文檔列字段joins嵌入文檔或者鏈接
22. MongoDB應用範圍和限制
MongoDB 的主要目標是在 key-value (鍵/值)存儲方式(提供了高性能和高度伸縮性)以及傳統的 RDBMS 系統(豐富的功能)架起一座橋樑,集兩者的優勢於一身。
MongoDB 適用範圍如下:
網站數據:
Mongo 非常適合實時的插入,更新與查詢,並具備網站實時數據存儲所需的複製及高度伸縮性。
緩存:
由於性能很高, Mongo 也適合作爲信息基礎設施的緩存層。在系統重啓之後,由 Mongo 搭建的持久化緩存層可以避免下層的數據源過載。
大尺寸,低價值的數據:使用傳統的關係型數據庫存儲一些數據時可能會比較昂貴,
在此之前,很多時候程序員往往會選擇傳統的文件進行存儲。
高伸縮性的場景:
Mongo 非常適合由數十或數百臺服務器組成的數據庫。
Mongo 的路線圖中已經包含對 MapReduce 引擎的內置支持。
用於對象及 JSON 數據的存儲:
Mongo 的 BSON 數據格式非常適合文檔化格式的存儲及查詢。
MongoDB 當然也會有以下場景的限制:
高度事物性的系統:
例如銀行或會計系統。傳統的關係型數據庫目前還是更適用於需要大量原子性複雜事務的應用程序。 傳統的商業智能應用:
針對特定問題的 BI 數據庫會對產生高度優化的查詢方式。對於此類應用,數據倉庫可能是更合適的選擇。 需要 SQL 的問題。
23. 簡述Reids的特點
Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,
整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據flush到硬盤上進行保存。
因爲是純內存操作,Redis的性能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value DB。
Redis的出色之處不僅僅是性能,Redis最大的魅力是支持保存多種數據結構,此外單個value的最大限制是1GB,
不像 memcached只能保存1MB的數據,因此Redis可以用來實現很多有用的功能。
比方說用他的List來做FIFO雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的Set可以做高性能的tag系統等等。
另外Redis也可以對存入的Key-Value設置expire時間,因此也可以被當作一 個功能加強版的memcached來用。
Redis的主要缺點是數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis適合的場景主要侷限在較小數據量的高性能操作和運算上。
24. 使用redis有哪些好處?
- 速度快,因爲數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間複雜度都是O(1)
- 支持豐富數據類型,支持string,list,set,sorted set,hash
- 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要麼全部執行,要麼全部不執行
- 豐富的特性:可用於緩存,消息,按key設置過期時間,過期後將會自動刪除
25. 爲什麼redis需要把所有數據放到內存中?
Redis爲了達到最快的讀寫速度將數據都讀到內存中,並通過異步的方式將數據寫入磁盤。
所以redis具有快速和數據持久化的特徵。
如果不將數據放在內存中,磁盤I/O速度爲嚴重影響redis的性能。
在內存越來越便宜的今天,redis將會越來越受歡迎。
如果設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值。
26. 單線程的redis爲什麼這麼-快
回答:主要是以下三點
- 純內存操作
- 單線程操作,避免了頻繁的上下文切換
- 採用了非阻塞I/O多路複用機制
27. redis持久化的幾種方式,至少寫出五種
-
快照(snapshots)
缺省情況情況下,Redis把數據快照存放在磁盤上的二進制文件中,文件名爲dump.rdb。你可以配置Redis的持久化策略,例如數據集中每N秒鐘有超過M次更新,就將數據寫入磁盤;或者你可以手工調用命令SAVE或BGSAVE。
-
工作原理
Redis forks.
子進程開始將數據寫到臨時RDB文件中。
當子進程完成寫RDB文件,用新文件替換老文件。
這種方式可以使Redis使用copy-on-write技術。
-
AOF
快照模式並不十分健壯,當系統停止,或者無意中Redis被kill掉,最後寫入Redis的數據就會丟失。
這對某些應用也許不是大問題,但對於要求高可靠性的應用來說,Redis就不是一個合適的選擇。Append-only文件模式是另一種選擇。你可以在配置文件中打開AOF模式 -
虛擬內存方式
當你的key很小而value很大時,使用VM的效果會比較好.因爲這樣節約的內存比較大.
當你的key不小時,可以考慮使用一些非常方法將很大的key變成很大的value,比如你可以考慮將key,value組合成一個新的value.
vm-max-threads這個參數,可以設置訪問swap文件的線程數,設置最好不要超過機器的核數,如果設置爲0,那麼所有對swap文件的操作都是串行的.可能會造成比較長時間的延遲,但是對數據完整性有很好的保證.
自己測試的時候發現用虛擬內存性能也不錯。如果數據量很大,可以考慮分佈式或者其他數據庫。
28. 使用過Redis分佈式鎖麼,怎麼用?使用場景是什麼?
它是什麼回事?先拿setnx來爭搶鎖,搶到之後,再用expire給鎖加一個過期時間防止鎖忘記了釋放。
這時候對方會告訴你說你回答得不錯,
然後接着問如果在setnx之後執行expire之前進程意外crash或者要重啓維護了,那會怎麼樣?
這時候你要給予驚訝的反饋:唉,是喔,這個鎖就永遠得不到釋放了。
緊接着你需要抓一抓自己得腦袋,故作思考片刻,好像接下來的結果是你主動思考出來的,
然後回答:我記得set指令有非常複雜的參數,這個應該是可以同時把setnx和expire合成一條指令來用的!對方這時會顯露笑容,心裏開始默唸:摁,這小子還不錯。
29. 假如Redis裏面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,如果將它們全部找出來?
使用keys指令可以掃出指定模式的key列表。
對方接着追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?
這個時候你要回答redis關鍵的一個特性:
-
redis的單線程的。
-
keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。
-
這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
30. 使用過Redis做異步隊列麼,你是怎麼用的?
答:一般使用list結構作爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。
如果對方追問可不可以不用sleep呢?
答:list還有個指令叫blpop,在沒有消息的時候,它會阻塞住直到消息到來。
如果對方追問能不能生產一次消費多次呢?
答:使用pub/sub主題訂閱者模式,可以實現1:N的消息隊列。
如果對方追問pub/sub有什麼缺點?
答:在消費者下線的情況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。
如果對方追問redis如何實現延時隊列?
我估計現在你很想把面試官一棒打死如果你手上有一根棒球棍的話,怎麼問的這麼詳細。
答:使用sortedset,拿時間戳作爲score,消息內容作爲key調用zadd來生產消息,消費者用zrangebyscore指令獲取N秒之前的數據輪詢進行處理。
到這裏,面試官暗地裏已經對你豎起了大拇指。但是他不知道的是此刻你卻豎起了中指,在椅子背後。
如果有大量的key需要設置同一時間過期,一般需要注意什麼?
如果大量的key過期時間設置的過於集中,到過期的那個時間點,redis可能會出現短暫的卡頓現象。一般需要在時間上加一個隨機值,使得過期時間分散一些。
31. Pipeline有什麼好處,爲什麼要用pipeline?
可以將多次IO往返的時間縮減爲一次,前提是pipeline執行的指令之間沒有因果相關性。
使用redis-benchmark進行壓測的時候可以發現影響redis的QPS峯值的一個重要因素是pipeline批次指令的數目。
32. Redis的同步機制瞭解麼?
Redis可以使用主從同步,從從同步。
- 第一次同步時,主節點做一次bgsave,並同時將後續修改操作記錄到內存buffer,待完成後將rdb文件全量同步到複製節點,複製節點接受完成後將rdb鏡像加載到內存。
- 加載完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程。
33. 是否使用過Redis集羣,集羣的原理是什麼?
-
Redis Sentinal着眼於高可用,在master宕機時會自動將slave提升爲master,繼續提供服務。
-
Redis Cluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。
34. 什麼是Redis的併發競爭問題,怎麼解決,至少給出五種方案
Redis的併發競爭問題,主要是發生在併發寫競爭。
考慮到redis沒有像db中的sql語句,update val = val + 10 where ...,無法使用這種方式進行對數據的更新。
假如有某個key = "price", value值爲10,現在想把value值進行+10操作。
正常邏輯下,就是先把數據key爲price的值讀回來,加上10,再把值給設置回去。
如果只有一個連接的情況下,這種方式沒有問題,可以工作得很好,
但如果有兩個連接時,兩個連接同時想對還price進行+10操作,就可能會出現問題了。
例如:兩個連接同時對price進行寫操作,同時加10,最終結果我們知道,應該爲30纔是正確。
考慮到一種情況:
T1時刻,連接1將price讀出,目標設置的數據爲10+10 = 20。
T2時刻,連接2也將數據讀出,也是爲10,目標設置爲20。
T3時刻,連接1將price設置爲20。
T4時刻,連接2也將price設置爲20,則最終結果是一個錯誤值20。
解決方案
使用樂觀鎖的方式進行解決(成本較低,非阻塞,性能較高)
如何用樂觀鎖方式進行解決?
本質上是假設不會進行衝突,使用redis的命令watch進行構造條件。
35. redis和memcached的區別(總結)
- Redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過memcache還可用於緩存其他東西,例如圖片、視頻等等;
- Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲;
- 虛擬內存–Redis當物理內存用完時,可以將一些很久沒用到的value 交換到磁盤;
- 過期策略–memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire 設定,例如expire name 10;
- 分佈式–設定memcache集羣,利用magent做一主多從;redis可以做一主多從。都可以一主一從;
- 存儲數據安全–memcache掛掉後,數據沒了;redis可以定期保存到磁盤(持久化);
- 災難恢復–memcache掛掉後,數據不可恢復; redis數據丟失後可以通過aof恢復;
- Redis支持數據的備份,即master-slave模式的數據備份;
四Vue.js
1. 前端爲什麼要用vue.js 爲什麼要用工程化?
相對 HTML4 , HTML5 最大的亮點是它爲移動設備提供了一些非常有用的功能,使得 HTML5 具備了開發App的能力,
HTML5開發App 最大的好處就是跨平臺、快速迭代和上線,節省人力成本和提高效率,
因此很多企業開始對傳統的App進行改造,逐漸用H5代替Native,
到2015年的時候,市面上大多數App 或多或少嵌入都了H5 的頁面。
2. 談談Vue.js 和 jquery的區別?
jQuery是使用選擇器($)選取DOM對象,對其進行賦值、取值、事件綁定等操作,
其實和原生的HTML的區別只在於可以更方便的選取和操作DOM對象,
而數據和界面是在一起的。比如需要獲取label標籤的內容:
$("lable").val();,它還是依賴DOM元素的值。
Vue則是通過Vue對象將數據和View完全分離開來了。
對數據進行操作不再需要引用相應的DOM對象,可以說數據和View是分離的,
他們通過Vue對象這個vm實現相互的綁定。這就是傳說中的MVVM。
3. 談談混合式開發?
近幾年,混合模式移動應用的概念甚囂塵上,受到了一些中小型企業的青睞,
究其原因,混合模式開發可以比傳統移動開發節約大量的開發成本和人力成本。
Hybrid App(混合模式移動應用)是指介於web-app、native-app這兩者之間的app,
兼具“Native App良好用戶交互體驗的優勢”和“Web App跨平臺開發的優勢”。
說白了,如果走傳統移動開發路線,公司業務覆蓋多端,那麼每個平臺勢必要請一個專屬開發人員,
安卓要請一個前端開發,ios同理,那麼人力成本則進行了翻倍,
同時,如果多端使用不同的代碼,當有功能上的修改或者維護時,成本也是不可想象的。
試想如果開發者編寫一套代碼,可編譯到iOS、Android、H5、小程序等多個平臺,這絕對是省時省力的良好方案。
4. mvvm 和 mvc 區別?
mvc 和 mvvm 其實區別並不大。都是一種設計思想。
主要就是
-
mvc 中 Controller 演變成 mvvm 中的 viewModel。
-
mvvm 主要解決了 mvc 中大量的 DOM 操作使頁面渲染性能降低,加載速度變慢,影響用戶體驗。
當 Model 頻繁發生變化,開發者需要主動更新到 View 。
5. vue 的優點是什麼?
-
低耦合
視圖(View)可以獨立於 Model 變化和修改,一個 ViewModel 可以綁定到不同的"View"上,
當 View 變化的時候 Model 可以不變,當 Model 變化的時候 View 也可以不變。 -
可重用性
你可以把一些視圖邏輯放在一個 ViewModel 裏面,讓很多 view 重用這段視圖邏輯。 獨立開發。開發人員可以專注於業務邏輯和數據的開發(ViewModel),設計人員可以專注於頁面設計,使用 Expression Blend 可以很容易設計界面並生成 xml 代碼。 -
可測試。
界面素來是比較難於測試的,而現在測試可以針對 ViewModel 來寫。
6. vue生命週期的理解?
總共分爲 8 個階段
-
創建前/後:
在 beforeCreate 階段,vue 實例的掛載元素 el 還沒有。 -
載入前/後:
在 beforeMount 階段,vue 實例的$el 和 data 都初始化了,但還是掛載之前爲虛擬的 dom 節點,data.message 還未替換。在 mounted 階段,vue 實例掛載完成,data.message 成功渲染。 -
更新前/後:
當 data 變化時,會觸發 beforeUpdate 和 updated 方法。 銷燬前/後:在執行 destroy 方法後,對 data 的改變不會再觸發周期函數,說明此時 vue 實例已經解除了事件監聽以及和 dom 的綁定,但是 dom 結構依然存在 -
銷燬前/後
7. 組件之間如何傳值?
8. 路由之間如何跳轉?
-
聲明式(標籤跳轉)router-link
-
編程式( js 跳轉) router.push(‘index’)
9. 懶加載(按需加載路由)的原理是什麼?
webpack 中提供了 require.ensure()來實現按需加載。
以前引入路由是通過 import 這樣的方式引入,改爲 const 定義的方式進行引入。
-
不進行頁面按需加載引入方式: import home from ‘…/…/common/home.vue’
-
進行頁面按需加載的引入方式: const home = r => require.ensure( [], () => r (require(’…/…/common/home.vue’)))
10. vuex 是什麼?怎麼使用?哪種功能場景使用它?
vue 框架中狀態管理。在 main.js 引入 store,注入。
新建了一個目錄 store,…… export 。
- 場景有:
單頁應用中,組件之間的狀態。音樂播放、登錄狀態、加入購物車
11. vue 的雙向綁定的原理是什麼(常考)
vue.js 是採用數據劫持結合發佈者-訂閱者模式的方式,通過 Object.defineProperty()來劫持各個屬性的 setter,getter,在數據變動時發佈消息給訂閱者,觸發相應的監聽回調。
具體步驟:
-
第一步:
需要 observe 的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter 和 getter 這樣的話,給這個對象的某個值賦值,就會觸發 setter,那麼就能監聽到了數據變化 -
第二步:
compile 解析模板指令,將模板中的變量替換成數據,然後初始化渲染頁面視圖,並將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖 -
第三步:
Watcher 訂閱者是 Observer 和 Compile 之間通信的橋樑,主要做的事情是:
在自身實例化時往屬性訂閱器(dep)裏面添加自己 自身必須有一個 update()方法 待屬性變動 dep.notice()通知時,能調用自身的 update() 方法,並觸發 Compile 中綁定的回調,則功成身退。 -
第四步:
MVVM 作爲數據綁定的入口,整合 Observer、Compile 和 Watcher 三者,通過 Observer 來監聽自己的 model 數據變化,通過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的通信橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據 model 變更的雙向綁定效果。