最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

1 小時頂 7 天!程序員工作中的巧思

2021-05-24 23:24 作者:程序員魚皮  | 我要投稿

原計劃 7 天的工作,1 小時完成!是我開掛了么?

我最近在開發(fā)的項目,幫大家學編程:https://github.com/liyupi/code-nav

大家好,我是魚皮,今天分享自己工作中的小歡喜,也希望給大家?guī)硪恍┚幊躺系乃伎肌?/p>

孽起

事情是這樣的,最近在開發(fā)一個 僅限內(nèi)部使用 的數(shù)據(jù)分析系統(tǒng),我做后端,另外一個哥們做前端。

我們要實現(xiàn)的功能是:用戶可以在界面上任意輸入 SQL 數(shù)據(jù)查詢語句,并將它保存下來,生成一個數(shù)據(jù)看板。以后用戶可以隨時打開這個看板來瀏覽和分析 SQL 查詢出的最新數(shù)據(jù),而無需反復輸入 SQL 語句。

舉個例子!

假如我們有一個很大的數(shù)據(jù)倉庫,存了海量的數(shù)據(jù),有男有女:

產(chǎn)品同學可能只想對部分數(shù)據(jù)進行分析,于是寫了下列 SQL 語句來查詢所有男性:

select?*?from?table
?where?性別?=?'男';

將該 SQL 語句保存,得要一個 “男性數(shù)據(jù)看板”,之后,就可以在該看板頁面查看和分析所有男性數(shù)據(jù)啦。

要實現(xiàn)這個需求,一種最簡單的方式就是,直接將用戶在界面上輸入的 SQL 字符串發(fā)給后端保存,需要看數(shù)據(jù)時,后端再用這個字符串從數(shù)據(jù)庫中查詢數(shù)據(jù)即可。

寫 SQL 配置流程:

打開看板瀏覽數(shù)據(jù)流程:

既然是允許用戶任意輸入的,那么問題就來了。

假如小粗心不小心打錯了 SQL 語句:

#?錯誤??
sleetc?*?from?table
#?正確??
select?*?from?table;

又或者小迷糊記錯了 SQL 的語法:

#?錯誤??
select?table?from?a;
#?正確??
select?a?from?table;

甚至是小搗蛋不按規(guī)矩出牌,輸入一些亂七八糟的字符:

#?錯誤??
select?q^q?from?table;
#?正確??
select?q?from?table;

如果把這些錯誤的 SQL 語句發(fā)給后端,后端直接用它來查數(shù)據(jù)庫,必然會導致查詢錯誤,查了個寂寞。

對于實時查詢來說,這沒啥問題,查詢失敗了大不了再修改語句查詢一次唄。

但我要做的需求是允許用戶將查詢語句作為看板配置永久保存下來,便于后續(xù)自動查詢數(shù)據(jù)。而且寫 SQL 配置的用戶可能和看數(shù)據(jù)的用戶不是同一個人,如果小 A 在配置時就沒有發(fā)現(xiàn) SQL 語句是錯誤的,那到時候來查看數(shù)據(jù)看板的小 B 就會一臉懵逼,咋特么看不到數(shù)據(jù)呢?是數(shù)據(jù)還沒準備好,還是查詢出來的數(shù)據(jù)就是 0 行呢,還是說我沒有瀏覽權限呢?

他根本不會想到,已經(jīng)配置成功的 SQL 語句,竟然是錯誤的!

因此,需要在配置時就對用戶輸入的 SQL 進行校驗,看看它是否合法。

做個比喻,前端是一名底層員工(無知的小開發(fā)),后端是小組長,數(shù)據(jù)庫是大老板。小開發(fā)做了個需求之后,應該先交給小組長檢查,小組長說沒問題之后,再給大老板驗收。

那如何校驗 SQL 語句呢?

因為用戶的輸入是完全不確定的,他們寫的 SQL 語句可能又臭又長。所以我剛想到這個需求,就覺得腦闊疼,感覺賊麻煩,不保守地給自己計劃 7 天完成。

大家可以先想想如果讓你實現(xiàn) SQL 語句校驗,你會怎么做?

下面是我的思考過程。

絞盡腦汁

首先,我們要明確:是在前端,還是在后端校驗?

其實,無論在前端還是后端,校驗都至關重要,可以有效防止很多錯誤的輸入。但由于最終是后端程序來直接操作數(shù)據(jù)庫,可以說是數(shù)據(jù)庫的最后一道防線,因此建議 將校驗邏輯寫在后端。數(shù)據(jù)庫很嫩,他自己把握不住,需要后端程序來幫他把握把握。

那如何在后端去校驗 SQL 呢?

找現(xiàn)成的

首先,遇事不決問百度,不行再去搜倉庫。現(xiàn)在網(wǎng)上的開源項目很多,那不妨搜搜看,有沒有現(xiàn)成的 SQL 校驗類庫。最理想的情況是,有一個工具類函數(shù),我傳給他 SQL 字符串作為參數(shù),他直接返回給我 true 或 false。

然而,我發(fā)現(xiàn)自己在想 peach,各種開源項目都搜遍了,沒有找到能開箱即用的 PostgreSQL 校驗庫。

看來,只能自己動手,豐衣足食了。

模擬查詢

要自己實現(xiàn)校驗,我第一時間想到的方法是模擬一次查詢。用戶剛剛寫好 SQL 語句后,即便他現(xiàn)在并不需要瀏覽數(shù)據(jù)查詢結(jié)果,我也可以在他保存配置時,用他寫的 SQL 去查詢一次數(shù)據(jù)庫。假如查詢沒報錯,就說明 SQL 語句合法,允許保存。

這種方式最直接,也最方便,基本沒有任何的開發(fā)成本,賊香!就好比一名小開發(fā)寫完爛代碼后,交給小組長,但小組長不講武德,自己看不懂代碼(也可能是不想看),索性就把代碼直接丟給大老板,大老板說沒問題了,小開發(fā)再上線。小組長狂喜!

但是,有個致命的問題:用戶在配置 SQL 語句時,數(shù)據(jù)表可能還沒準備好,無論語句是否正確,都無法查出數(shù)據(jù)。

所以,在將 SQL 語句直接發(fā)向數(shù)據(jù)庫前,要先確認數(shù)據(jù)表是否存在。若存在,可以通過模擬查詢的方式校驗;若不存在,只能在后端通過其他方式校驗。

就好比小組長想把爛代碼直接丟給大老板時,大老板不在,這時,只能靠自己來檢查了。

正則表達式

要在程序中校驗字符串,我最先想到的是 正則表達式,即用特定語法來匹配同一類具有相似規(guī)則的字符串,常見的有校驗手機號、校驗郵箱、校驗身份證等。

在使用正則表達式進行校驗前,我們要先對字符串進行分析,看它們是否具有相似的結(jié)構、哪些部分相似。比如 QQ 郵箱,結(jié)構很規(guī)整,基本都是 xxx@qq.com,因此,可以用正則表達式 /^\w+@qq.com$/ 來校驗。

回過頭來看我們的需求,要校驗的是 SQL 語句,似乎也比較規(guī)整,無非就是查詢哪個表、選哪些行、選哪些列、怎么排序等等,大概的結(jié)構是這樣:

SELECT?select_list?
[?INTO?new_table?]?
FROM?table_source?
[?WHERE?search_condition?]?
[?GROUP?BY?group_by_expression?]?
[?HAVING?search_condition?]?
[?ORDER?BY?order_expression?[?ASC?|?DESC?]?]

根據(jù)這個結(jié)構,很容易編寫出粗略的正則表達式。但是,數(shù)據(jù)業(yè)務中的 SQL 語句可比這復雜得多,包含各種四則運算、IF ... ELSE 條件判斷、CASE ... WHEN ... 分支,字符串、日期類型處理函數(shù),還有各種聚合函數(shù)等,比如下面這個 SQL:

select?a?as?b,?
?sum(case?when?(false)?then?d?/?a?else?2?end)?as?c
?from?table
?where?a?=?1
?group?by?b,?c;

如果以上這些零碎的語法都用正則表達式來匹配,可就太麻煩了!想想腦闊又疼了。

解析表達式

既然編寫一套正則表達式比較麻煩,那我能想到的就只有把 SQL 打的稀吧碎了??梢杂妙愃凭幾g原理語法分析的方式,搞一個 SQL 解析器,將完整的 SQL 語句轉(zhuǎn)換為一顆抽象語法樹(AST),每個節(jié)點都是一個小表達式,從而能夠更精細地校驗 SQL 語句的合法性。

如果自己從零開始實現(xiàn)這樣一套 SQL 解析器,實在是太麻煩了,而且不具備一定的專業(yè)知識也寫不出來。因此,我先到網(wǎng)上去搜索一番,看看有沒有現(xiàn)成的解析器引擎。

這次的搜索結(jié)果還算滿意,找到了一些知名解析引擎,但是看了一圈,讀了半天,發(fā)現(xiàn)很難直接去使用他們的源碼。那委曲求全的方式就是照著他們的源碼自己寫一個解析器了。

想到這里,頭頂不僅感受到了一絲寒涼,感覺給自己估時 7 天都少了。

移花接木

第二天,我又思考了一下,網(wǎng)上有那么多現(xiàn)成的類庫,難道就沒有一個能滿足我的需求?即使沒有完全現(xiàn)成的,能不能找個相對好用的呢?

畢竟自己來寫這復雜的校驗邏輯實在太麻煩了,所以我必須再掙扎一下!

于是,我掏出了御用小黃鴨,開始對著它念叨:SQL 校驗、SQL 校驗、SQL 校驗。。。

我:什么時候會用到 SQL 校驗呢?

小黃鴨:需要查數(shù)據(jù)庫的時候。

我:什么東西會去查數(shù)據(jù)庫呢?

小黃鴨:框架、數(shù)據(jù)庫連接池、或者代理。

我:那這些玩意在查數(shù)據(jù)庫的時候,會幫我們做校驗么?

小黃鴨:校驗校驗,你就知道校驗,你需要的功能一定是校驗么?

等等,我好像恍然大悟了!

既然沒辦法直接搜到現(xiàn)成的 SQL 校驗類庫,那不妨來個 移花接木,想一想其他的類庫中是否包含 SQL 解析功能,如果解析失敗,不就表示 SQL 非法,校驗不通過么!

我開始回想自己以前用過的和訪問數(shù)據(jù)庫有關的技術,突然想到,阿里的 Druid 數(shù)據(jù)庫連接池類庫好像有一個 SQL 語句格式化的功能,能把雜亂的 SQL 重新排版。既然能對 SQL 格式化,是不是意味著,這個類庫有能力對 SQL 語句進行解析呢?

仔細一查 Druid 的文檔,發(fā)現(xiàn)還真有一個類叫 SQLUtils,這個類有一個方法叫 parseStatements,可以對多種不同的 SQL 方言進行解析,比如 MySQL、PostgreSQL 等。

//?解析,接受?sql?語句和數(shù)據(jù)庫方言為參數(shù)
SQLUtils.parseStatements(sql,?POSTGRESQL);

解析失敗時,會拋出異常,表示 SQL 語句非法,正好能夠滿足我的需求!

最終,我寫出的代碼如下:

try?{
??String?sql?=?"select?*?from?a";
??SQLUtils.parseStatements(sql,?POSTGRESQL);
??return?true;
}?catch?(ParserException?e)?{
??LOGGER.error("解析失敗",?e);
?return?false;
}

幾分鐘就寫完了代碼,然后又花了一些時間輸入各種 SQL 語句來測試,雖然只能實現(xiàn)基本的語法校驗,但綜合衡量效果和成本上,我覺得已經(jīng)不錯了,省下的大量時間可以繼續(xù)完善和優(yōu)化項目的其他代碼。

關鍵是,心不累了,頭發(fā)又支棱起來了!

通過這件事,帶給我三點思考:

  1. 在我們找項目代碼、找類庫的時候,如果沒辦法找到直接滿足需求的,那么可以把思維從整體轉(zhuǎn)向局部,想想在其他的項目中是否包含了你要找的功能。就像查詞典一樣,你要查單詞 apple,但是翻目錄只有首字母 a,這個時候,就不能只盯著 a 看,而是要看到詞典里面的內(nèi)容,其實 apple 就藏在 a 之中。

  2. 前人栽樹,后人乘涼,現(xiàn)在網(wǎng)上現(xiàn)成的項目代碼太多了,如果不是為了學習,很多東西沒必要自己再去實現(xiàn)一遍。

  3. 寫代碼時要注重積累,多學習和了解技術,并歸納總結(jié)到你的武器庫中,否則前人栽的樹你找不到,就可惜了。

當然,有條件的話,前端也是可以加校驗的,但目前沒啥必要,這里我們先用 CodeMirror 做一個 SQL 代碼高亮來替代。

如果真的讓你實現(xiàn)前端 SQL 校驗,你會怎么做呢?

我是魚皮,原創(chuàng)不易,如果覺得文章還不錯的話,希望朋友們 點贊 支持下,給俺點創(chuàng)作動力。

最近還在開發(fā)我的 編程導航(https://www.code-nav.cn),一個幫大家找編程資源的項目,歡迎使用!

我是如何在大學期間通過自學,拿到騰訊、字節(jié)等大廠 offer 的,可以看這篇文章,不再迷茫!

我學計算機的四年,共勉?。?span id="s0sssss00s" class="font-size-16">https://t.1yb.co/q0mS)


1 小時頂 7 天!程序員工作中的巧思的評論 (共 條)

分享到微博請遵守國家法律
建水县| 云和县| 玉溪市| 翁源县| 宜宾市| 龙胜| 东光县| 平邑县| 常熟市| 临汾市| 新沂市| 科尔| 精河县| 三河市| 北票市| 桦南县| 保定市| 图片| 伊通| 巩留县| 康乐县| 旬邑县| 六枝特区| 太白县| 罗甸县| 韶山市| 游戏| 曲水县| 阆中市| 山东省| 康马县| 保靖县| 镇原县| 江陵县| 牟定县| 马山县| 类乌齐县| 柳江县| 罗平县| 来安县| 醴陵市|