IKEA 直接賣「家」了,來看看這既環保又有型的 Tiny Home 小屋拖車_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

演而優則… 誒不是。總之,IKEA 居家產品賣著賣著,現在竟然也做起了「移動的家」露營拖車。重點是看起來還是非常地有瑞典風而且細節也是滿滿呢!繼續閱讀 IKEA 直接賣「家」了,來看看這既環保又有型的 Tiny Home 小屋拖車 報導內文。

▲圖片來源:IKEA

IKEA 直接賣「家」了,來看看這既環保又有型的 Tiny Home 小屋拖車

這個方正如貨櫃屋但又以很舒服外在色調環繞的 Tiny Home 小屋拖車。是 IKEA 與 Vox Creative 合作打造的微屋 / 小房子 / Tiny Home 計畫。希望透過這個可永續、可負擔、低浪費且有型,小小僅約 5 坪多(187 平方英尺)的空間,證明任何人都可以無拘無束地實現更永續的生活。

▲圖片來源:IKEA

先前我們也有介紹過類似概念的「家」– 是個美到讓人會想要反問,這房子怎麼會有駕駛座的校車改造計畫。這次 IKEA 的 Tiny Home Project,則是以露營拖車的形式實現的小屋計畫,並且也確認成真,將可用美金 4.75 萬也就是約 135 萬台幣擁有。

雖說對於 IKEA 而言,小屋應該主要還是可以展示他們的居家產品的用途為主(還有個網站可以做虛擬「看房」)。但這由 Escape Vista Boho XL 拖車屋為基礎所訂製而成的 Tiny Home,還具備有包括太陽能板、可堆肥廁所系統等功能細節,並可依需提供包括熱水的功能(這部分的能源則由車輛提供)。

▲圖片來源:IKEA

而根據 NBC 的報導,這個以電力運作的小屋是以零碳排與零污染為概念所建成,包括內在建材與家具也都有考量到永續環保或回收材質,但也同時十分注重如桌面採可折疊收納的功能性與美觀 — 這就是 IKEA 展現實力的地方吧。

雖說可能得要仰賴其他能源的狀態下,很顯然要正常在這個小屋生活,基本上很難達到真正的零污染。但至少整個建造的低浪費與環保方向還是很值得鼓勵,也讓人看到了環保不見得就得要犧牲美觀與設計的可能。

本篇圖片 / 引用來源

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

延伸閱讀:

支援 AirPods Max 磁吸休眠的三方皮革收納盒來了,連充電器也能完整裝入

電動車時代來臨?《消費者報告》調查逾 7 成消費者考慮購入電動車

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

居然不知道這些優惠巨大的進口車?教授都替你急了_包裝設計

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

你可能會說,差不多的動力系統,我為什麼不買更加便宜的卡羅拉或者雷凌雙擎。然而事實上,雷克薩斯始終是雷克薩斯,在做工、用料方面,雷克薩斯還是比豐田領先,而且大雷還有免費保養政策呢。寶馬1系指導價:25。60-46。

在國內汽車市場還不是很發達的時候,國民的汽車都主要靠進口,然而時至今日,自主和合資品牌的車汽車都在逐漸壯大,看進口車的人也就逐漸少了。實際上進口車在机械品質和做工方面相對合資車的優勢並不大,但由於車企自身的計劃等各種原因,一些不錯的車子都只有進口沒有合資。今天提到的這幾款便是這樣的車型,重點是,它們的優惠還挺大。

沃爾沃V40

指導價:22.39-27.99萬

優惠幅度:2.5-3萬

如果讓叫獸總結一下V40的外觀設計,那叫獸只能說它真的是很“沃爾沃”。來自北歐的這個汽車品牌,雖已安全為本,但設計上有十分濃厚的自身特色。動感又不失高雅的車身線條,傾斜穿過車標的鍍鉻飾條,以及車尾的黑色后風擋邊框和“L”字形尾燈。都帶有濃濃的沃爾沃味道在裡頭。

V40的內飾依舊是熟悉的沃爾沃特色,面積不大的中控屏以及一大串類似於電話按鍵的中控按鍵,過複雜的按鍵實際上也不便於操作,然而沃爾沃依然在堅持。除此以外,V40也延續沃爾沃的傳統,有豐富的安全配置,通過中控屏可以一一進行查看和設置。

沃爾沃的座椅一直都是比較出色的,V40上的也一樣,十分厚實的填充、緊緻的包裹感、寬大的承托以及柔軟舒適的面料,座椅的舒適性極佳。空間方面,身高179cm的體驗者在後排能取得三指的腿部空間,至於頭頂就幾乎頂到車頂了,空間比較局促。

V40提供1.5T和2.0T兩種動力,分別提供最大152pS和190pS的馬力,均搭載6AT的手自一體變速箱。拿小排量的1.5T來說,動力系統響應靈敏,實際動力表現並不強勢,但也不至於表現出疲乏。懸挂的質感比較緊緻,但處理顛簸時還是不夠從容,少了幾分高級感。

總體來說,認為該車的行駛質感在緊湊型車來說還算很不錯的了,更何況V40延續了沃爾沃優秀的做工品質和豐富的安全性能。

雷克薩斯-CT

指導價:26.90-34.80萬

優惠幅度:5萬左右

從CT的外觀就可以看出它並不是要做一輛普通的兩廂小車,而是要做有個性的兩廂車。車頭依舊有熟悉的紡錘體格柵,前臉聚攏的線條會讓車頭更加有衝擊力,雖然這輛車並不是主打性能。

來到內飾,豪華感固然和同品牌的老大哥RX那些車系沒法比,但優質的用料、精緻的做工和層次分明的布局,還是讓CT充滿了雷克薩斯的味道。至於配置方面就十分厚道,常見的主動和被動安全配置還有無鑰匙啟動等等均為全系標配,就算買最低配的車型也不用擔心配置不夠用。

CT的織物座椅使用比較高檔的絨布面料,乘坐的質感比普通的織物要好上不少,配合運動化設計的座椅,提供很好的側向支撐。至於乘坐空間方面,身高174cm的體驗者在後排有4指的腿部和頭部空間,表現十分局促。

動力方面,CT全系搭載1.8L自吸發動機和豐田混動車特有的E-CVT變速箱,最大馬力僅有99pS,數據方面貌似並不出色。然而豐田的混動系統總能讓動力系統提供最優化的輸出,所以CT的動力表現並不會十分疲弱,滿足日常駕駛是卓卓有餘的。

你可能會說,差不多的動力系統,

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

我為什麼不買更加便宜的卡羅拉或者雷凌雙擎?然而事實上,雷克薩斯始終是雷克薩斯,在做工、用料方面,雷克薩斯還是比豐田領先,而且大雷還有免費保養政策呢。

寶馬1系

指導價:25.60-46.90萬元

優惠幅度:7.5-8萬元

寶馬1系的車身造型十分緊湊和動感,前臉使用的絕對是寶馬的雙腎無疑的了,但新款1系的中網鍍鉻比舊款更加開揚、更具立體感了,而頭燈造型也變得更加有精神了。全LED光源的大燈,科技感十足啊。

1系的內飾依舊是典型的寶馬風格,環保式的中控台、懸浮式的6.5吋中控屏、以及整齊排列的物理按鍵。方向盤的面積不大,但十分粗壯,能增強駕駛者的駕駛慾望。而最新款的iDrive系統在15款車型已經搭載,支持藍牙音樂播放,說實話,這套iDrive真的不太好用。

座椅方面,現在全系車型都支持選裝真皮座椅了,不過即使是織物座椅,支撐性也是很好的,畢竟1系主打的駕駛樂趣嘛。至於後排空間,保持了一貫的狹窄,身高174cm的體驗者,只有一拳的腿部和四指的頭部空間。

動力方面,1系有四個不同版本的動力,從家用到性能都能夠滿足,全系標配8AT變速箱這點就比較優秀了。但即使是1.5T、136pS馬力的發動機也不容小覷,運動模式下依舊能給你不錯的推背感。至於底盤依舊的緊緻有韌性,十分靈敏,方向盤的虛位很小,雖然手感略沉,但轉向精準,買寶馬,買的就是這種駕駛樂趣啊。

靈活和精準,是給1系的關鍵詞,沒有超跑的狂飆、也沒有實用的空間,但當你在上下班通勤的路上感受了那份駕駛的樂趣以後,你就知道為什麼他們會選擇1系了。

奔馳A級

指導價:23.40-36.00萬元

優惠幅度:2萬左右

A級的造型就是在簡潔之中略帶動感,車身的線條還是偏向圓潤。前臉碩大的三叉星車標讓人一眼就看出了他的身份,而兩個大燈上自帶的日行燈也十分有科技感。而側面就能看到有上揚式的側麵線條,讓A級的外觀更加年輕化了。

內飾的豪華感雖然不強,但是在做工細緻,且加入了不少的運動話的元素來襯托它的定位。認為唯一的敗筆是懸浮式的中控屏,邊框的面積太大了,讓這个中控屏看起來一點都不高級。

皮革與織物混合的座椅面料,提供更好的防滑之餘又有不錯的質感。座椅已經不是傳統的奔馳座椅了,硬朗、包裹性強,所有的一切都是為了運動而準備。後排的空間是夠用的,身高175cm的人都能有一拳左右的腿部空間,只是後排又硬又短的座椅舒適性着實差。

動力方面,那A200來說,其動力系統其實和B200一樣,高功率的1.6T,152pS的馬力,但這對於身形更小,中心更低的A級來說會是更加刺激的動力輸出。底盤的調較已經放棄了奔馳的舒適,非常硬,而轉向則依舊輕盈,高速行駛的穩定性很好。

總結:買車,有時候買的更是一種生活,如果你真正載人的時間不是十分多的話,何不買一輛駕駛帶感,做工精緻的車來好好取悅自己呢?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

【極客思考】計算機網絡:Wireshark抓包分析TCP中的三次握手與四次揮手_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

【摘要】本文重點分析計算機網絡中TCP協議中的握手和揮手的過程。

【前提說明】

前段時間突然看到了一篇關於TCP/IP模型的文章,心想這段時間在家裡也用wireshark抓了點包,那麼想着想着就覺得需要複習一下網絡知識,於是就有這篇博文的誕生。當然網上關於TCP相關的知識點也是芸芸,閑着無事也可以多google深入理解一下,本文重點在分析TCP協議中的握手和揮手的過程。

【抓包前準備】

既然要抓包,我的裝備是個人電腦,操作系統是Mac OS。抓包工具是wireshark,至於怎麼安裝和一些基本的操作,可以點擊參考這篇文章。

用本地電腦模擬server和client,都是localhost的地址,但是我選擇的是不同的端口進行標識。server的端口號:12345;client的端口號:50784。因為是用的本機做的實驗,所以wireshark監聽的不是網卡而是Loopback:lo0,如圖所示:

以下是我模擬client和server的代碼:

1)server端

-Python 代碼
01
#! /usr/bin/python
02
# -*- coding: utf-8 -*-
03
 
04
import socket
05
 
06
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
07
 
08
server_address = ('127.0.0.1', 12345)
09
print "Starting up on %s:%s" % server_address
10
sock.bind(server_address)
11
 
12
sock.listen(1)
13
 
14
while True:
15
    print "Waiting for a connection"
16
    connection, client_address = sock.accept()
17
 
18
    try:
19
        print "Connection from", client_address
20
 
21
        data = connection.recv(1024)
22
        print "Receive '%s'" % data
23
    finally:
24
        connection.close()

2)client端-Python 代碼

01
# /usr/bin/python
02
# -*- coding: utf-8 -*-
03
 
04
import socket
05
 
06
def check_tcp_status(ip, port):
07
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
08
 
09
    server_address = (ip, port)
10
    print 'Connecting to %s:%s.' % server_address
11
    sock.connect(server_address)
12
 
13
    message = "I'm TCP client"
14
    print 'Sending "%s".' % message
15
    sock.sendall(message)
16
 
17
    print 'Closing socket.'
18
    sock.close()
19
 
20
 
21
if __name__ == "__main__":
22
    print check_tcp_status("127.0.0.1", 12345)

代碼比較簡單,就是模擬了一次鏈接,可以多次執行client,client只要鏈接成功就會發送一句話“I’m TCP client”,server一直死循環監聽端口,並將接受到的信息打印到console中。

【結果分析】

看到上面的console輸出之後,我們看一下wireshark抓到的結果:

我用兩種顏色標了出來,可以看到黃色框中的序號為1、2、3的三次通信過程其實就是我們說的三次握手;握手建立之後的序號為4、5、6便為傳輸數據的過程;而序號7、8、9、10就是我們所說的四次揮手的過程。

我們再進一步細看下握手、揮手這倆過程。

三次握手

 

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

我們來總結一下握手的規律:

  • 第一次握手:建立鏈接。客戶端發送鏈接的請求,發送SYN報文,將Seq設置為0。然後客戶端就進入了SYN_SEND狀態,等待服務器的確認。
  • 第二次握手:服務器收到客戶端的SYN報文段。需要對這個SYN報文段進行確認,發送ACK報文,並將Ack設置為1。同時,自己也要發送SYN請求信息,將Seq設置為0,。服務器將上述的所有信息一併發送給客戶端,此時服務器進入SYN_RECV狀態。
  • 第三次握手:客戶端收到服務器的ACK和SYN報文後,進行確認,然後將Ack設置為1,Seq設置為1,向服務器發送ACK報文段,這個報文段發送完畢之後,客戶端和服務器都進入了ESTABLISHED狀態。就此完成了TCP的三次握手。

四次揮手

 

接着總結下揮手的規律:

  • 第一次揮手:客戶端想服務器發送一個FIN報文段,將設置Seq為15和Ack為1。此時客戶端進入FIN_WAIT_1狀態。這表示客戶端沒有數據要發送服務器了,請求關閉連接。
  • 第二次揮手:服務器收到了客戶端發送的FIN報文段,向客戶端回一個ACK報文段,Ack設置為16,Seq設置為1;服務器進入了CLOSE_WAIT狀態,客戶端收到服務器返回的ACK報文之後隨即進入FIN_WAIT_2狀態。
  • 第三次揮手:服務器會觀察自己是否還有數據沒有發送給客戶端,如果有,先把數據發送給客戶端,再發送FIN報文;如果沒有,那麼服務器直接發送FIN報文給客戶端。請求關閉連接,同時服務器進入LAST_ACK狀態。
  • 第四次揮手:客戶端收到服務器發送的FIN報文,向服務器發送ACK報文,將Seq設置為16,Ack設置為2,然後客戶端進入TIME_WAIT狀態;服務器收到客戶端的ACK報文之後就關閉了連接;此時,客戶端等待2msl后依然沒有收到回復,則證明服務器已正常關閉,客戶端也可以關閉連接了。

注意個規律: 每次一方返回ACK報文的時候,設置Ack=對方傳來的Seq值+1。

【理解TCP/IP模型】

說完TCP協議之後,不能免俗的要聊一下TCP/IP協議模型,該模型是計算機網絡的經典的模型了。該模型由OSI模型演化而來,由原來的7層簡化為了5層,具體如下圖所示:

TCP/IP協議被稱為傳輸控制協議/互聯網協議,又稱網絡通訊協議(Transmission Control Protocol)。是由網絡層的IP協議和傳輸層的TCP協議組成,是一個很大的協議集合。

  • 物理層和數據鏈路層沒有定義任何特定協議,支持所有的標準和專用的協議。
  • 網絡層定義了網絡互聯也就是IP協議,主要包括IP、ARP、RARP、ICMP、IGMP。
  • 傳輸層定義了TCP和UDP(User Datagram Protocol),我們會後面重點介紹一下TCP協議。
  • 應用層定義了HTTP(超文本傳輸協議)、FTP(文件傳輸協議)、DNS(域名系統)等協議。

TCP/IP的網絡模型分層思想算是非常有借鑒性的系統分層思想。映射到我們的軟件系統上來看,其實我們的軟件系統更多的時候也需要考慮分層,層次之間通過接口來交互。在嚴格的分層系統里,內部的層只對相鄰的層次可見,這樣就可以將一個複雜問題分解成增量步驟序列。由於每一層最多隻影響兩層,也給維護帶來了很大的便利。

參考資料:

http://www.cnblogs.com/linyfeng/p/9496126.html

http://zhuanlan.zhihu.com/p/33797520

blog.csdn.net/zhzdeng/article/details/53490386

點擊關注,第一時間了解華為雲新鮮技術~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

孫金龍赴廣西調研省以下環保垂改工作_包裝設計

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

2020-11-12 來源:生態環境部

2020-11-12
來源:生態環境部 分享到:
[打印]
字號:[大] [中] [小]   11月12日,生態環境部黨組書記孫金龍赴廣西南寧,調研省以下環保機構監測監察執法垂直管理改革工作(以下簡稱環保垂改)情況。他強調,要深入學習貫徹十九屆五中全會精神,按照中央巡視反饋意見整改工作要求,紮實推進環保垂改任務如期落實落地,進一步釋放改革紅利,助力“十四五”生態環境保護工作開好局、起好步。   孫金龍先後來到南寧市生態環境局、自治區生態環境廳主持召開座談會,分別聽取自治區、市、縣三級生態環境部門監測監察執法垂直管理改革落實情況的彙報。座談會上,大家總結了改革落實過程中的好做法好經驗,

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

對一些具有共性、單靠基層又難以解決的突出問題,進行了深入探討交流,提出了下一步深入推進落實改革任務的意見建議。   孫金龍強調,習近平總書記早在黨的十八屆五中全會上就親自部署環保垂改任務,並就為什麼要改革和怎麼樣改革作了說明。黨中央、國務院印發《關於省以下環保機構監測監察執法垂直管理制度改革試點工作的指導意見》,要求“十三五”時期全面完成環保機構監測監察執法垂直管理制度改革任務。全國生態環境系統要切實增強“四個意識”、堅定“四個自信”、做到“兩個維護”,深刻認識到環保垂改是對地方生態環境管理體制整體重塑的一項重大改革舉措,進一步增強做好垂改工作的緊迫感、責任感和使命感。要有效銜接地方機構改革、綜合執法改革,有針對性地解決環保垂改落實過程中存在的問題,加快打造生態環境保護鐵軍,為精準治污、科學治污、依法治污提供堅強體制機制保障。   廣西壯族自治區政府副主席劉宏武出席座談會並陪同調研。中央編辦有關負責同志,生態環境部辦公廳、人事司主要負責同志參加調研和座談。   廣西壯族自治區生態環境廳主要負責同志及班子成員和有關負責同志;南寧市生態環境局主要負責同志及班子成員和有關負責同志;柳州市、賀州市、桂林市全州、來賓市忻城生態環境局主要負責同志參加座談會。

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

