主頁 > 後端開發 > 使用Python決議并“篡改”MySQL的Binlog

使用Python決議并“篡改”MySQL的Binlog

2020-10-01 09:06:43 後端開發

文章目錄

  • 前言
  • Binlog的結構
  • 恢復誤洗掉的記錄
  • 找出 Binlog 中的大事務
  • 切割 Binlog 中的大事務
  • 后記

前言

MySQL 的 Binlog 記錄著 MySQL 資料庫的所有變更資訊,了解 Binlog 的結構可以幫助我們決議Binlog,甚至對 Binlog 進行一些修改,或者說是“篡改”,例如實作類似于 Oracle 的 flashback 的功能,恢復誤洗掉的記錄,把 update 的記錄再還原回去等,本文將帶您探討一下這些神奇功能的實作,您會發現比您想象地要簡單得多,本文指的 Binlog 是 ROW 模式的 Binlog,這也是 MySQL 8 里的默認模式,STATEMENT 模式因為使用中有很多限制,現在用地越來越少了,

Binlog的結構

Binlog由事件(event)組成,請注意是事件(event)不是事務(transaction),一個事務可以包含多個事件,事件描述對資料庫的修改內容,
從 MySQL 5 版本開始,Binlog 采用的是 v4 版本,事件的型別根據 MySQL 的內部檔案,有下面36類:

enum Log_event_type { 
  UNKNOWN_EVENT= 0, 
  START_EVENT_V3= 1, 
  QUERY_EVENT= 2, 
  STOP_EVENT= 3, 
  ROTATE_EVENT= 4, 
  INTVAR_EVENT= 5, 
  LOAD_EVENT= 6, 
  SLAVE_EVENT= 7, 
  CREATE_FILE_EVENT= 8, 
  APPEND_BLOCK_EVENT= 9, 
  EXEC_LOAD_EVENT= 10, 
  DELETE_FILE_EVENT= 11, 
  NEW_LOAD_EVENT= 12, 
  RAND_EVENT= 13, 
  USER_VAR_EVENT= 14, 
  FORMAT_DESCRIPTION_EVENT= 15, 
  XID_EVENT= 16, 
  BEGIN_LOAD_QUERY_EVENT= 17, 
  EXECUTE_LOAD_QUERY_EVENT= 18, 
  TABLE_MAP_EVENT = 19, 
  PRE_GA_WRITE_ROWS_EVENT = 20, 
  PRE_GA_UPDATE_ROWS_EVENT = 21, 
  PRE_GA_DELETE_ROWS_EVENT = 22, 
  WRITE_ROWS_EVENT = 23, 
  UPDATE_ROWS_EVENT = 24, 
  DELETE_ROWS_EVENT = 25, 
  INCIDENT_EVENT= 26, 
  HEARTBEAT_LOG_EVENT= 27, 
  IGNORABLE_LOG_EVENT= 28,
  ROWS_QUERY_LOG_EVENT= 29,
  WRITE_ROWS_EVENT = 30,
  UPDATE_ROWS_EVENT = 31,
  DELETE_ROWS_EVENT = 32,
  GTID_LOG_EVENT= 33,
  ANONYMOUS_GTID_LOG_EVENT= 34,
  PREVIOUS_GTIDS_LOG_EVENT= 35, 
  ENUM_END_EVENT 
  /* end marker */ 
};

每個 Binlog 檔案總是以 Format Description Event 作為開始,以 Rotate Event 結束作為結束,我們來看一個 Binlog 的例子:

mysql>  show binlog events in 'scut.000023';
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| Log_name    | Pos | Event_type     | Server_id | End_log_pos | Info                                                   |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| scut.000023 |   4 | Format_desc    |      1024 |         123 | Server ver: 5.7.31-0ubuntu0.16.04.1-log, Binlog ver: 4 |
| scut.000023 | 123 | Previous_gtids |      1024 |         154 |                                                        |
| scut.000023 | 154 | Anonymous_Gtid |      1024 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                   |
| scut.000023 | 219 | Query          |      1024 |         291 | BEGIN                                                  |
| scut.000023 | 291 | Rows_query     |      1024 |         330 | # delete from tt1                                      |
| scut.000023 | 330 | Table_map      |      1024 |         378 | table_id: 111 (test.tt1)                               |
| scut.000023 | 378 | Delete_rows    |      1024 |         434 | table_id: 111 flags: STMT_END_F                        |
| scut.000023 | 434 | Xid            |      1024 |         465 | COMMIT /* xid=216 */                                   |
| scut.000023 | 465 | Rotate         |      1024 |         507 | scut.000024;pos=4                                      |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
9 rows in set (0.00 sec)

關于“show binlog events”語法顯示的每一列的作用說明如下:

列名說明
Log_name當前事件所在的 binlog 檔案名稱
Pos當前事件的開始位置,每個事件都占用固定的位元組大小,結束位置(End_log_position)減去Pos,就是這個事件占用的位元組數,
Event_type表示事件的型別
Server_id表示產生這個事件的 MySQL server_id
End_log_position下一個事件的開始位置
Info當前事件的描述資訊

每個事件型別的說明可以參考 MySQL 的內部檔案,我們這里說明一下這里遇到的幾個事件型別:

事件名說明
Format_desc是 binlog 檔案的第一個事件,在 Info 列,我們可以看到,其標明了 MySQL Server 的版本是5.7.31, Binlog 版本是4,
Previous_gtids這是表示之前的 Binlog 檔案中,已經執行過的 GTID,需要我們開啟 GTID 選項,這個事件才會有值,
Anonymous_Gtid沒有開啟 GTID 選項時,每個事務開始的事件;
Query是向 Binlog 發生一個陳述句,這里是事務的開始陳述句 begin,
Rows_query記錄SQL,這個事件只有當引數 binlog_rows_query_log_events 為 TRUE 的情況下才會產生,這個引數的默認為值為 FALSE,
Table_map記錄將要被修改的表的結構
Delete_rows從表中洗掉一個記錄
Xid事務 commit 的時候寫入事務 ID
RotateRotate Event是每個Binlog檔案的結束事件,在Info列中,我們看到了其指定了下一個 Binlog檔案的名稱是 mysql-bin.000018,

根據官方檔案,事件(event)資料結構如下:

+=====================================+
| event  | timestamp         0 : 4    |
| header +----------------------------+
|        | type_code         4 : 1    |
|        +----------------------------+
|        | server_id         5 : 4    |
|        +----------------------------+
|        | event_length      9 : 4    |
|        +----------------------------+
|        | next_position    13 : 4    |
|        +----------------------------+
|        | flags            17 : 2    |
|        +----------------------------+
|        | extra_headers    19 : x-19 |
+=====================================+
| event  | fixed part        x : y    |
| data   +----------------------------+
|        | variable part              |
+=====================================+

恢復誤洗掉的記錄

現在我們已經了解了 Binlog 的結構,我們可以試著修改 Binlog 里的資料,例如前面舉例的 Binlog 洗掉了一條記錄,我們可以試著把這條記錄恢復,Binlog 里面有個洗掉行(DELETE_ROWS_EVENT)的事件,就是這個事件洗掉了記錄,這個事件和寫行(WRITE_ROWS_EVENT)的事件的資料結構是完全一樣的, 只是洗掉行事件的型別是32,寫行事件的型別是30,我們把對應的 Binlog 位置的32改成30即可把已經洗掉的記錄再插入回去,從前面的“show binlog events”里面可看到這個 DELETE_ROWS_EVENT 是從位置378開始的,這里的位置就是 Binlog 檔案的實際位置(以位元組為單位),從事件(event)的結構里面可以看到 type_code 是在 event 的第5個位元組,我們寫個 Python 小程式把把第383(378+5=383)位元組改成30即可,當然您也可以用二進制編輯工具來改,下面是這個 Python 小程式的例子:

#! /usr/bin/python3
import sys

if len(sys.argv) != 3:
        print ('Please run chtype.py inputType changedType.')
        sys.exit()

inputType=open(sys.argv[1],"rb")
changedType=open(sys.argv[2],"wb")

changedType.write(inputType.read(382))
changedType.write(chr(30).encode())
inputType.seek(1,1)
while True:
  line = inputType.readline()  
  if not line:
        break
  changedType.write(line)
  
inputType.close()
changedType.close()

我們把原來的 Binlog 和修改后的 Binlog 進行一個對比:
Binlog 修改對比

發現這兩個 Binlog只有一個位元組有區別,也就是 type_code 從32變成了30,注意 Binlog 里面顯示的是16進制的數字,
我們分別應用一下原來的 Binlog 和修改后的 Binlog,看看效果如何?

$ mysql  -e "select * from test.tt1";
$ mysqlbinlog ./scut.000023_ch |mysql
$ mysql  -e "select * from test.tt1";
+---------------------+
| col1                |
+---------------------+
| aaaaaaaaaaaaaaaaaaa |
+---------------------+
$ mysqlbinlog ./scut.000023 |mysql
$ mysql  -e "select * from test.tt1";
$ mysqlbinlog ./scut.000023_ch |mysql
$ mysql  -e "select * from test.tt1";
+---------------------+
| col1                |
+---------------------+
| aaaaaaaaaaaaaaaaaaa |
+---------------------+

我們發現這兩個 Binlog 可以分別把對應的記錄洗掉和插入到 MySQL 資料庫中,這樣我們就成功地實作了類似于 Oracle 的 flashback 功能,

找出 Binlog 中的大事務

由于 ROW 模式的 Binlog 是每一個變更都記錄一條日志,因此一個簡單的 SQL,在 Binlog 里可能會產生一個巨無霸的事務,例如一個不帶 where 的 update 或 delete 陳述句,修改了全表里面的所有記錄,每條記錄都在 Binlog 里面記錄一次,結果是一個巨大的事務記錄,這樣的大事務經常是產生麻煩的根源,我的一個客戶有一次向我抱怨,一個 Binlog 前滾,滾了兩天也沒有動靜,我把那個 Binlog 決議了一下,發現里面有個事務產生了 1.4G 的記錄,修改了66萬條記錄!下面是一個簡單的找出 Binlog 中大事務的 Python 小程式,我們知道用 mysqlbinlog 決議的 Binlog,每個事務都是以BEGIN 開頭,以 COMMIT 結束,我們找出 BENGIN 前面的“# at”的位置,檢查 COMMIT 后面的“# at”位置,這兩個位置相減即可計算出這個事務的大小,下面是這個 Python程式的例子,

$ cat ./checkBigTran.py 
#! /usr/bin/python3
import sys

position=0
beginPosition=0
endPosition=0
maxSize=0
isEnd=0
for line in sys.stdin:
      if line[: 4]=='# at':
          position=int(line[5:])
          if isEnd:
             endPosition=position
             isEnd=0
      if line[: 5]=='BEGIN':
          beginPosition=position
      if line[: 6]=='COMMIT':
          isEnd=1
      if endPosition-beginPosition>maxSize:
          maxBeginPosition= beginPosition
          maxEndPosition=endPosition
          maxSize=endPosition-beginPosition

print("The largest transaction size is %d, the begion position is %d, the end position is %d." % (maxSize,maxBeginPosition,maxEndPosition))

用這個小程式檢查一下可能包含大事務的 Binlog:

$ mysqlbinlog binlog1|./checkBigTran.py 
The largest transaction size is 1468183501, the begion position is 5737766, the end position is 1473921267.

發現里面果然包含了一個1.4G的大事務,

切割 Binlog 中的大事務

對于大的事務, MySQL 會把它分解成多個事件(注意一個是事務TRANSACTION,另一個是事件EVENT),事件的大小由引數 binlog-row-event-max-size 決定,這個引數默認是8K,因此我們可以把若干個事件切割成一個單獨的略小的事務,例如下面這個 Binlog:

mysql> show binlog events in 'scut.000025';
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| Log_name    | Pos | Event_type     | Server_id | End_log_pos | Info                                                   |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
| scut.000025 |   4 | Format_desc    |      1024 |         123 | Server ver: 5.7.31-0ubuntu0.16.04.1-log, Binlog ver: 4 |
| scut.000025 | 123 | Previous_gtids |      1024 |         154 |                                                        |
| scut.000025 | 154 | Anonymous_Gtid |      1024 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                   |
| scut.000025 | 219 | Query          |      1024 |         291 | BEGIN                                                  |
| scut.000025 | 291 | Rows_query     |      1024 |         343 | # insert into tt1 values ('1')                         |
| scut.000025 | 343 | Table_map      |      1024 |         391 | table_id: 111 (test.tt1)                               |
| scut.000025 | 391 | Write_rows     |      1024 |         429 | table_id: 111 flags: STMT_END_F                        |
| scut.000025 | 429 | Rows_query     |      1024 |         481 | # insert into tt1 values ('2')                         |
| scut.000025 | 481 | Table_map      |      1024 |         529 | table_id: 111 (test.tt1)                               |
| scut.000025 | 529 | Write_rows     |      1024 |         567 | table_id: 111 flags: STMT_END_F                        |
| scut.000025 | 567 | Xid            |      1024 |         598 | COMMIT /* xid=397 */                                   |
| scut.000025 | 598 | Rotate         |      1024 |         640 | scut.000026;pos=4                                      |
+-------------+-----+----------------+-----------+-------------+--------------------------------------------------------+
12 rows in set (0.01 sec)

這個 Binlog 的兩個 insert 是在一個事務里面完成的,我們可以兩個事務之間插入 xid、Anonymous_Gtid, Query 等三個事件把一個事務切割成兩個事務, Rows_query 這個事件不用插入,這個事件是注釋掉了的,記錄的是執行的 SQL,這個事件只有在引數 binlog_rows_query_log_events 為 on 時才會有,默認是 off ,相應的 Python 程式如下:

# cat splitTran.py 
#! /usr/bin/python3
import sys

if len(sys.argv) != 3:
    print ('Please run splitTrans.py inputBinlog changedBinlog.')
    sys.exit()

inputBinlog=open(sys.argv[1],"rb")
changedBinlog=open(sys.argv[2],"wb")

