MySQL之Innodb恢復的學習筆記

来源:https://www.cnblogs.com/DataArt/archive/2018/10/29/9873200.html
-Advertisement-
Play Games

MySQL · 引擎特性 · InnoDB 崩潰恢復過程 innodb中的 3個lsn innodb的lsn和oracle的scn一樣,是一個重要的概念。比如 在flush list中正是是使用low lsn作為鏈表的條件參考buf_page_t中的lsn_t oldest_modification ...


MySQL · 引擎特性 · InnoDB 崩潰恢復過程

enum {
    SRV_FORCE_IGNORE_CORRUPT = 1,    /*!< let the server run even if it
                    detects a corrupt page */
    SRV_FORCE_NO_BACKGROUND    = 2,    /*!< prevent the main thread from
                    running: if a crash would occur
                    in purge, this prevents it */
    SRV_FORCE_NO_TRX_UNDO = 3,    /*!< do not run trx rollback after
                    recovery */
    SRV_FORCE_NO_IBUF_MERGE = 4,    /*!< prevent also ibuf operations:
                    if they would cause a crash, better
                    not do them */
    SRV_FORCE_NO_UNDO_LOG_SCAN = 5,    /*!< do not look at undo logs when
                    starting the database: InnoDB will
                    treat even incomplete transactions
                    as committed */
    SRV_FORCE_NO_LOG_REDO = 6    /*!< do not do the log roll-forward
                    in connection with recovery */
};

innodb中的 3個lsn

innodb的lsn和oracle的scn一樣,是一個重要的概念。比如

  • 在flush list中正是是使用low lsn作為鏈表的條件
    參考buf_page_t中的lsn_t oldest_modification;
  • 在checkpoint中記錄的也是lsn
    參考巨集
#define LOG_CHECKPOINT_NO        0
#define LOG_CHECKPOINT_LSN        8
#define LOG_CHECKPOINT_OFFSET        16
#define LOG_CHECKPOINT_LOG_BUF_SIZE    24
  • 在物理文件中每個塊最後的刷新lsn
    參考巨集FIL_PAGE_LSN
  • 在寫日誌落盤的時候也是以lsn為標準的
    參考函數log_write_up_to

實際上lsn就是表示的日誌量的位元組數,是一個累加的值,在5.7中表現為:

/* Type used for all log sequence number storage and arithmetics */
typedef    ib_uint64_t        lsn_t;

及一個8位元組非負的整數。最大值及2的64次方。有了這種物理上概念,lsn很容易換算為當前日誌的偏移量。

下麵描述一下和檢查點相關的幾個lsn

  • ibdata第一個塊FIL中的lsn(flush lsn):ibdata的26後面8位元組是在innodb 乾凈關閉的時候進行更新的,如果不正常關閉不會進行寫入(FIL_PAGE_FILE_FLUSH_LSN)
  • redolog中MLOG_CHECKPOINT的lsn: redolog MLOG_CHECKPOINT lsn的寫入是在每次checkpoint的時候同步寫入的.乾凈關閉會更新。
  • redolog header中的lsn:是在每次checkpoint的時候非同步寫入的在MLOG_CHECKPOINT寫入之後.乾凈關閉會更新。
    我們表示為lsn1/lsn2/lsn3

正常關閉3個lsn是相等的,如果非正常關閉innodb,lsn1不會更新,因此lsn3必然不和lsn1相等,則判定需要進行carsh recovery。

if (checkpoint_lsn != flush_lsn) {

    ......
        if (!recv_needed_recovery) {

            ib::info() << "The log sequence number " << flush_lsn
                << " in the system tablespace does not match"
                " the log sequence number " << checkpoint_lsn
                << " in the ib_logfiles!"; //出現這個警告說明需要恢復了,因為沒有乾凈的關閉資料庫,那麼flush_lsn一定比checkpoint_lsn小

            if (srv_read_only_mode) {
                ib::error() << "Can't initiate database"
                    " recovery, running in read-only-mode.";
                log_mutex_exit();
                return(DB_READ_ONLY);
            }
            recv_init_crash_recovery(); //初始化
        }
    }

MLOG_CHECKPOINT

  • log_checkpoint 函數由master線程調用,以及關閉資料庫的時候調用,不斷的向redo log中寫入MLOG_CHECKPOINT和MLOG_FILE_NAME

log_group_checkpoint 寫入checkpoint信息到log header

#0  mtr_t::commit_checkpoint (this=0x7fff761fb830, checkpoint_lsn=697558445) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/mtr/mtr0mtr.cc:592
#1  0x0000000001ceb4b9 in fil_names_clear (lsn=697558445, do_write=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/fil/fil0fil.cc:7067
#2  0x0000000001a521cc in log_checkpoint (sync=true, write_always=false) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1927
#3  0x0000000001b856f2 in srv_master_do_idle_tasks () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2596
#4  0x0000000001b85b6b in srv_master_thread (arg=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2744
#5  0x0000003f74807aa1 in start_thread () from /lib64/libpthread.so.0
#6  0x0000003f740e8bcd in clone () from /lib64/libc.so.6

正常innodb運行的情況下 checkpoint是由master線程觸發。我們知道臟數據通過page clean線程和lru manager線程是在不斷寫盤的,那麼在進行異常重啟的的時候我們必須要知道一個恢復的起點,但是這個起點是不能記錄在記憶體中必要固化到磁碟,恢復的時候讀取這個點以後的redo進行恢復,而checkpoint就是完成這個事情下麵是checkpoint的執行流程。

正常情況下master會每秒進行檢查點其作用有:(參考log_checkpoint函數)
1、檢查是否有自上次檢查點以來的臟數據寫盤了
2、如果有則在redo裡面會為每個修改過的文件寫入MLOG_FILE_NAME,完成後寫入一個總的MLOG_CHECKPOINT(參考fil_names_clear函數)
MLOG_FILE_NAME主要記錄至上次檢查點以來更改過的數據文件
MLOG_CHECKPOINT主要記錄檢查點的lsn
3、如果有則在redo header中寫入相應的檢查點信息包含(非同步寫)(參考log_group_checkpoint函數)

Log sequence number 697794162
Log flushed up to 697794162
Pages flushed up to 697794162
Last checkpoint at 697794153

697794162-697794153 = 9 剛好是MLOG_CHECKPOINT的長度
oldest_lsn <= log_sys->last_checkpoint_lsn + SIZE_OF_MLOG_CHECKPOINT 
SIZE_OF_MLOG_CHECKPOINT=9

redo的寫入有6個途徑:
1、master 線程每秒調用 棧幀(可能是idle可能是active 和檢測是否需要插入緩存合併有關)
2、master 線程每秒checkpoint調用 (可能是idle可能是active 和檢測是否需要插入緩存合併有關)
3、page clean 線程調用 棧幀 / Force the log to the disk before writing the modified block /
4、主線程commit 調用 棧幀
5、innodb shutdown
6、redo buffer不足

1、master線程調用 棧幀(可能是idle可能是active 和檢測是否需要插入緩存合併有關)

#0  log_group_write_buf (group=0x33f29f8, buf=0x7fffa5b38000 "\200\024", len=512, pad_len=0, start_lsn=697764864, new_data_offset=166)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145
#1  0x0000000001a50f95 in log_write_up_to (lsn=697765068, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493
#2  0x0000000001a51163 in log_buffer_sync_in_background (flush=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1553
#3  0x0000000001b84bd1 in srv_sync_log_buffer_in_background () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2312
#4  0x0000000001b85666 in srv_master_do_idle_tasks () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2586
#5  0x0000000001b85b6b in srv_master_thread (arg=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2744

2、master 線程checkpoint調用 (可能是idle可能是active 和檢測是否需要插入緩存合併有關)

#0  log_group_write_buf (group=0x33f29f8, buf=0x7fffa5a38000 "\200\024\002", len=1024, pad_len=0, start_lsn=697789952, new_data_offset=139)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145
#1  0x0000000001a50f95 in log_write_up_to (lsn=697790725, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493
#2  0x0000000001a52247 in log_checkpoint (sync=true, write_always=false) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1934
#3  0x0000000001b856f2 in srv_master_do_idle_tasks () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2596
#4  0x0000000001b85b6b in srv_master_thread (arg=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0srv.cc:2744

3、page clean 線程調用 棧幀 / Force the log to the disk before writing the modified block /

#0  log_group_write_buf (group=0x33f29f8, buf=0x7fffa5a38000 "\200\024\002", len=13312, pad_len=1024, start_lsn=697778176, new_data_offset=468)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145
#1  0x0000000001a50f95 in log_write_up_to (lsn=697790015, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493
#2  0x0000000001c704c7 in buf_flush_write_block_low (bpage=0x7fffc0cae940, flush_type=BUF_FLUSH_LIST, sync=false)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1035
#3  0x0000000001c70cea in buf_flush_page (buf_pool=0x33247d8, bpage=0x7fffc0cae940, flush_type=BUF_FLUSH_LIST, sync=false)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1237
#4  0x0000000001c717f4 in buf_flush_try_neighbors (page_id=..., flush_type=BUF_FLUSH_LIST, n_flushed=0, n_to_flush=25)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1466
#5  0x0000000001c71b57 in buf_flush_page_and_try_neighbors (bpage=0x7fffc0cae940, flush_type=BUF_FLUSH_LIST, n_to_flush=25, count=0x7fffa02867c0)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1558
#6  0x0000000001c72862 in buf_do_flush_list_batch (buf_pool=0x33247d8, min_n=25, lsn_limit=18446744073709551615)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1846
#7  0x0000000001c72cb6 in buf_flush_batch (buf_pool=0x33247d8, flush_type=BUF_FLUSH_LIST, min_n=25, lsn_limit=18446744073709551615)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:1926
#8  0x0000000001c73104 in buf_flush_do_batch (buf_pool=0x33247d8, type=BUF_FLUSH_LIST, min_n=25, lsn_limit=18446744073709551615, n_processed=0x7fffa0286938)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:2071
#9  0x0000000001c734ee in buf_flush_lists (min_n=25, lsn_limit=18446744073709551615, n_processed=0x7fffa02869c8)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:2202
#10 0x0000000001c76a97 in buf_flush_page_cleaner_coordinator (arg=0x0) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/buf/buf0flu.cc:3362

4、主線程commit 調用 棧幀

#0  log_group_write_buf (group=0x33f29f8, buf=0x7fffa5a38000 "\200\024\002", len=2560, pad_len=0, start_lsn=697762816, new_data_offset=230)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1145
#1  0x0000000001a50f95 in log_write_up_to (lsn=697765030, flush_to_disk=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1493
#2  0x0000000001a51087 in log_buffer_flush_to_disk (sync=true) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:1524
#3  0x00000000019a9157 in innobase_flush_logs (hton=0x2e9fdd0, binlog_group_flush=true)
    at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/handler/ha_innodb.cc:4407
#4  0x0000000000f65893 in flush_handlerton (thd=0x0, plugin=0x7ffff03588e8, arg=0x7ffff0358944) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/handler.cc:2606
#5  0x00000000015d7716 in plugin_foreach_with_mask (thd=0x0, func=0xf65835 <flush_handlerton(THD*, plugin_ref, void*)>, type=1, state_mask=4294967287, 
    arg=0x7ffff0358944) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:2318
#6  0x0000000000f658ef in ha_flush_logs (db_type=0x0, binlog_group_flush=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/handler.cc:2617
#7  0x000000000185733d in MYSQL_BIN_LOG::process_flush_stage_queue (this=0x2e02c80, total_bytes_var=0x7ffff0358a88, rotate_var=0x7ffff0358a87, 
    out_queue_var=0x7ffff0358a78) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8541
#8  0x000000000185899f in MYSQL_BIN_LOG::ordered_commit (this=0x2e02c80, thd=0x7fff2c000b70, all=false, skip_commit=false)
    at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:9189
#9  0x000000000185700c in MYSQL_BIN_LOG::commit (this=0x2e02c80, thd=0x7fff2c000b70, all=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8440
#10 0x0000000000f63df8 in ha_commit_trans (thd=0x7fff2c000b70, all=false, ignore_global_read_lock=false)

入口函數
innobase_start_or_create_for_mysql

recv_recovery_from_checkpoint_start

1、此函數需要輸入flush的lsn及臟數據寫入到的位置

這個數據從FIL_PAGE_FILE_FLUSH_LSN中讀取,這個值
只在ibdata的第一個page有效其他均為0,他的讀取來自於
函數Datafile::validate_first_page,
其中
*flush_lsn = mach_read_from_8(
m_first_page + FIL_PAGE_FILE_FLUSH_LSN);


其寫入由函數  正常shutdown才會寫入,非正常關閉不會寫入,正常運行檢查點也不會寫入
fil_write_flushed_lsn 寫入
mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);

棧幀
    #0  fil_write_flushed_lsn (lsn=696973727) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/fil/fil0fil.cc:1946
    #1  0x0000000001a538a7 in logs_empty_and_mark_files_at_shutdown () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/log/log0log.cc:2464
    #2  0x0000000001b915a9 in innobase_shutdown_for_mysql () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0start.cc:2803
    #3  0x00000000019a8ffc in innobase_end (hton=0x2e9edd0, type=HA_PANIC_CLOSE) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/handler/ha_innodb.cc:4360
    #4  0x0000000000f62621 in ha_finalize_handlerton (plugin=0x3015cd0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/handler.cc:813
    #5  0x00000000015d3d25 in plugin_deinitialize (plugin=0x3015cd0, ref_check=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:995
    #6  0x00000000015d410e in reap_plugins () at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:1077
    #7  0x00000000015d6073 in plugin_shutdown () at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:1845
    #8  0x0000000000ebf7eb in clean_up (print_message=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:1336
    #9  0x0000000000ec701b in mysqld_main (argc=98, argv=0x2e9cf08) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5386
    #10 0x0000000000ebd604 in main (argc=10, argv=0x7fffffffe458) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25

2、此函數首先建立紅黑樹用於恢復並且做 force recovery判斷

   (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) 
   然後調用 
   recv_find_max_checkpoint 此函數就是找到最大的checkpoint lsn、redo文件,以及field 就是相對於一個日誌而講所在的offset set (512*1 or 512*3)_
   讀取如下:
                   group->lsn = mach_read_from_8(
                  buf + LOG_CHECKPOINT_LSN);
                group->lsn_offset = mach_read_from_8(
                  buf + LOG_CHECKPOINT_OFFSET);
                checkpoint_no = mach_read_from_8(
                  buf + LOG_CHECKPOINT_NO);

3、recv_group_scan_log_recs

   迴圈讀取64K(RECV_SCAN_SIZE)日誌到redo buffer(log_group_read_log_seg)
   recv_scan_log_recs
     本函數將64K 的redo 通過每個512 bytes block大小迴圈加入到(recv_sys_add_to_parsing_buf) 掃描到parse buffer 
     代碼片段拷貝
          ut_memcpy(recv_sys->buf + recv_sys->len,
              log_block + start_offset, end_offset - start_offset);
            
           當每次掃描了64K*80的日誌量的時候會輸出,級5M
           ib::info() << "Doing recovery: scanned up to"
                " log sequence number " << scanned_lsn;
     並且進行分析對這加入到 parse buffer的日誌進行分析(recv_parse_log_recs) /其中parse buffer 為2M(巨集RECV_PARSING_BUF_SIZE大小)
        recv_parse_log_recs函數對每次加入 parse buffer的64k進行分析主要分析是MLOG_SINGLE_REC_FLAG還是MLOG_MULTI_REC_END 同時確認MLOG_MULTI_REC_END
        是否完整,完成後加入到hash table,函數是調用recv_parse_log_rec進行 (type spaceid page_no data)的剝離。 

那麼recv_group_scan_log_recs為第一層迴圈,迴圈掃描64K日誌到redo buffer
然後調用recv_scan_log_recs以block單位(512b)大小迴圈加入到parse buffer,這是通過函數recv_sys_add_to_parsing_buf完成
等到64k加入到parse buffer後調用recv_parse_log_recs函數對每次加入 parse buffer的64k進行分析,分析是迴圈以record為單位的,主要分析MLOG_SINGLE_REC_FLAG還是MLOG_MULTI_REC_END,同時確保MLOG_MULTI_REC_END記錄是完整的。完成後recv_parse_log_recs函數 還要將其加入到hash table函數為recv_add_to_hash_table,本函數是通過recv_parse_log_rec進行 (type spaceid page_no data)的剝離。

recv_apply_hashed_log_recs 最後完成分析完成後的日誌應用,從hash table中


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • lvs: Linux Virtual Server l4:四層交換;四層路由; 根據請求報文的目標IP和PORT將其轉發至後端主機集群中的某一臺主機(根據挑選演算法); netfilter: PREROUTING --> INPUT PREROUTING --> FORWARD --> POSTROU ...
  • 概念 簡稱brew,是Mac OSX上的軟體包管理工具,能在Mac中方便的安裝軟體或者卸載軟體,相當於Red hat的yum、Ubuntu的apt get。 安裝命令 ruby e "$(curl fsSL "https://raw.githubusercontent.com/Homebrew/in ...
  • #本文並非原創,屬於本人學習中的記錄筆記或是轉存筆記,如果涉及到哪位高人的創作權益,敬請海涵! Vim 是一個上古神器,本篇文章主要持續總結使用 Vim 的過程中不得不瞭解的一些指令和註意事項,以及持續分享一個前端工作者不得不安裝的一些插件,而關於 Vim 的簡介,主題的選擇,以及為何使用 vim- ...
  • 本章主要講解了section header的定義,各欄位含義和可能的取值。然後介紹了系統預定義的一些section名稱。最後我們綜合運用第二章和第三章的知識,做了一個讀取section names的練習。 ...
  • Redis集群實現了較為完善的高可用方案。本文將詳細介紹集群,主要內容包括:集群的作用;集群的搭建以及設計方案;集群的基本原理;客戶端訪問集群的方法;以及其他實踐中需要的集群知識。 ...
  • 《大數據時代》是國外大數據研究的先河之作,本書作者維克托•邁爾•舍恩伯格被譽為“大數據商業應用第一人”,擁有在哈佛大學、牛津大學、耶魯大學和新加坡國立大學等多個互聯網研究重鎮任教的經歷,早在2010年就在《經濟學人》上發佈了長達14頁對大數據應用的前瞻性研究。 維克托•邁爾•舍恩伯格在書中前瞻性地指 ...
  • 下載mysql安裝程式 官方下載地址:http://dev.mysql.com/downloads/mysql/ 解壓下載文件,如圖 其中data和my.ini文件需要自己創建 my.ini 文件配置如下: 配置環境變數 電腦 屬性 高級系統屬性 環境變數 初始化data目錄 以管理員命令運行cmd ...
  • 1. 基礎知識 安裝mysql5.6資料庫Mysql binlog初步理解 2. 配置mysql 開啟binlog、修改binlog模式為Row Level模式 修改mysql配置文件,在[mysqld]下增加以下內容 3. 重啟mysql資料庫 binlog開啟 生成文件/var/lib/mysq ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...