小米發表中階 Redmi Note 9T 與入門 Redmi 9T,效能與長續航合而為一_包裝設計

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

好久沒有紅米系列的好消息了,在今晚(1/8)的發表會中,小米一口氣發表了號稱中階、入門機皇的兩款新機 Redmi Note 9T 與 Redmi 9T,以震撼 5G 手機市場的價格提供 5G + 5G 雙卡雙待,超乎同級競爭對手的效能表現與長效續航力,攝影與外型上也絲毫不妥協。

小米發表中階 Redmi Note 9T 與入門 Redmi 9T,效能與長續航合而為一

Redmi Note 9T
這款機型擁有特別打造的機身外型,具備 Unibody 3D 曲面機背,具紋理的聚碳酸酯纖維提高抓握感和抗指紋等特性,加上康寧第五代大猩猩玻璃的保護,讓你用起來更安心,共有日暮黑與晨曦紫兩款顏色,典雅大方。配備 6.53 吋 FHD+ DotDisplay 螢幕,並通過德國萊因低藍光認證,在給你更好的視覺享受同時保護你的眼睛。

搭載支援 5G 的聯發科天璣 800U 行動平台,處理速度較前代快 100%,以八核心處理器及 7nm 製程技術帶來絕佳的運行效能。而 Redmi Note 9T 也是整個 Redmi Note 系列中首款隻原 5G+5G 雙卡雙待的機型;配備 5,000mAh 電池和高效處理器技術,在消除電池容量煩惱同時為 5G 時代兼顧效能與電源效率兩個方面。Redmi Note 9T 支援 18W 快速充電,手機隨盒附上 22.5W 充電器,加上高循環週期電池技術,在日常情況下可確保 3 年電量儲存不縮水。

Redmi Note 9T 配備 4,800 萬像素 AI 三鏡頭後置相機,以 4,800 萬像素主鏡頭、200 萬像素景深鏡頭和 200 萬像素微距鏡頭,讓攝影新手也能輕鬆拍出專業攝影作品。以 1/2 吋感光元件和旗艦級 ISP 影像處理器架構,提升影像品質與提供更快的成像速度。同時,Redmi Note 9T 擁有多款全新攝影模式,如夜景模式、Pro+、RAW、HDR和人像模式等,在任何時刻均能捕捉完美的照片。

Redmi Note 9T 提供 4GB+64GB 及 4GB+128GB 兩種容量選擇,售價分別為 229 歐元(約合新台幣 8,085 元)及 269 歐元(約合新台幣 9,495 元)。

Redmi 9T
Redmi 9T 採用圓角及防指紋機背的現代簡約設計,配備 6.53 吋外覆康寧第三代大猩猩玻璃的 FHD+ 水滴螢幕,帶來清晰的觀看體驗,同時提供有效的防裂和防刮保護,共提供碳纖灰、暮光藍、日出橙與海洋綠四款顏色。

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

配備 6,000mAh 大電量電池及 Qualcomm Snapdragon 662 行動平台,以 11nm 製程的節能處理器,讓 Redmi 9T 在產生更少熱能及更少功耗的情況下,比前幾代帶來更高的效能。此外,MIUI的省電模式及反向有線充電功能,讓使用者能全日或多日使用。而 Redmi 9T 與 Redmi Note 9T 同樣支援 18W 快充,且隨盒一樣附贈 22.5W 充電器。Redmi 9T 支援雙卡及可擴充 microSD 的儲存空間,提供高達 512GB 內建儲存空間,並能彈性擴充,讓用戶可以將喜愛的應用程式、遊戲、照片及影片儲存於同一手機;另外,Redmi 9T 支援紅外線遙控功能,增加操控其他裝置的方便性。

Redmi 9T 配備 4,800 萬像素 AI 四鏡頭,除主鏡頭外,還有 800 萬像素超廣角鏡頭能在無需裁剪的情況下拍攝大型團體照及寬廣的風景照,而 200 萬像素微距鏡頭及 200 萬像素景深鏡頭可拍攝出具專業水平的特寫照片。Redmi 9T 提供全新電影相框功能,在無需編輯的情況下讓照片呈現電影質感。同時,更擁有全新縮時攝影功能,拍攝可設定不同速度和持續時間,在無需使用數位單眼相機或其他專業相機的情況下,拍攝出創意亮眼的縮時照片。

Redmi 9T 提供 4GB+64GB、4GB+128GB 及 6GB+128GB 三種容量選擇,售價分別為 159 歐元(約合新台幣 5,615 元)、189 歐元(約合新台幣 6,670 元)及 199 歐元(約合新台幣 7,025 元)。

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

【大廠面試01期】高併發場景下,如何保證緩存與數據庫一致性?_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

PS:本文已收錄到1.1K Star數開源學習指南——《大廠面試指北》,如果想要了解更多大廠面試相關的內容及獲取《大廠面試指北》離線PDF版,請掃描下方二維碼碼關注公眾號“大廠面試”,謝謝大家了!項目地址:https://github.com/NotFound9/interviewGuide

《大廠面試指北》項目截圖:

獲取《大廠面試指北》離線PDF版,請掃描下方二維碼關注公眾號“大廠面試”

面試題:高併發場景下,如何保證緩存與數據庫一致性?

問題分析

我們日常開發中,對於緩存用的最多的場景就像下圖一樣,可能僅僅是對數據進行緩存,減輕數據庫壓力,縮短接口響應時間。

這種方案在不需要考慮高併發得去寫緩存,高併發得讀寫緩存時,是不會有問題,但是如果是在高併發場景下,要保證緩存和數據庫的一致性,至少需要解決以下問題:

高併發寫時的數據不一致問題

高併發讀寫時,請求執行各步驟的順序是不可控的。假設此時有一個請求A,B都在在執行寫流程,請求A是需要將某個數據改成1,請求B是需要將某個數據改為2,執行操作如下時就會導致數據不一致的問題:

1.請求A執行操作1.1刪除緩存。

2.請求A執行操作1.2更新數據庫,將值改為1。

3.請求B執行操作1.1刪除緩存。

4.請求B執行操作1.2更新數據庫,將值改為2

5.假設說請求B所在服務器網絡延遲比較低,請求B先更新緩存,此時緩存中的key對應的value是2。

6.請求A更新緩存,將緩存中B更新的數據進行覆蓋,將key對應的值改為1。

此時數據庫中是B修改后的數據,值為2,而緩存中的數據是1,這樣在緩存過期錢,用戶讀到的都是臟數據,與數據庫不一致。

高併發讀寫時的數據不一致的問題

高併發讀寫時,請求執行各步驟的順序是不可控的。假設此時有一個請求A在執行寫流程,將原值由1改成2,請求B執行讀流程,執行操作如下時就會導致數據不一致的問題:

1.寫請求A執行1.1操作刪除緩存key,value是原值1。

2.讀請求B執行2.1操作發現緩存中沒有數據,就去執行2.2操作讀數據庫,讀到舊數據,值為1。

3.寫請求A執行1.2操作更新數據庫,將數據由1改為2。

4.寫請求A執行1.3操作更新緩存,此時緩存中的數據key對應的value是2。

5.讀請求B執行2.3操作更新緩存,將之前讀到的舊數據1設置到緩存中,此時緩存中的數據key對應的value是1。

所以如果說讀請求B所在服務器網絡延遲比較高,去執行2.3操作比寫請求A晚,就會導致寫請求A更新完緩存后,讀請求B使用之前讀到的舊數據去更新緩存,此時緩存中數據就與數據庫中的不一致。

解決方案

保證數據一致性,網上有很多種方案,例如:

1.先刪除緩存,再更新數據庫。

2.先更新數據庫,再刪除緩存。

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

3.先刪除緩存,再更新數據庫,然後異步延遲一段時間再去刪一次緩存。

但是這些方案都是存在各種各樣的問題,這裏篇幅有限,只給出目前相對正確的三套方案,目前的這些方案也有自己的局限性。

方案1.寫請求串行化

寫請求

1.寫請求更新之前先獲取分佈式鎖,獲得之後才能去數據庫更新這個數據,獲取不到就進行等待,超時后就返回更新失敗。

2.更新完之後去刷新緩存,如果刷新失敗,放到內存隊列中進行重試(重試時取數據庫最新數據更新緩存)。

讀請求

讀請求發現緩存中沒有數據時,直接去讀取數據庫,讀完更新緩存。

總結

這種技術方案通過對寫請求的實現串行化來保證數據一致性,但是會導致吞吐量變低。比較適合銀行相關的業務,因為對於銀行項目來說,保證數據一致性比可用性更加重要,就像是去存款機存錢,取錢時,為了保證賬戶安全,都是會讓用戶執行操作后,等待一段時間才能獲得反饋,這段時間其實取款機是不可用的。

方案2.先更新數據庫,異步刪除緩存,刪除失敗后重試

1.先更新數據庫

2.異步刪除緩存(如果數據庫是讀寫分離的,那麼刪除緩存時需要延遲刪除,否則可能會在刪除緩存時,從庫還沒有收到更新后的數據,其他讀請求就去從庫讀到舊數據然後設置到緩存中。)

3.刪除緩存失敗時,將刪除的key放到內存隊列或者是消息隊列中進行異步重試

發散思考

在更新完數據庫后,我們為什麼不直接更新,而是採用刪除緩存呢?

這是因為直接更新緩存的話,在高併發場景下,有多個更新請求時,難以保證后更新數據庫的請求會後更新緩存,也就是上面的高併發寫問題。如果採用刪除緩存,可以讓下次讀時讀取數據庫,更新緩存,保證一致性。

方案3.業務項目更新數據庫,其他項目訂閱binlog更新

1.業務項目直接更新數據庫。

2.cannal項目會讀取數據庫的binlog,然後解析后發消息到kafka。

3.然後緩存更新項目訂閱topic,從kafka接收到更新數據庫操作的消息后,更新緩存,更新緩存失敗時,新建異步線程去重試或者將操作發到消息隊列,後續再進行處理。

總結:

但是這種方案在更新數據庫后,緩存中還是舊值,必須等緩存更新項目消費消息后,更新緩存,緩存中才是最新值。所以更新操作完成與更新生效之間會有一定的延遲。

最後

大家有了解其他的技術方案,歡迎進群一起討論!

評論裏面有朋友問延時雙刪策略是什麼?

這裏解釋一下:延時雙刪策略就是先刪除緩存,再更新數據庫,再異步過一小段時間后刪除緩存(時間取決於MySQL主從同步的時間)。

是因為MySQL如果是讀寫分離時(寫請求寫主庫,讀請求讀從庫),我們更新主庫后,需要一段時間,從庫才會收到更新。

如果是寫請求更新主庫后,第二次立即刪除緩存,MySQL從庫還沒有收到更新,還是舊數據,那麼讀請求直接從庫讀到舊數據,設置到緩存的數據就是舊數據,就會數據不一致,所以這也是延時雙刪策略提出的初衷。

參考鏈接:

https://www.cnblogs.com/-wenli/p/11474164.html

https://www.cnblogs.com/rjzheng/p/9041659.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

研究:1950年代以來 全球熱浪天數不斷增加_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

小米推出米家電動刮鬍刀 S700 :米家首款旋轉式陶瓷刀片刮鬍刀,支援座充與 Type-C 充電_包裝設計

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

除了隨身旅行好攜帶的米家便攜電動刮鬍刀 1S ,採用座充方式的米家電動刮鬍刀 S500 系列則是台灣消費者目前在小米台灣可夠買的機種。近日小米也在中國率先推出全新一代的米家電動刮鬍刀 S700 ,不僅是米家首款採用旋轉式陶瓷刀片的刮鬍刀,這次更在座充之外增加了 Type-C 的充電方式,對於臨時充電需求更加便利。

小米推出米家電動刮鬍刀 S700 :米家首款旋轉式陶瓷刀片刮鬍刀,支援座充與 Type-C 充電

米家電動刮鬍刀 S700 搭載陶瓷刀片,也是米家旗下首款採用旋轉式陶瓷刀片的電動刮鬍刀,以廣泛應用於醫療領域的氧化鋯陶瓷為基礎材料打造,刀片鋒利、抗腐蝕能力更強、耐酸鹼、不易氧化,使用壽命也比以往更持久。相較過去鋼刀片硬度為 HV500~600 ,而陶瓷刀片硬度則為 HV1200~1500 ,抗磨損能力也更強。

創新的鬍鬚檢測系統通過全方位的 PID 演算法智慧檢測鬍鬚負載,讓轉速始終保持恆定且不受進鬍量、鬍鬚密度影響。米家電動刮鬍刀 S700 搭載 4.4nN・m 大扭矩電機和高階直驅低噪馬達,在保有強勁不卡頓的動力同時也讓運轉噪音更低。

藉由創新懸掛浮動和獨立浮動技術,讓 3 刀頭全面服貼臉部、剃鬍無死角。動力模式可根據個人習慣或皮膚狀態切換 3 檔轉速模式。同時也支持檔位記憶功能,讓下次啟動無需手動調節。

以往座充類型的電動刮鬍刀多數都只支持座充的方式,但這對於旅行攜帶就得記得帶著充電座、尋找能充電的插座,難免感到不太方便。
全新推出的米家電動刮鬍刀 S700 除了延續過去的座充方式,更在機身上配置 USB Type-C 充電接口,不僅讓充電更容易、更支持邊充邊用的便利功能。米家電動刮鬍刀 S700 亦支持 2 小時快速充電,在充飽電後最長可 60 分鐘的時間。

對於電動刮鬍刀使用者來說,時常清洗保持衛生的狀態也相當重要,米家電動刮鬍刀 S700 整機為 IPX7 等級防水,在機身底部也設置機內排水口,讓清洗更方便。

細節方面,米家電動刮鬍刀 S700在刀頭外圈部分鍍以順滑圖層,有效降低摩擦、減輕肌膚的刺激感。

米家也將應用於汽車儀錶板、高階電子產品的雷射微孔顯示技術沿用到電動刮鬍刀,在米家電動刮鬍刀 S700 的金屬機身下可顯示電量、檔位、旅行所以及鬍鬚清理通知,都能藉由指示燈清晰呈現:

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

米家電動刮鬍刀採用高強度 6 系列全鋁金屬機身,擁有抗氧化、兼顧、輕盈的特性:

由於米家電動刮鬍刀 S700 更高階的產品定位,在價格方面也相較之前略高一些,建議售價為人民幣 499 元(約合新台幣 2,150 元),不過與其他同級產品相比性價比仍是相當高。

圖片/消息來源:小米商城(中國)

延伸閱讀:
小米智慧攝影機雲台版2K 在台開賣:升級 2K 高畫質和 F1.4 大光圈,售價 1,095元

小米11 Pro 最新高清晰概念渲染圖曝光!傳聞搭載 50MP 四鏡頭主相機,支持 120x 混合變焦

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

Flutter 動畫鼻祖之CustomPaint_包裝設計

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

老孟導讀:CustomPaint可以稱之為動畫鼻祖,它可以實現任何酷炫的動畫和效果。CustomPaint本身沒有動畫屬性,僅僅是繪製屬性,一般情況下,CustomPaint會和動畫控制配合使用,達到理想的效果。

基本用法

CustomPaint的用法非常簡單,如下:

CustomPaint(
  painter: MyCustomPainter(),
)

MyCustomPainter定義如下:

class MyCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {}

  @override
  bool shouldRepaint(MyCustomPainter oldDelegate) {
    return this != oldDelegate;
  }
}

上面的MyCustomPainter為了看起來清晰,什麼也沒有做,通常情況下,在paint方法內繪製自定義的效果。shouldRepaint方法通常在當前實例和舊實例屬性不一致時返回true。

paint通過canvas繪製,size為當前控件的大小,下面看看canvas的方法。

繪製點

Paint _paint = Paint()
    ..color = Colors.red
    ..strokeWidth = 3;

  @override
  void paint(Canvas canvas, Size size) {
    var points = [
      Offset(0, 0),
      Offset(size.width / 2, size.height / 2),
      Offset(size.width, size.height),
    ];
    canvas.drawPoints(PointMode.points, points, _paint);
  }

PointMode有3種模式:

  • points:點
  • lines:將2個點繪製為線段,如果點的個數為奇數,最後一個點將會被忽略
  • polygon:將整個點繪製為一條線

繪製線

canvas.drawLine(Offset(0, 0),Offset(size.width, size.height), _paint);

繪製路徑

Paint _paint = Paint()
  ..color = Colors.red
  ..style = PaintingStyle.stroke
  ..strokeWidth = 3;

@override
void paint(Canvas canvas, Size size) {
  print('size:$size');
  var _path = Path()
    ..moveTo(0, 0)
    ..lineTo(size.width, 0)
    ..lineTo(size.width, size.height)
  ..close();
  canvas.drawPath(_path, _paint);
}

這裏注意Paint.style,還可以設置為PaintingStyle.fill,效果如下:

此時Path的路徑不要在一條直線上,否則會看不到效果。

繪製各種形狀

繪製圓形

canvas.drawCircle(Offset(size.width/2, size.height/2), 20, _paint);

繪製橢圓

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

canvas.drawOval(Rect.fromLTRB(0, 0, size.width, size.height/2), _paint);

如果給定的Rect為正方形,那麼橢圓將會變為圓形。

繪製弧

canvas.drawArc(
    Rect.fromLTRB(0, 0, size.width, size.height), 0, pi/2, true, _paint);

繪製圓角矩形

canvas.drawRRect(
    RRect.fromLTRBR(0, 0, size.width, size.height, Radius.circular(10)), _paint)

canvas還有很多繪製函數,比如貝塞爾曲線、三次貝塞爾曲線、畫布的反轉等操作,這裏不在一一介紹。

這些函數和Android的Canvas基本一樣,如果你有Android基礎,直接套用即可。

最後奉上一個繪製玫瑰的動畫效果:

這個效果是不是很酷炫,我們看下繪製花骨朵代碼:

///
/// 繪製花骨朵
///
_drawFlower(Canvas canvas, Size size) {
  //將花變為紅色
  if (flowerPaths.length >= RoseData.flowerPoints.length) {
    var path = Path();
    for (int i = 0; i < flowerPaths.length; i++) {
      if (i == 0) {
        path.moveTo(flowerPaths[i].dx, flowerPaths[i].dy);
      } else {
        path.lineTo(flowerPaths[i].dx, flowerPaths[i].dy);
      }
    }
    _paint.style = PaintingStyle.fill;
    _paint.color = _flowerColor;
    canvas.drawPath(path, _paint);
  }
  //繪製線
  _paint.style = PaintingStyle.stroke;
  _paint.color = _strokeColor;
  //去掉最後2個點,最後2個點為了繪製紅色
  var points = flowerPaths.sublist(0, max(0, flowerPaths.length - 2));
  canvas.drawPoints(PointMode.polygon, points, _paint);
}

花骨朵的繪製只通過canvas.drawPath就實現了,其實整個玫瑰花的繪製都是通過canvas.drawPath加上動畫控制實現的。

CustomPaint可以實現任何你想要的動畫的效果,比如繪畫版就可以通過此控件實現。

獲取完整代碼方式掃碼下方二維碼回復:rose

交流

老孟Flutter博客地址(近200個控件用法):http://laomengit.com

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

居然還有人這樣解說mybatis運行原理_台中搬家

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

目錄

  • Mybatis基本認識
    • 動態代理
      • JDK實現
      • CGLIB動態代理
      • 總結
    • 反射
  • Configuration對象作用
  • 映射器結構
  • sqlsession執行流程(源碼跟蹤)
    • Executor
    • StatementHandler
    • 結果處理器(ResultSetHandler)
    • 總結
  • 主題

mybatis運行分為兩部分,第一部分讀取配置文件緩存到Configuration對象中。用以創建SqlSessionFactory,第二部分是SqlSession的執行過程。

Mybatis基本認識

動態代理

  • 之前我們知道Mapper僅僅是一個接口,而不是一個邏輯實現類。但是在Java中接口是無法執行邏輯的。這裏Mybatis就是通過動態代理實現的。關於動態代理我們常用的有Jdk動態代理和cglib動態代理。兩種卻別這裏不做贅述。關於CGLIB代理在框架中使用的比較多。

  • 關於動態代理就是所有的請求有一個入口,由這個入口進行分發。在開發領域的一個用途就是【負載均衡】

  • 關於Mybatis的動態代理是使用了兩種的結合。

  • 下面看看JDK和cglib兩種實現

JDK實現

  • 首先我們需要提供一個接口 , 這個接口是對我們程序員的一個抽象。 擁有編碼和改BUG的本領

public interface Developer {

    /**
     * 編碼
     */
    void code();

    /**
     * 解決問題
     */
    void debug();
}

  • 關於這兩種本領每個人處理方式不同。這裏我們需要一個具體的實例對象

public class JavaDeveloper implements Developer {
    @Override
    public void code() {
        System.out.println("java code");
    }

    @Override
    public void debug() {
        System.out.println("java debug");
    }
}

  • 我們傳統的調用方式是通過java提供的new 機制創造一個JavaDeveloper對象出來。而通過動態代理是通過java.lang.reflect.Proxy對象創建對象調用實際方法的。

  • 通過newProxyInstance方法獲取接口對象的。而這個方法需要三個參數
    ClassLoader loader : 通過實際接口實例對象獲取ClassLoader
    Class<?>[] interfaces : 我們抽象的接口
    InvocationHandler h : 對我們接口對象方法的調用。在調用節點我們可以進行我們的業務攔截


JavaDeveloper jDeveloper = new JavaDeveloper();
Developer developer = (Developer) Proxy.newProxyInstance(jDeveloper.getClass().getClassLoader(), jDeveloper.getClass().getInterfaces(), (proxy, method, params) -> {
    if (method.getName().equals("code")) {
        System.out.println("我是一個特殊的人,code之前先分析問題");
        return method.invoke(jDeveloper, params);
    }
    if (method.getName().equals("debug")) {
        System.out.println("我沒有bug");

    }
    return null;
});
developer.code();
developer.debug();

CGLIB動態代理

  • cglib動態代理優點在於他不需要我們提前準備接口。他代理的實際的對象。這對於我們開發來說就很方便了。

public class HelloService {
    public HelloService() {
        System.out.println("HelloService構造");
    }

    final public String sayHello(String name) {
        System.out.println("HelloService:sayOthers>>"+name);
        return null;
    }

    public void sayHello() {
        System.out.println("HelloService:sayHello");
    }
}

  • 下面我們只需要實現cglib提供的MethodInterceptor接口,在初始化設置cglib的時候加載這個實例化對象就可以了

public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("======插入後者通知======");
        return object;
    }
}

  • 下面我們就來初始化設置cglib

public static void main(String[] args) {
    //代理類class文件存入本地磁盤方便我們反編譯查看源代碼
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/root/code");
    //通過CGLIB動態代理獲取代理對象過程
    Enhancer enhancer = new Enhancer();
    //設置enhancer對象的父類
    enhancer.setSuperclass(HelloService.class);
    // 設置enhancer的回調對象
    enhancer.setCallback(new MyMethodInterceptor());
    //創建代理對象
    HelloService helloService = (HelloService) enhancer.create();
    //通過代理對象調用目標方法
    helloService.sayHello();
}

  • 仔細看看cglib和spring的aop特別像。針對切點進行切面攔截控制。

總結

  • 通過對比兩種動態代理我們很容易發現,mybatis就是通過JDK代理實現Mapper調用的。我們Mapper接口實現通過代理到xml中對應的sql執行邏輯

