Serverless 最佳實踐的第二講來了,本講將幫你 Get 如下技巧:git
在第一講雲函數的生命週期中,咱們已經提到了在雲函數 Mount 階段建立數據庫鏈接帶來的兩方面好處:github
咱們再回顧一下示例代碼:sql
import { Func } from '@faasjs/func'; // FaasJS 的雲函數類
import { Sql } from '@faasjs/sql'; // FaasJS 的 Sql 插件
// 初始化數據庫對象
const sql = new Sql();
// 返回雲函數實例
export default new Func({
plugins: [sql], // 插件管理,FaasJS 將自動管理插件的生命週期
async handler(){ // 業務代碼
return await sql.query('SELECT * FROM users WHERE id = ?', [1]);
}
});
複製代碼
FaasJS 的 Sql 插件支持 Mysql、PostgreSql 和 Sqlite 及支持這三類數據庫協議的數據庫,且已經內部封裝了基於雲函數生命週期機制的最佳實踐,開發者只需直接使用便可。typescript
Knex 是一個 SQL 語句生成插件,而且能夠與 TypeScript 結合,大幅簡化開發者對數據庫的操做。數據庫
咱們直接看代碼示例:性能優化
// user.func.ts
import { Func } from '@faasjs/func'; // FaasJS 的雲函數類
import { Sql } from '@faasjs/sql'; // FaasJS 的 Sql 插件
import knex from 'knex';
// 使用 TypeScript 來定義用戶表的結構
interface User {
id: number;
name: string;
}
// 初始化數據庫對象
const sql = new Sql();
// 返回雲函數實例
export default new Func({
plugins: [sql], // 插件管理,FaasJS 將自動管理插件的生命週期
async handler(){ // 業務代碼
const users = knex<User>({
client: sql.adapterType
}) // 告訴 Knex 返回的數據類型和數據庫的類型
.from('users') // 告訴 Knex 表名
.connection(sql.adapter!.pool); // 複用 sql 插件自動維護的數據庫鏈接
return await users.where({ id: 1 }); // Knex 形式的數據庫查詢
}
});
複製代碼
上面的代碼中有兩個要點:微信
按上面的寫法,雲函數自己的業務代碼是沒問題了,但 Knex 還支持建表之類的操做,對於自動化測試是很是有用的,因此咱們再深刻看一下自動化測試腳本怎麼寫更好:框架
// __tests__/user.test.ts
import { FuncWarpper } from '@faasjs/test'; // FaasJS 對雲函數的測試用封裝
import { Sql } from '@faasjs/sql'; // 引入 Sql 插件
import knex from 'knex'; // 引入 knex 插件
// FaasJS 使用 Jest 做爲測試框架
describe('user', function () {
let func: FuncWarpper;
beforeEach(async function () {
// 生成雲函數
func = new FuncWarpper(require.resolve('../user.func') as string);
// 爲了便於測試腳本中對數據庫各類操做,咱們把 sql 插件實例放個快捷方式在 func 對象上
func.sql = func.plugins[0] as Sql;
// 因爲數據庫鏈接是在 mount 階段生成的,所以這裏先 mount 一下
await func.mountedHandler();
// 建表
await knex({
client: func.sql.adapterType
})
.schema
.connection(func.sql.adapter!.pool)
.dropTableIfExists('users')
.createTable('users', function (t) {
t.integer('id').notNullable();
t.string('name').notNullable();
});
});
test('should work', async function () {
// 插入假數據
await knex({
client: func.sql.adapterType
})
.from('users')
.connection(func.sql.adapter!.pool)
.insert({
id: 1,
name: 'hi'
});
// 調用雲函數
const res = await func.handler();
// 檢查返回結果是否符合預期
expect(res.length).toEqual(1);
expect(res[0].id).toEqual(1);
expect(res[0].name).toEqual('hi');
});
});
複製代碼
這裏留一個小問題:當多個雲函數都須要調用這個數據表時,如何封裝比較好呢?(答案見後文)。less
隨着業務增加,必然會遇到數據種類和數量愈來愈多的狀況,若是大量的雲函數都鏈接到一個數據庫,必然會對該數據庫形成較大的壓力,因此建議在開發到必定程度時,提早進行分庫操做,對數據和代碼進行解耦。async
FaasJS 的文件夾結構自然支持分庫,假設咱們把 users 表和 orders 分拆爲兩個數據庫,則只需將它們分別放在兩個不一樣的文件夾裏,每一個文件夾裏獨自配置各自的 faas.yaml 便可。
我在 Github 上的示例代碼包括瞭如下最佳實踐示例:
點擊連接前往: github.com/faasjs/exam…
最後,在使用中遇到任何問題,歡迎關注微信公衆號(寂靜小站)反饋交流或加入 QQ 羣(772109193)一塊兒討論交流: