資料庫操作 —— 使用進階:通過查詢構建器實現高級功能

来源:https://www.cnblogs.com/zmdComeOn/archive/2018/12/29/10196968.html
-Advertisement-
Play Games

簡介 資料庫查詢構建器提供了一個方便的流介面用於創建和執行資料庫查詢。查詢構建器可以用於執行應用中絕大部分資料庫操作,並且能夠在 Laravel 支持的所有資料庫系統上工作。 註:流介面是一種設計模式,更多關於流介面模式的設計和使用方式,可查看這篇教程:PHP 設計模式系列 —— 流介面模式。 La ...


簡介

資料庫查詢構建器提供了一個方便的流介面用於創建和執行資料庫查詢。查詢構建器可以用於執行應用中絕大部分資料庫操作,並且能夠在 Laravel 支持的所有資料庫系統上工作。

註:流介面是一種設計模式,更多關於流介面模式的設計和使用方式,可查看這篇教程:PHP 設計模式系列 —— 流介面模式

Laravel 查詢構建器使用 PDO 參數綁定來避免 SQL 註入攻擊,不再需要過濾以綁定方式傳遞的字元串。

獲取結果集

從一張表中取出所有行

我們可以從 DB 門面的 table 方法開始,table 方法為給定表返回一個流式查詢構建器實例,該實例允許你在查詢上鏈接多個約束條件並返回最終查詢結果。在本例中,我們使用 get 方法獲取表中所有記錄:

 1 <?php
 2 
 3 namespace App\Http\Controllers;
 4 
 5 use Illuminate\Support\Facades\DB;
 6 use App\Http\Controllers\Controller;
 7 
 8 class UserController extends Controller
 9 {
10     /**
11      * 顯示用戶列表
12      *
13      * @return Response
14      */
15     public function index()
16     {
17         $users = DB::table('users')->get();
18         return view('user.index', ['users' => $users]);
19     }
20 }

get 方法返回包含結果集的 Illuminate\Support\Collection,其中每一個結果都是 PHP 的 StdClass 對象實例:

你可以像訪問對象的屬性一樣訪問欄位的值:

1 foreach ($users as $user) {
2     echo $user->name;
3 }

從一張表中獲取一行/一列

如果你只是想要從數據表中獲取一行數據,可以使用 first 方法,該方法將會返回單個 StdClass 對象:

1 $user = DB::table('users')->where('name', 'John')->first();
2 echo $user->name;

如果你不需要完整的一行,可以使用 value 方法從結果中獲取單個值,該方法會直接返回指定列的值:

1 $email = DB::table('users')->where('name', 'John')->value('email');

獲取數據列值列表

如果想要獲取包含單個列值的數組,可以使用 pluck 方法,在本例中,我們獲取角色標題數組:

$titles = DB::table('roles')->pluck('title');

foreach ($titles as $title) {
    echo $title;
}

還可以在返回數組中為列值指定自定義鍵(該自定義鍵必須是該表的其它欄位列名,否則會報錯):

$roles = DB::table('roles')->pluck('title', 'name');

foreach ($roles as $name => $title) {
    echo $title;
}

組塊結果集

如果你需要處理成千上百條資料庫記錄,可以考慮使用 chunk 方法,該方法一次獲取結果集的一小塊,然後傳遞每一小塊數據到閉包函數進行處理,該方法在編寫處理大量資料庫記錄的 Artisan 命令的時候非常有用。例如,我們可以將處理全部 users 表數據分割成一次處理 100 條記錄的小組塊:

DB::table('users')->orderBy('id')->chunk(100, function($users) {
    foreach ($users as $user) {
        //
    }
});

你可以通過從閉包函數中返回 false 來終止組塊的運行:

DB::table('users')->orderBy('id')->chunk(100, function($users) {
    // 處理結果集...
    return false;
});

聚合函數

查詢構建器還提供了多個聚合方法,如countmaxminavg 和 sum,你可以在構造查詢之後調用這些方法:

$users = DB::table('users')->count();

$price = DB::table('orders')->max('price');

當然,你可以聯合其它查詢子句和聚合函數來構建查詢:

$price = DB::table('orders')
                ->where('finalized', 1)
                ->avg('price');

查詢(Select)

指定查詢子句

當然,我們並不總是想要獲取數據表的所有列,使用 select 方法,你可以為查詢指定自定義的 select 子句:

$users = DB::table('users')->select('name', 'email as user_email')->get();

distinct 方法允許你強制查詢返回不重覆的結果集:

$users = DB::table('users')->distinct()->get();

如果你已經有了一個查詢構建器實例並且希望添加一個查詢列到已存在的 select 子句,可以使用 addSelect 方法:

$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();

原生表達式

有時候你希望在查詢中使用原生表達式,這些表達式將會以字元串的形式註入到查詢中,所以要格外小心避免 SQL 註入。想要創建一個原生表達式,可以使用 DB::raw 方法:

$users = DB::table('users')
                     ->select(DB::raw('count(*) as user_count, status'))
                     ->where('status', '<>', 1)
                     ->groupBy('status')
                     ->get();

原生方法

除了使用 DB::raw 外,你還可以使用以下方法來插入原生表達式到查詢的不同部分。

selectRaw

selectRaw 方法可用於替代 select(DB::raw(...)),該方法接收一個可選的綁定數組作為第二個參數:

$orders = DB::table('orders')
                ->selectRaw('price * ? as price_with_tax', [1.0825])
                ->get();

whereRaw / orWhereRaw

whereRaw 和 orWhereRaw 方法可用於註入原生 where 子句到查詢,這兩個方法接收一個可選的綁定數組作為第二個參數:

$orders = DB::table('orders')
            ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
            ->get();

havingRaw / orHavingRaw

havingRaw 和 orHavingRaw 方法可用於設置原生字元串作為 having 子句的值:

$orders = DB::table('orders')
                ->select('department', DB::raw('SUM(price) as total_sales'))
                ->groupBy('department')
                ->havingRaw('SUM(price) > 2500')
                ->get();

orderByRaw

orderByRaw 方法可用於設置原生字元串作為 order by 子句的值:

$orders = DB::table('orders')
                ->orderByRaw('updated_at - created_at DESC')
                ->get();

連接(Join)

查詢構建器還可以用於編寫連接語句,關於 SQL 的幾種連接類型,通過下圖可以一目瞭然:

內連接(等值連接)

要實現一個簡單的"內連接",你可以使用查詢構建器實例上的 join 方法,傳遞給 join 方法的第一個參數是你需要連接到的表名,剩餘的其它參數則是為連接指定的列約束,當然,正如你所看到的,你可以在單個查詢中連接多張表:

$users = DB::table('users')
            ->join('contacts', 'users.id', '=', 'contacts.user_id')
            ->join('orders', 'users.id', '=', 'orders.user_id')
            ->select('users.*', 'contacts.phone', 'orders.price')
            ->get();

左連接

如果你是想要執行“左連接”而不是“內連接”,可以使用 leftJoin 方法。該方法和 join 方法的用法一樣:

$users = DB::table('users')
        ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
        ->get();

交叉連接

要執行“交叉連接”可以使用 crossJoin 方法,傳遞你想要交叉連接的表名到該方法即可。交叉連接在第一張表和被連接表之間生成一個笛卡爾積:

$users = DB::table('sizes')
        ->crossJoin('colours')
        ->get();

高級連接語句

你還可以指定更多的高級連接子句,傳遞一個閉包到 join 方法作為第二個參數,該閉包將會接收一個 JoinClause對象用於指定 join 子句約束:

DB::table('users')
    ->join('contacts', function ($join) {
        $join->on('users.id', '=', 'contacts.user_id')->orOn(...);
    })
    ->get();

如果你想要在連接中使用“where”風格的子句,可以在查詢中使用 where 和orWhere 方法。這些方法會將列和值進行比較而不是列和列進行比較:

DB::table('users')
    ->join('contacts', function ($join) {
        $join->on('users.id', '=', 'contacts.user_id')
             ->where('contacts.user_id', '>', 5);
    })
    ->get();

聯合(Union)

查詢構建器還提供了“聯合”兩個查詢的快捷方式,比如,你可以先創建一個查詢,然後使用 union 方法將其和第二個查詢進行聯合:

$first = DB::table('users')
            ->whereNull('first_name');

$users = DB::table('users')
            ->whereNull('last_name')
            ->union($first)
            ->get();

註:unionAll 方法也是有效的,並且和 union 使用方式相同。

Where子句

簡單 Where 子句

使用查詢構建器上的 where 方法可以添加 where 子句到查詢中,調用where 最基本的方式需要傳遞三個參數,第一個參數是列名,第二個參數是任意一個資料庫系統支持的操作符,第三個參數是該列要比較的值。

例如,下麵是一個驗證“votes”列的值是否等於 100 的查詢:

$users = DB::table('users')->where('votes', '=', 100)->get();

為了方便,如果你只是簡單比較列值和給定數值是否相等,可以將數值直接作為where 方法的第二個參數:

$users = DB::table('users')->where('votes', 100)->get();

當然,你還可以使用其它操作符來編寫 where 子句:

$users = DB::table('users')
            ->where('votes', '>=', 100)
            ->get();

$users = DB::table('users')
            ->where('votes', '<>', 100)
            ->get();

$users = DB::table('users')
            ->where('name', 'like', 'T%')
            ->get();

還可以傳遞條件數組到 where 函數:

$users = DB::table('users')->where([
    ['status', '=', '1'],
    ['subscribed', '<>', '1'],
])->get();

or 語句

你可以通過方法鏈將多個 where 約束鏈接到一起,也可以添加 or 子句到查詢,orWhere 方法和 where 方法接收參數一樣:

$users = DB::table('users')
                ->where('votes', '>', 100)
                ->orWhere('name', 'John')
                ->get();

更多 Where 子句

whereBetween

whereBetween 方法驗證列值是否在給定值之間:

$users = DB::table('users')
            ->whereBetween('votes', [1, 100])->get();

whereNotBetween

whereNotBetween 方法驗證列值不在給定值之間:

$users = DB::table('users')
            ->whereNotBetween('votes', [1, 100])
            ->get();

whereIn/whereNotIn

whereIn 方法驗證給定列的值是否在給定數組中:

$users = DB::table('users')
            ->whereIn('id', [1, 2, 3])
            ->get();

whereNotIn 方法驗證給定列的值不在給定數組中:

$users = DB::table('users')
            ->whereNotIn('id', [1, 2, 3])
            ->get();

whereNull/whereNotNull

whereNull 方法驗證給定列的值為 NULL

$users = DB::table('users')
            ->whereNull('updated_at')
            ->get();

whereNotNull 方法驗證給定列的值不是 NULL

$users = DB::table('users')
            ->whereNotNull('updated_at')
            ->get();

whereDate / whereMonth / whereDay / whereYear

whereDate 方法用於比較欄位值和日期:

$users = DB::table('users')
    ->whereDate('created_at', '2016-10-10')
    ->get();

whereMonth 方法用於比較欄位值和一年中的指定月份:

$users = DB::table('users')
    ->whereMonth('created_at', '10')
    ->get();

whereDay 方法用於比較欄位值和一月中的指定日期:

$users = DB::table('users')
    ->whereDay('created_at', '10')
    ->get();

whereYear 方法用於比較欄位值和指定年:

$users = DB::table('users')
    ->whereYear('created_at', '2017')
    ->get();

whereColumn

whereColumn 方法用於驗證兩個欄位是否相等:

$users = DB::table('users')
        ->whereColumn('first_name', 'last_name')
        ->get();

還可以傳遞一個比較運算符到該方法:

$users = DB::table('users')
    ->whereColumn('updated_at', '>', 'created_at')
    ->get();

還可以傳遞多條件數組到 whereColumn 方法,這些條件通過 and 操作符進行連接:

$users = DB::table('users')
        ->whereColumn([
            ['first_name', '=', 'last_name'],
            ['updated_at', '>', 'created_at']
        ])->get();

參數分組

有時候你需要創建更加高級的 where 子句,比如“where exists”或者嵌套的參數分組。Laravel 查詢構建器也可以處理這些。作為開始,讓我們看一個在括弧中進行分組約束的例子:

DB::table('users')
    ->where('name', '=', 'John')
    ->orWhere(function ($query) {
        $query->where('votes', '>', 100)
              ->where('title', '<>', 'Admin');
    })
    ->get();

正如你所看到的,傳遞閉包到 orWhere 方法構造查詢構建器來開始一個約束分組,該閉包將會獲取一個用於設置括弧中包含的約束的查詢構建器實例。上述語句等價於下麵的 SQL:

select * from users where name = 'John' or (votes > 100 and title <> 'Admin')

where exists子句

whereExists 方法允許你編寫 where exists SQL 子句,whereExists 方法接收一個閉包參數,該閉包獲取一個查詢構建器實例從而允許你定義放置在“exists”子句中的查詢:

DB::table('users')
        ->whereExists(function ($query) {
            $query->select(DB::raw(1))
                  ->from('orders')
                  ->whereRaw('orders.user_id = users.id');
        })
        ->get();

上述查詢等價於下麵的 SQL 語句:

select * from users
where exists (
    select 1 from orders where orders.user_id = users.id
)

JSON Where子句

Laravel 還支持在提供 JSON 欄位類型的資料庫(目前是 MySQL 5.7 和 PostgresSQL)上使用操作符 -> 獲取指定 JSON 欄位值:

$users = DB::table('users')
                ->where('options->language', 'en')
                ->get();

$users = DB::table('users')
                ->where('preferences->dining->meal', 'salad')
                ->get();

排序、分組、限定

orderBy

orderBy 方法允許你通過給定欄位對結果集進行排序,orderBy 的第一個參數應該是你希望排序的欄位,第二個參數控制著排序的方向 —— asc 或 desc

$users = DB::table('users')
        ->orderBy('name', 'desc')
        ->get();

latest / oldest

latest 和 oldest 方法允許你通過日期對結果進行排序,預設情況下,結果集根據 created_at 欄位進行排序,或者,你可以按照你想要排序的欄位作為欄位名傳入:

$user = DB::table('users')
        ->latest()
        ->first();

inRandomOrder

inRandomOrder 方法可用於對查詢結果集進行隨機排序,比如,你可以用該方法獲取一個隨機用戶:

$randomUser = DB::table('users')
        ->inRandomOrder()
        ->first();

groupBy / having

groupBy 和 having 方法用於對結果集進行分組,having 方法和 where 方法的用法類似:

$users = DB::table('users')
        ->groupBy('account_id')
        ->having('account_id', '>', 100)
        ->get();

關於 having 的更多高級用法,可查看 havingRaw 方法。

skip / take

想要限定查詢返回的結果集的數目,或者在查詢中跳過給定數目的結果,可以使用skip 和 take 方法:

$users = DB::table('users')->skip(10)->take(5)->get();

作為替代方法,還可以使用 limit 和 offset 方法:

$users = DB::table('users')
        ->offset(10)
        ->limit(5)
        ->get();

條件子句

有時候你可能想要某些條件為 true 的時候才將條件子句應用到查詢。例如,你可能只想給定值在請求中存在的情況下才應用 where 語句,這可以通過 when 方法實現:

$role = $request->input('role');

$users = DB::table('users')
                ->when($role, function ($query) use ($role) {
                    return $query->where('role_id', $role);
                })
                ->get();

when 方法只有在第一個參數為 true 的時候才執行給定閉包,如果第一個參數為 false,則閉包不執行。

你可以傳遞另一個閉包作為 when 方法的第三個參數,該閉包會在第一個參數為 false 的情況下執行。為了演示這個特性如何使用,我們來配置一個查詢的預設排序:

$sortBy = null;

$users = DB::table('users')
                ->when($sortBy, function ($query) use ($sortBy) {
                        return $query->orderBy($sortBy);
                    }, function ($query) {
                        return $query->orderBy('name');
                    })
                ->get();

插入(Insert)

查詢構建器還提供了 insert 方法用於插入記錄到數據表。insert 方法接收數組形式的欄位名和欄位值進行插入操作:

DB::table('users')->insert(
    ['email' => '[email protected]', 'votes' => 0]
);

你甚至可以一次性通過傳入多個數組來插入多條記錄,每個數組代表要插入數據表的記錄:

DB::table('users')->insert([
    ['email' => '[email protected]', 'votes' => 0],
    ['email' => '[email protected]', 'votes' => 0]
]);

自增ID

如果數據表有自增ID,使用 insertGetId 方法來插入記錄並返回ID值:

$id = DB::table('users')->insertGetId(
    ['email' => '[email protected]', 'votes' => 0]
);

註:當使用 PostgresSQL 時 insertGetId 方法預設自增列被命名為 id,如果你想要從其他“序列”獲取ID,可以將序列名作為第二個參數傳遞到insertGetId 方法。

更新(Update)

當然,除了插入記錄到資料庫,查詢構建器還可以通過使用 update 方法更新已有記錄。update 方法和 insert 方法一樣,接收欄位名和欄位值的鍵值對數組,對應欄位名就是要更新的列,你可以通過 where 子句來對 update 查詢進行約束:

 DB::table('users')
    ->where('id', 1)
    ->update(['votes' => 1]);

更新 JSON 欄位

更新 JSON 欄位的時候,需要使用 -> 語法訪問 JSON 對象上相應的值,該操作只能用於支持 JSON 欄位類型的資料庫:

DB::table('users')
    ->where('id', 1)
    ->update(['options->enabled' => true]);

增加/減少

查詢構建器還為增減給定欄位名對應數值提供方便。相較於編寫 update 語句,這是一條捷徑,提供了更好的體驗和測試介面。

這兩個方法都至少接收一個參數:需要修改的列。第二個參數是可選的,用於控制列值增加/減少的數目。

DB::table('users')->increment('votes');

DB::table('users')->increment('votes', 5);

DB::table('users')->decrement('votes');

DB::table('users')->decrement('votes', 5);

在操作過程中你還可以指定額外的列進行更新:

DB::table('users')->increment('votes', 1, ['name' => 'John']);

刪除(Delete)

當然,查詢構建器還可以通過 delete 方法從表中刪除記錄,你可以在調用 delete 方法前通過添加 where 子句來添加約束條件:

DB::table('users')->delete();

DB::table('users')->where('votes', '>', 100)->delete();

如果你希望清除整張表,也就是刪除所有列並將自增 ID 置為 0,可以使用 truncate 方法:

DB::table('users')->truncate();

悲觀鎖 & 樂觀鎖

悲觀鎖(Pessimistic Lock),顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖、表鎖、讀鎖、寫鎖等,都是在做操作之前先上鎖。

樂觀鎖(Optimistic Lock),顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制實現。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像資料庫如果提供類似於 write_condition 機制的其實都是提供的樂觀鎖。

下麵我們看下悲觀鎖和樂觀鎖在 Laravel 中的使用:

悲觀鎖使用

Laravel 查詢構建器提供了一些方法幫助你在 select 語句中實現“悲觀鎖”。可以在查詢中使用 sharedLock 方法從而在運行語句時帶一把”共用鎖“。共用鎖可以避免被選擇的行被修改直到事務提交:

DB::table('users')->where('votes', '>', 100)->sharedLock()->get();

上面這個查詢等價於下麵這條 SQL 語句:

select * from `users` where `votes` > '100' lock in share mode

此外你還可以使用 lockForUpdate 方法。“for update”鎖避免選擇行被其它共用鎖修改或刪除:

DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();

上面這個查詢等價於下麵這條 SQL 語句:

select * from `users` where `votes` > '100' for update

for update 與 lock in share mode 都是用於確保被選中的記錄值不能被其它事務更新(上鎖),兩者的區別在於 lock in share mode 不會阻塞其它事務讀取被鎖定行記錄的值,而 for update 會阻塞其他鎖定性讀對鎖定行的讀取(非鎖定性讀仍然可以讀取這些記錄,lock in share mode 和 for update 都是鎖定性讀)。

這麼說比較抽象,我們舉個計數器的例子:在一條語句中讀取一個值,然後在另一條語句中更新這個值。使用 lock in share mode 的話可以允許兩個事務讀取相同的初始化值,所以執行兩個事務之後最終計數器的值+1;而如果使用 for update 的話,會鎖定第二個事務對記錄值的讀取直到第一個事務執行完成,這樣計數器的最終結果就是+2了。

樂觀鎖使用

樂觀鎖,大多是基於數據版本 ( Version )記錄機制實現。何謂數據版本?即為數據增加一個版本標識,在基於資料庫表的版本解決方案中,一般是通過為資料庫表增加一個 “version” 欄位來實現。

讀取出數據時,將此版本號一同讀出,之後更新時,對此版本號加一。此時,將提交數據的版本數據與資料庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大於資料庫表當前版本號,則予以更新,否則認為是過期數據。

總結

兩種鎖各有優缺點,不可認為一種好於另一種,像樂觀鎖適用於寫比較少的情況下,即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生衝突,上層應用會不斷的進行重試,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。


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

-Advertisement-
Play Games
更多相關文章
  • python預設序列支持+和*操作的.下麵幾種列表的賦值有的是生成一個新的列表,有的仍是原有列表. 1 ls1=[1,2,3,5,6,8] 2 ls2=ls1 3 ls2.append(9) 4 print(ls2) 5 print(ls1) 這個輸出結果可以猜出來,lst1和lst2一樣,都追加了 ...
  • 十三、整型(int) 基本操作: 1.+ - * / % // ** 2. .bit_length() 計算整數在記憶體中占⽤的⼆進位碼的⻓度 如: 十四、布爾值(bool) True False 1.字元串 => 數字 int() 數字 = > 字元串 str() x => y類型 y(x) 結論: ...
  • 最近在網上看到很多網友在問微信功能變數名稱攔截檢測API介面。有的是想找一個穩定靠譜的服務商,有的是剛接觸這方面的業務想通過程式來代替之前的人工檢測,更有甚者想具體瞭解微信功能變數名稱檢測API介面的原理,當然這部分人群大多數是技術人員或者是喜歡研究的。不管你是出於什麼目的,作為一個研究介面服務多年的人來說這個介面 ...
  • 在ROS機器人的應用開發中,調用攝像頭進行機器視覺處理是比較常見的方法,現在把利用opencv和python語言實現攝像頭調用並轉換成HSV模型的方法分享出來,希望能對學習ROS機器人的新手們一點幫助。至於為什麼轉換成HSV模型,因為在機器視覺方面用HSV模型進行圖像處理是比較方便的,實現的方法和效 ...
  • 題意 "題目鏈接" Sol 最直觀的思路是求出刪除每個點後的最長路,我們考慮這玩意兒怎麼求 設$f[i]$表示以$i$結尾的最長路長度,$g[i]$表示以$i$開始的最長路長度 根據DAG的性質,顯然我們刪除一個點後,整個集合會被分成兩部分:拓撲序小於/大於當前點 那麼此時的最長路一定可以通過計算連 ...
  • 題意 "題目鏈接" Sol 做的時候忘記寫題解了 可以參考 "這位大爺" cpp include define Pair pair define MP make_pair define fi first define se second using namespace std; const int ...
  • 我們的目標網站是這個http://awehome.com.cn,登錄頁面是這個http://awehome.com.cn/tenant/login 搜索我們使用request的session來保存會話並且進入登錄頁面,他是這樣的 我們先來獲取驗證碼,直接通過html.text來獲取是找不到他裡面的圖 ...
  • 題意 "題目鏈接" 有$n$張牌,每張牌有四個屬性$(a, b, c, d)$,主人公有兩個屬性$(x, y)$(初始時為(0, 0)) 一張牌能夠被使用當且僅當$a define Pair pair define MP(x, y) make_pair(x, y) define fi first d ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...