掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
答:Backend as a Database, Sort Of

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了山陽免費(fèi)建站歡迎大家使用!
直接把 Mysql 暴露在公網(wǎng)給前端使用會(huì)有什么問題:
要做到 Backend as a "Database",就是回答以上問題如何解決。
Mysql / Postgresql 的權(quán)限太粗了??隙ㄊ且?Mysql / Postgresql 外邊套一層去校驗(yàn)權(quán)限。這里有如下的挑戰(zhàn)要解決
解決了以上問題,我們就獲得了一個(gè)內(nèi)建權(quán)限的“Database”,可以開放到公網(wǎng)給前端訪問。實(shí)際拉數(shù)據(jù)的時(shí)候,用的是人類用戶自己的身份。只要用戶自己對(duì)要訪問的數(shù)據(jù)表或者行有權(quán)限,就可以訪問到,否則就訪問不到。
寫一個(gè) Typescript 的類,然后把 Mysql 的表建好。和 Java Hibernate 一樣
- @Biz.profile('買家', 'read')
- @Biz.profile('店長(zhǎng)', 'read', 'create', 'update', 'delete')
- @Biz.profile('管理員', 'read', 'create', 'update', 'delete')
- @Biz.authentic({ rowPolicy: 'public' })
- @Biz.published
- export class RegionFreightTmpl extends Biz.ActiveRecord {
- @Biz.lookup
- public readonly freightTmpl: FreightTmpl;
- // 計(jì)費(fèi)模式:按件(目前只有按件)
- public freightTmplType: string;
- public firstPrice: number;
- public firstAmount: number = 1;
- public additionalPrice: number;
- public additionalAmount: number = 1;
- public regions?: string;
- }
查詢的時(shí)候直接用這個(gè) class 來指代這張數(shù)據(jù)庫(kù)表就可以了。
能夠做好權(quán)限校驗(yàn)的前提是只暴露單表的簡(jiǎn)單查詢。那么 count / sum / join 這些怎么處理? 難道是要發(fā)明一種 SQL 變種,然后搞 SQL 解析么?
一個(gè)簡(jiǎn)單的做法就是引入“視圖表”的概念。把這些聚合查詢都建模成一張?zhí)摂M的視圖表。這樣在查詢的時(shí)候仍然是單表查詢。
如果所有的聚合查詢都要按需計(jì)算則會(huì)非常慢。經(jīng)常我們需要一些按日期,按維度提前聚合好的中間結(jié)果。這個(gè)可以用物化視圖表來表達(dá)
- @(Biz.view`SELECT id, gender, age, city, SUM(OrderItem.cost) AS total
- FROM ${impactSet}
- JOIN ${User} on User.id = impactSet.userId
- LEFT JOIN ${Order} on User.id = Order.userId
- LEFT JOIN ${OrderItem} on Order.id = OrderItem.orderId`)
- @(impactSet`SELECT DISTINCT(Order.userId) AS userId FROM ${ Order }`)
- @(impactSet`SELECT DISTINCT(Order.userId) AS userId FROM ${ OrderItem } JOIN ${ Order } on Order.id = OrderItem.orderId`)
- @Biz.source(Starriness, { dataSource: 'clickhouse' })
- export class UserWithTotal extends Biz.SqlView {
- public readonly id: string;
- public readonly userId: string;
- public readonly created_at: Date;
- public readonly total: number;
- }
物化視圖的問題在于什么時(shí)候刷新。通過用 SQL 定義 impactSet,我們可以由 mysql binlog 觸發(fā)物化在 clickhouse 中的物化視圖表刷新。
物化視圖的來源是業(yè)務(wù)數(shù)據(jù)。用戶行為因?yàn)閿?shù)據(jù)量比較大,不太適合直接插入到 mysql 中。把用戶行為單獨(dú)提供一張寬表來記錄用戶做過什么操作。寫入可以是內(nèi)存緩沖,或者經(jīng)過 kafka 這樣的隊(duì)列緩沖。
寬表的列應(yīng)該是按業(yè)務(wù)需求擴(kuò)展的,如果業(yè)務(wù)上關(guān)心用戶操作的訂單id,或者商品id,則要加上這些字段。大概的 api 也類似 mixpanel 這些老牌分析廠商的上報(bào)接口。
物化視圖在計(jì)算報(bào)表的時(shí)候可以 join 用戶行為表和業(yè)務(wù)數(shù)據(jù)表來得出分析結(jié)果。
一次 rpc roundtrip 只能發(fā)一條查詢太慢了。那支持一個(gè)數(shù)組,一次可以提交多條查詢就好了。至于前端代碼中怎么把多個(gè)組件的查詢聚合到一個(gè) rpc 中,這個(gè)就看前端的 data query 框架是怎么來弄了。無非就是全局搞個(gè) buffer,在“合適的時(shí)候”刷一下這個(gè) buffer,批量查一次。
細(xì)粒度的用戶權(quán)限只能解決數(shù)據(jù)完全被一個(gè)用戶擁有的問題。很多時(shí)候數(shù)據(jù)是協(xié)作數(shù)據(jù),有多個(gè) stakeholder,那么就必須經(jīng)過協(xié)商好的規(guī)則去修改數(shù)據(jù),而不是一個(gè)用戶說了算。例如你可以決定今天的日記本里隨便寫啥,但是不能決定把今天晚飯的訂單改成0。日記是你擁有的,但是訂單是多個(gè)相關(guān)方都關(guān)心的。
解決業(yè)務(wù)規(guī)則校驗(yàn)后寫入的問題就是存儲(chǔ)過程了。前端同學(xué)肯定是希望用 javascript 來寫存儲(chǔ)過程。實(shí)際上就是所謂 FaaS 的云函數(shù)。本質(zhì)上就是后端代碼仍然有,只是換了一撥人來寫。
如果業(yè)務(wù)規(guī)則比較簡(jiǎn)單,例如只是一個(gè)狀態(tài)機(jī)的轉(zhuǎn)換圖,則可以用配置替代code。當(dāng)然大部分時(shí)候,復(fù)雜的業(yè)務(wù)邏輯,上 javascript 是最直觀的。
數(shù)據(jù)庫(kù)表結(jié)構(gòu)變更了肯定還是要寫 SQL 來升級(jí)數(shù)據(jù)庫(kù)的,標(biāo)準(zhǔn)做法沒啥說的。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流