主頁 > 後端開發 > 讓世界為之贊嘆的開源專案,除了 Linux,還有我們常用的Git

讓世界為之贊嘆的開源專案,除了 Linux,還有我們常用的Git

2020-09-25 03:06:30 後端開發

吾詩已成,無論大神的震怒,還是山崩地裂,都不能把它化為無形!
—— 奧維德《變形記》

之前的時候,我寫過幾個把GitHub當作網盤等使用的騷氣操作,純粹是出于個人愿意瞎折騰,然后寫了一篇大廠為什么喜歡問原始碼的文章

本身應該沒什么問題,但是,突然今天,有一個很神奇的讀者聯系我,看下面的對話吧

 

這大哥是怎么把這兩個事聯系到一起的呀,將來必成大事啊

但是同樣的,最后我的那個問題,你的答案是什么,如果你的答案和我最初那樣,git=svn+分布式的話,那我還是建議你去看一下吧

還可能會有人說,git不就是個代碼倉庫啊,花里胡哨的整這么多干什么,我不太想懟人,只能說是你面試的不夠,不信,看下面這張圖,這是我整理的一些關于git的面試和使用重點,幾乎常用的命令都在其中進行了整理

 

回歸正題,我們詳細的了解一下git,一次改變世界的代碼提交

背景

Linux 作為最大也是最成功的開源專案,吸引了全球程式員的貢獻,到目前為止,共有兩萬多名開發者給 Linux Kernel 提交過代碼,

令人驚訝的是,在專案的前十年(1991 ~ 2002)中,Linus 作為專案管理員并沒有借助任何配置管理工具,而是以手工方式通過 patch 來合并大家提交的代碼,倒不是說 Linus 喜歡手工處理,而是因為他對于軟體配置管理工具(SCM)非常挑剔,無論是商用的 clearcase 還是開源的 cvs、svn 等都不能入他的法眼,

在他看來,一個能夠滿足 Linux 內核專案開發使用的版本控制系統需要滿足幾個條件: 1) 快 2)支持多分支場景(幾千個分支并行開發場景) 3) 分布式 4) 能夠支持大型專案,直到2002年,Linus 終于找到了一款基本滿足他要求的工具——BitKeeper, 而 BitKeeper 是商業工具,他們愿意給 Linux 社區免費使用,但是需要保證遵守不得進行反編譯等條款,BitKeeper 提供的默認介面顯然不能滿足社區用戶的全部需要,一位社區開發者反編譯 BitKeeper 并利用了未公開介面,這讓 BitKeeper 公司撤回了免費使用的 License,不得已,Linus 利用假期十天時間,實作一款 DVCS —— Git,并推送給社區開發者們使用,

設計

Git 已經成為全球軟體開發者的標配,關于 Git 的介紹和用法不需多說,我今天想要談談 Git 的內部實作,不過在看本文之前,我先給大家提一個問題:如果是你來設計 git(或者重新設計 git),你打算怎么設計?第一個版本發布準備實作哪些功能?看完本文,再對照自己的想法做個比較,歡迎留言討論,

學習 Git 的內部實作,最好的辦法是看 Linus 最初的代碼提交,checkout 出 git 專案的第一次提交節點(方法參見博客:《閱讀開源代碼小技巧》),可以看到代碼庫中只有幾個檔案:一個 README,一個構建腳本Makefile,剩下幾個 C 源檔案,這次 commit 的備注寫的也非常特別: Initial revision of “git”, the information manager from hell.

commit e83c5163316f89bfbde7d9ab23ca2e25604af290
Author: Linus Torvalds <[email protected]>
Date:   Thu Apr 7 15:13:13 2005 -0700

    Initial revision of "git", the information manager from hell

在 README 中,Linus 詳細描述了 Git 的設計思路,看似復雜的 Git 作業,在 Linus 的設計里,只有兩種物件抽象:1) 物件資料庫(“object database”); 2) 當前目錄快取(“current directory cache”),

Git 的本質就是一系列的檔案物件集合,代碼檔案是物件、檔案目錄樹是物件、commit 也是物件,這些檔案物件的名稱即內容的 SHA1 值,SHA1 哈希演算法的值為40位,Linus 將前二位作為檔案夾、后38位作為檔案名,大家可以在 .git 目錄里的 objects 里看到有很多兩位字母/數字名稱的目錄,里面存盤了很多38位hash值名稱的檔案,這就是 Git 的所有資訊,