反射

  • 相信有一定經驗的Java工程師都對反射或多或少有一定了解。其實從思想上看不慣哪種語言都是有反射的機制的。
  • 通過反射我們就擺脫了對象的限制我們調用方法不再需要通過對象調用了。可以通過Class對象獲取方法對象。從而通過invoke方法進行方法的調用了。

Configuration對象作用

  • Configuration對象存儲了所有Mybatis的配置。主要初始化一下參數
    • properties
    • settings
    • typeAliases
    • typeHandler
    • ObjectFactory
    • plugins
    • environment
    • DatabaseIdProvider
    • Mapper映射器

映射器結構

  • BoundSql提供三個主要的屬性 parameterMappings 、parameterObject、sql

  • parameterObject參數本身。我們可以傳遞java基本類型、POJO、Map或者@Param標註的參數。

  • 當我們傳遞的是java基本類型mybatis會轉換成對應的包裝對象 int -> Integer

  • 如果我們傳遞POJO、Map。就是對象本身

  • 我們傳遞多個參數且沒有@Param指定變量名則parameterObject 類似
    {“1″:p1,”2″:p2,”param1″:p1,”param2”:p2}

    台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

    台中搬家公司推薦超過30年經驗,首選台中大展搬家

  • 我們傳遞多個參數且@Param指定變量名 則parameterObject類似
    {“key1″:p1,”key2″:p2,”param1″:p1,”param2”:p2}

  • parameterMapping 是記錄屬性、名稱、表達式、javaType,jdbcType、typeHandler這些信息

  • sql 屬性就是我們映射器中的一條sql. 正常我們在常見中對sql進行校驗。正常不需要修改sql。

sqlsession執行流程(源碼跟蹤)

  • 首先我們看看我們平時開發的Mapper接口是如何動態代理的。這就需要提到MapperProxyFactory這個類了。該類中的newInstance方法

protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  • 通過上滿代碼及上述對jdk動態代理的表述。我們可以知道mapperProxy是我們代理的重點。
  • MapperProxy是InvocationHandler的實現類。他重寫的invoke方法就是代理對象執行的方法入口。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
    if (Object.class.equals(method.getDeclaringClass())) {
    return method.invoke(this, args);
    } else if (isDefaultMethod(method)) {
    return invokeDefaultMethod(proxy, method, args);
    }
} catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}


private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
    & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
    && method.getDeclaringClass().isInterface();
}

  • 通過源碼發現。invoke內部首先判斷對象是否是類 。 通過打斷點發現最終會走到cacheMapperMethod這個方法去創建MapperMethod對象。
  • 繼續查看MapperMethod中execute方法我們可以了解到內部實現其實是一個命令行模式開發。通過判斷命令從而執行不同的語句。判斷到具體執行語句然後將參數傳遞給sqlsession進行sql調用並獲取結果。到了sqlsession就和正常jdbc開發sql進行關聯了。sqlsession中ExecutorStatementHandlerParameterHandlerResulthandler四大天王

Executor

  • 顧名思義他就是一個執行器。將java提供的sql提交到數據庫。Mybatis提供了三種執行器。

  • Configuration.classnewExecutor源碼

  • 根據uml我們不難看出mybatis中提供了三類執行器分別SimpleExecutor、ReuseExecutor、BatchExecutor

public SqlSession openSession() {
  return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 得到configuration 中的environment
      final Environment environment = configuration.getEnvironment();
      // 得到configuration 中的事務工廠
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 獲取執行器
      final Executor executor = configuration.newExecutor(tx, execType);
      // 返回默認的SqlSession
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  • 通過上述源碼我們知道在sqlsession獲取一個數據庫session對象時我們或根據我們的settings配置加載一個Executor對象。在settings中配置也很簡單

<settings>
<!--取值範圍 SIMPLE, REUSE, BATCH -->
	<setting name="defaultExecutorType" value="SIMPLE"/>
</settings>

  • 我們也可以通過java代碼設置

factory.openSession(ExecutorType.BATCH);

StatementHandler

  • 顧名思義,StatementHandler就是專門處理數據庫回話的。這個對象的創建還是在Configuration中管理的。

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

  • 很明顯Mybatis中StatementHandler使用的是RoutingStatementHandler這個class
  • 關於StatementHandler和RoutingStatementHandler之間的關係我們通過源碼可以看出這裏和Executor一樣都是適配器模式。採用這種模式的好處是方便我們對這些對象進行代理。這裏讀者可以猜測一下是使用了哪種動態代理。給點提示 這裏使用了接口哦

  • 在查看BaseStatementHandler結構我們會發現和Executor一模一樣。同樣的Mybatis在構造RoutingStatementHandler的時候會根據setting中配置來加載不同的具體子類。這些子類都是繼承了BaseStatementHandler.

  • 前一節我們跟蹤了Executor。 我們知道Mybatis默認的是SimpleExecutor。 StatementHandler我們跟蹤了Mybaits默認的是PrePareStatementHandler。在SimpleExecutor執行查詢的源碼如下

  • 我們發現在executor查詢錢會先讓statementHandler構建一個Statement對象。最終就是StatementHandler中prepare方法。這個方法在抽象類BaseStatmentHandler中已經封裝好了。
  • 這個方法的邏輯是初始化statement和設置連接超時等一些輔助作用
  • 然後就是設置一些參數等設置。最後就走到了執行器executor的doquery
  • PrepareStatement在我們jdbc開發時是常見的一個類 。 這個方法執行execute前我們需要設置sql語句,設置參數進行編譯。這一系列步驟就是剛才我們說的流程也是PrepareStatementHandler.prepareStatement幫我們做的事情。那麼剩下的我們也很容易想到就是我們對數據結果的封裝。正如代碼所示下馬就是resultSetHandler幫我們做事情了。

結果處理器(ResultSetHandler)


@Override
  public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

  • 這個方法我們可以導出來是結果xml中標籤配置對結果的一個封裝。

總結

  • SqlSession在一個查詢開啟的時候會先通過CacheExecutor查詢緩存。擊穿緩存後會通過BaseExector子類的SimpleExecutor創建StatementHandler。PrepareStatementHandler會基於PrepareStament執行數據庫操作。並針對返回結果通過ResultSetHandler返回結果數據

主題

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司