changedBinlog.write(inputBinlog.read(429))   # read from the head of  input binlog file to the first insert, then write into the changed binlog file.
firstInsert=inputBinlog.tell()
inputBinlog.seek(567,0)  # locate to the xid event
changedBinlog.write(inputBinlog.read(31))  # read from 567 to 598, write xid event, into the changed binlog file.
inputBinlog.seek(154,0)  # locate to the Anonymous_Gtid, Query events.
changedBinlog.write(inputBinlog.read(137))  # read from 154 to 291, write Anonymous_Gtid, Query events into changed binlog file.
inputBinlog.seek(firstInsert)
while True:
      line = inputBinlog.readline()  
      if not line:
           break
      changedBinlog.write(line)
  
inputBinlog.close()
changedBinlog.close()

我們執行這個 Python 程式,生成一個新的 Binlog ,然后把新的 Binlog 應用到 MySQL,

$  ./splitTran.py scut.000025 scut.000025_ch
$ mysqlbinlog scut.000025_ch |mysql
$ 

我們看看執行地效果:


mysql> show binlog events in 'scut.000026';
+-------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------------------------------------------------------------------+
| Log_name    | Pos | Event_type     | Server_id | End_log_pos | Info                                                                                                                               |
+-------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------------------------------------------------------------------+
| scut.000026 |   4 | Format_desc    |      1024 |         123 | Server ver: 5.7.31-0ubuntu0.16.04.1-log, Binlog ver: 4                                                                             |
| scut.000026 | 123 | Previous_gtids |      1024 |         154 |                                                                                                                                    |
| scut.000026 | 154 | Anonymous_Gtid |      1024 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                               |
| scut.000026 | 219 | Query          |      1024 |         287 | BEGIN                                                                                                                              |
| scut.000026 | 287 | Rows_query     |      1024 |         439 | # BINLOG '
EbA7XxMABAAAMAAAAIcBAAAAAG8AAAAAAAEABHRlc3QAA3R0MQAB/gL+QAEYYumN
EbA7Xx4ABAAAJgAAAK0BAAAAAG8AAAAAAAEAAgAB//4BMeeyFcw=
' |
| scut.000026 | 439 | Table_map      |      1024 |         487 | table_id: 111 (test.tt1)                                                                                                           |
| scut.000026 | 487 | Write_rows     |      1024 |         525 | table_id: 111 flags: STMT_END_F                                                                                                    |
| scut.000026 | 525 | Xid            |      1024 |         556 | COMMIT /* xid=425 */                                                                                                               |
| scut.000026 | 556 | Anonymous_Gtid |      1024 |         621 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                               |
| scut.000026 | 621 | Query          |      1024 |         689 | BEGIN                                                                                                                              |
| scut.000026 | 689 | Rows_query     |      1024 |         841 | # BINLOG '
F7A7XxMABAAAMAAAABECAAAAAG8AAAAAAAEABHRlc3QAA3R0MQAB/gL+QAE+WKbj
F7A7Xx4ABAAAJgAAADcCAAAAAG8AAAAAAAEAAgAB//4BMmfP2Zk=
' |
| scut.000026 | 841 | Table_map      |      1024 |         889 | table_id: 111 (test.tt1)                                                                                                           |
| scut.000026 | 889 | Write_rows     |      1024 |         927 | table_id: 111 flags: STMT_END_F                                                                                                    |
| scut.000026 | 927 | Xid            |      1024 |         958 | COMMIT /* xid=432 */                                                                                                               |
+-------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------------------------------------------------------------------+
14 rows in set (0.00 sec)

我們看到兩個 insert 已經分開到兩個事務里面了,

后記

ROW模式下,即使我們只更新了一條記錄的其中某個欄位,也會記錄每個欄位變更前后的值,這個行為是 binlog_row_image 引數控制的,這個引數有3個值,默認為FULL,也就是記錄列的所有修改,即使欄位沒有發生變更也會記錄,這樣我們就可以實作類似 Oracle 的 flashback 的功能,我個人估計 MySQL 未來的版本從可能會基于 Binlog 推出這樣的功能,
了解了 Binlog 的結構,再加上 Python 這把瑞士軍刀,我們還可以實作很多功能,例如我們可以統計哪個表被修改地最多? 我們還可以把 Binlog 切割成一段一段的,然后再重組,可以靈活地進行 MySQL 資料庫的修改和遷移等作業,

姚遠2018 CSDN認證博客專家 10G OCM 12C OCM
Oracle10g,12c OCM; MySQL 5.6,5.7,8.0 OCP;CCNA; EMC Certified; IBM P Certified; RHCE; SQLServer 764; DB2 Certified; TOEIC 890;獲得過兩次國家部級科技進步獎;發明過兩項計算機專利,

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

標籤:python

上一篇:深入oracle索引,磁區

下一篇:MySQL8.0基本操作以及進階操作

標籤雲
其他(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