Linus 在設計物件的資料結構時按照 <標簽ascii碼表示>(blob/tree/commit) + <空格> + <長度ascii碼表示> + <\0> + <二進制資料內容> 來定義,大家可以用 xxd 命令看下 objects 目錄里的物件檔案(需 zlib 解壓),比如一個 tree 物件檔案內容如下:

00000000: 7472 6565 2033 3700 3130 3036 3434 2068  tree 37.100644 h
00000010: 656c 6c6f 2e74 7874 0027 0c61 1ee7 2c56  ello.txt.'.a..,V
00000020: 7bc1 b2ab ec4c bc34 5bab 9f15 ba         {....L.4[....

物件有三種:BLOB、TREE、CHANGESET,

BLOB: 即二進制物件,這就是 Git 存盤的檔案,Git 不像某些 VCS (如 SVN)那樣存盤變更 delta 資訊,而是存盤檔案在每一個版本的完全資訊,比如先提交了一份 hello.c 進入了 Git 庫,會生成一個 BLOB 檔案完整記錄 hello.c 的內容;對 hello.c 修改后,再提交 commit,會再生成一個新的 BLOB 檔案記錄修改后的 hello.c 全部內容,Linus 在設計時,BLOB 中僅記錄檔案的內容,而不包含檔案名、檔案屬性等元資料資訊,這些資訊被記錄在第二種物件 TREE 里,

TREE: 目錄樹物件,在 Linus 的設計里 TREE 物件就是一個時間切片中的目錄樹資訊抽象,包含了檔案名、檔案屬性及BLOB物件的SHA1值資訊,但沒有歷史資訊,這樣的設計好處是可以快速比較兩個歷史記錄的 TREE 物件,不能讀取內容,而根據 SHA1 值顯示一致和差異的檔案,

另外,由于 TREE 上記錄檔案名及屬性資訊,對于修改檔案屬性或修改檔案名、移動目錄而不修改檔案內容的情況,可以復用 BLOB 物件,節省存盤資源,而 Git 在后來的開發演進中又優化了 TREE 的設計,變成了某一時間點檔案夾資訊的抽象,TREE 包含其子目錄的 TREE 的物件資訊(SHA1),這樣,對于目錄結構很復雜或層級較深的 Git庫 可以節約存盤資源,歷史資訊被記錄在第三種物件 CHANGESET 里,

 

圖片摘自 Pro Git 1

CHANGESET: 即 Commit 物件,一個 CHANGESET 物件中記錄了該次提交的 TREE 物件資訊(SHA1),以及提交者(committer)、提交備注(commit message)等資訊,跟其他SCM(軟體配置管理)工具所不同的是,Git 的 CHANGESET 物件不記錄檔案重命名和屬性修改操作,也不會記錄檔案修改的 Delta 資訊等,CHANGESET 中會記錄父節點 CHANGESET 物件的 SHA1 值,通過比較本節點和父節點的 TREE 資訊來獲取差異,

Linus 在設計 CHANGESET 父節點時允許一個節點最多有 16 個父節點,雖然超過兩個父節點的合并是很奇怪的事情,但實際上,Git 是支持超過兩個分支的多頭合并的,

Linus 在三種物件的設計解釋后著重闡述了可信(TRUST):雖然 Git 在設計上沒有涉及可信的范疇,但 Git 作為配置管理工具是可以做到可信的,原因是所有的物件都以SHA1編碼(Google 實作 SHA1 碰撞攻擊是后話,且 Git 社區也準備使用更高可靠性的 SHA256 編碼來代替),而簽入物件的程序可以靠簽名工具保證,如 GPG 工具等,

理解了Git 的三種基本物件,那么對于 Linus 對于 Git 初始設計的“物件資料庫”和“當前目錄快取”這兩層抽象就很好理解了,加上原本的作業目錄,Git 有三層抽象,如下圖示:一個是當前作業區(Working Directory),也就是我們查看/撰寫代碼的地方,一個是 Git 倉庫(Repository),即 Linus 說的物件資料庫,我們在 Git 倉看到的 .git 檔案夾中存盤的內容,Linus 在第一版設計時命名為 .dircache,在這兩個存盤抽象中還有一層中間的快取區(Staging Area),即 .git/index 里存盤的資訊,我們在執行 git add 命令時,便是將當前修改加入到了快取區,

Linus 解釋了“當前目錄快取”的設計,該快取就是一個二進制檔案,內容結構很像 TREE 物件,與 TREE 物件不同的是 index 不會再包含嵌套 index 物件,即當前修改目錄樹內容都在一個 index 檔案里,這樣設計有兩個好處:1. 能夠快速的復原快取的完整內容,即使不小心把當前作業區的檔案洗掉了,也可以從快取中恢復所有檔案;2. 能夠快速找出快取中和當前作業區內容不一致的檔案,

 

圖片摘自 Things About Git and Github You Need to Know as Developer 2

實作

Linus 在 Git 的第一次代碼提交里便完成了 Git 的最基礎功能,并可以編譯使用,代碼極為簡潔,加上 Makefile 一共只有 848 行,感興趣的同事可以通過上一段所述方法 checkout Git 最早的 commit 上手編譯玩玩,只要有 Linux 環境即可,

因為依賴庫版本的問題,需要對原始 Makefile 腳本做些小修改,Git 第一個版本依賴 openssl 和 zlib 兩個庫,需要手工安裝這兩個開發庫,在 ubuntu 上執行: sudo apt install libssl-dev libz-dev ; 然后修改 makefile 在 LIBS= -lssl 行 中的 -lssl 改成 -lcrypto 并增加 -lz ;最后執行 make,忽略編譯告警,會發現編出了7個可執行程式檔案: init-db, update-cache, write-tree, commit-tree, cat-file, show-diff 和 read-tree.

下面分別簡要介紹下這些可執行程式的實作:

(1)init-db: 初始化一個 git 本地倉庫,這也就是我們現在每次初始化建立 git 庫式敲擊的 git init 命令,只不過一開始 Linus 建立的 倉庫及 cache 檔案夾名稱叫 .dircache, 而不是我們現在所熟知的 .git 檔案夾,

(2)update-cache: 輸入檔案路徑,將該檔案(或多個檔案)加入緩沖區中,具體實作是:校驗路徑合法性,然后將檔案計算 SHA1值,將檔案內容加上 blob 頭資訊進行 zlib 壓縮后寫入到物件資料庫(.dircache/objects)中;最后將檔案路徑、檔案屬性及 blob sha1 值更新到 .dircache/index 快取檔案中,

(3)write-tree: 將快取的目錄樹資訊生成 TREE 物件,并寫入物件資料庫中,TREE 物件的資料結構為: ‘tree ‘ + 長度 + \0 + 檔案樹串列,檔案樹串列中按照 檔案屬性 + 檔案名 + \0 + SHA1 值結構存盤,寫入物件成功后,飯回該 TREE 物件的 SHA1 值,

(4)commit-tree: 將 TREE 物件資訊生成 commit 節點物件并提交到版本歷史中,具體實作是輸入要提交的 TREE 物件 SHA1 值,并選擇輸入父 commit 節點(最多 16個),commit 物件資訊中包含 TREE、父節點、committer 及作者的 name、email及日期資訊,最后寫入新的 commit 節點物件檔案,并回傳 commit 節點的 SHA1 值,

(5)cat-file: 由于所有的物件檔案都經過 zlib 壓縮,因此想要查看檔案內容的話需要使用這個工具來解壓生成臨時檔案,以便查看物件檔案的內容,

(6)show-diff: 快速比較當前快取與當前作業區的差異,因為檔案的屬性資訊(包括修改時間、長度等)也保存在快取的資料結構中,因此可以快速比較檔案是否有修改,并展示差異部分,

(7)read-tree: 根據輸入的 TREE 物件 SHA1 值輸出列印 TREE 的內容資訊,

這就是第一個可用版本的 Git 的全部七個子程式,可能用過 Git 的同事會說:這怎么跟我常用的 Git 命令不一樣呢? Git add, git commit 呢?是的,在最初的 Git 設計中是沒有我們這些平常所使用的 git 命令的,

在 Git 的設計中,有兩種命令:分別是底層命令(Plumbing commands)和高層命令(Porcelain commands),一開始,Linus 就設計了這些給開源社區黑客使用的符合 Unix KISS 原則的命令,因為黑客們本身就是動手高手,水管壞了就擼起袖子去修理,因此這些命令被稱為 plumbing commands. 后來接手 Git 的 Junio Hamano 覺得這些命令對于普通的用戶可不太友好,因此在此之上,封裝了更易于使用、介面更精美的高層命令,也就是我們今天每天使用的 git add, git commit 之類,

Git add 就是封裝了 update-cache 命令,而 git commit 就是封裝了 write-tree, commit-tree 命令,關于底層命令的更詳細介紹,大家有興趣的話可以看 Pro Git 中的 Git Internals 章節,

具體的代碼實作在這里就不再細述,Linus 的代碼風格極為簡潔,能一行完成的絕不寫兩行,另外,對于 Linux API 的使用自然無人出其右,我印象最深的是有好多處使用 mmap 建立檔案與記憶體的映射,省去了記憶體申請、檔案讀寫等操作,提升了工具性能,正如一位同事說的:Linus 的代碼除了不滿足編程規范,其他好像真挑不出什么毛病,順便說一句,Linus 的縮進風格是 Tab 鍵(典故參見《制表符還是空格符,這是個問題》),

啟示

Linus 在提交了第一個 git commit 后,并向社區發布了 git 工具,當時,社區中有位叫 Junio Hamano 的開發者覺得這個工具很有意思,便下載了代碼,結果發現一共才 1244 行代碼,這更令他驚奇也引發了極大的興趣,Junio 在郵件串列與 Linus 交流并幫助增加了 merge 等功能,而后持續打磨 git,最后 Junio 完全接手了 Git 的維護作業,Linus 則回去繼續維護 Linux Kernel 專案,

如果選歷史上最偉大的一次 Git 代碼提交,那一定是這 Git 工具專案本身的第一次代碼提交,這次代碼提交無疑是開創性的,如果說 Linux 專案促成了開源軟體的成功并改寫了軟體行業的格局,那么 Git 則是改變了全世界開發者的作業方式和寫作方式,在 Git 誕生后兩年,舊金山的一個小酒館里坐著三位年輕的程式員,決定要用 Git 做點什么,幾個月后,GitHub 上線,

回歸正題

回到文中開頭提到的問題,如果我來設計 Git 的話,估計還是會從已有工具經驗(如SVN使用)上來延伸設計,甚至在我最早接觸 Git 時候曾膚淺的認為 Git 就是 SVN + 分布式,正是了解了 Git 的內部原理乃至閱讀了 Git 的初始代碼后才感嘆其設計的精妙,Git 的初始設計和實作大概能給(開源)軟體產品如下啟發:

1.解決痛點問題: Git 的緣起便是 Linus 本人及 Linux 社區的訴求,而這些訴求推而廣之是專案協作開發(特別是跨地域專案)的共性訴求,Linus 解決了他本人遇到的痛點問題,順便達成了一項偉大的成就,

2.極簡設計:Linus 在設計 Git 工具時并沒有受傳統 SCM 工具的束縛,考慮檔案差異、版本對比等,而是抽象了幾種基本物件就把 git 的設計思路給理清楚了,

3.MVP (minimum viable product, 最小可用產品):這個概念大家都懂,但實際操作起來卻不容易,一個 MVP 的配置管理工具需要哪些功能?一般來說會想到代碼提交、歷史追溯、版本比較、分支合并等,但 Linus 卻將它拆解開來,快速實作了底層的基本功能,簡單到只有開源社區黑客才能用,但這就夠了,黑客們因此發現了它的價值,繼續給它添磚加瓦,

4.快速發布,快速迭代:這也是源于 Linux Kernel 的開發經驗;Linus 在實作了 Git MVP 后,便在 Linux 社區郵件串列中公布,并征求意見,迭代完善,

5.找到合適接班人:《大教堂與集市》中也有類似的觀點,它說的是:“如果你對一個專案失去了興趣,你最后的職責就是把它交給一個稱職的繼承者,”不過 Linus 將 Git 交給 Junio 并不是因為失去了興趣,而是因為他發現在 Git 基礎架構建立好之后,Junio 比他更擅長于實作更豐富、對普通用戶界面更友好的功能,因此他就放心的將 Git 交給了 Junio. 為開源專案找到更合適的接班人,這既需要魄力也需要智慧,


不知道看完這篇文章后,是不是對于Git有了全新的認知,在我的世界里,任何的技術從來都不是學,而是玩,把技術當作一個興趣,就像喜歡看動漫,看漫畫書一樣,不知不覺間,開開心心的把技術學到手,真的是一個很開心的事情,而且這樣,在大家看來就是每天不務正業,但是技術就是會的很多(我不會說是為了裝X的),被人所羨慕

好啦,基本到這里,對于Git的由來以及內部實作基本講完了,雖然沒多少東西,但是也不得不去羨慕這群大神的腦洞和技術,太狠了,后期造福了多少程式員啊,尤其是現在對于多人團隊協作的開發模式

覺得今天學到東西的,想要相應的知識圖譜的,關注公眾號:Java架構師聯盟,即可查看獲取方式

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/122710.html

標籤:其他

上一篇:Java創建多執行緒的四種方式

下一篇:并列資料排序的問題,急急急

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more