機油怎麼分好壞?教授親自帶你到歐洲看機油研發過程

實測:在發動機測試實里我們看到各種不同的發動機,所有機油在路試之前都要在這裏分別進行100小時高溫測試、冷機潤滑性能測試、模擬實際使用情況長測,以及整車測試等。在探訪過程中我們還發現了送測的日產雷諾新1。6T機器,整車合作廠家會把最新的發動機送來研發中心,因應發動機的特性開發專用機油並加以改進,所以所謂品牌專用機油和市場上買到的還真是有區別。

說起汽車機油,相信大家都知道每次保養時需要更換,但不同機油之間的差別,好像一般用家不會太在意。比較資深的老司機會知道機油有合成、礦物油之分,也知道機油有不同標號、等級之分,但怎麼選擇一款最適合自己愛車的機油,一款好機油的技術含量有多高,你又知道多少?

在出發前,我們先掃一下盲。

發動機裏面有無數金屬部件在運動,運動過程中會產生摩擦,就好像人的關節一樣,使用了不良或是不合適的機油,發動機就好像得了關節炎一樣,運動不順暢,久而久之,甚至會得大病。

機油具有潤滑、清潔、冷卻、密封、減磨、防鏽 的功能。因此選擇機油是不能馬虎的。

Jacky 此次特意飛往來自法國的品牌—道達爾的集團總部参觀學習,給大家窺探一款優異的機油的研發過程。

什麼?只聽過殼牌、美孚、嘉實多?那你就Out 了!

道達爾是世界第四大石油天然氣公司,業務遍及130多個國家。

在汽車賽事方面,道達爾一直活躍於國內外頂級賽車運動的賽場上,在頂級的賽車運動場上始終能看到道達爾的身影,如一級方程式錦標賽(F1)、世界拉力錦標賽(WRC)、世界耐力錦標賽(WEC)、以及勒芒24小時耐力賽、達喀爾拉力賽(Dakar)。

亞洲勒芒系列賽事(ALMS)、世界房車錦標賽(WTCC)、中國越野拉力賽(CGR)、絲綢之路拉力賽(Silk Way Rally)等其它著名賽事。通過這些頂級賽事,道達爾的產品性能(潤滑油和燃油)在非常嚴苛的環境下都得到了驗證。

到底一款優良的機油是怎樣研發的呢?第一站我們來到了位於里昂近郊的道達爾Soliaze研發中心。

在這裏每年有超過1200種不同特性的潤滑油誕生。

機油研發分為調配、試驗、分析、實測幾個重要步驟:

調配:因應不同的訴求,加入不同的添加劑來達到相應的效果,你所使用的機油和F1車隊使用的機油都是在同一個實驗室由同一幫工程師調配出來的。

試驗:調和好的機油會送到實驗室進行高溫、低溫、各種耐久測試,這裏的溫度控制精度必須達到小數點后2位,因為實驗室屬於整個生產流程的最頂端,不能允許有任何誤差。在這裏我們也看到了標緻和雷諾的廠家機油測試標準,比一般的歐標和美標都要更嚴格一些。

實測:在發動機測試實里我們看到各種不同的發動機,所有機油在路試之前都要在這裏分別進行100小時高溫測試、冷機潤滑性能測試、模擬實際使用情況長測,以及整車測試等。在探訪過程中我們還發現了送測的日產雷諾新1.6T機器,整車合作廠家會把最新的發動機送來研發中心,因應發動機的特性開發專用機油並加以改進,所以所謂品牌專用機油和市場上買到的還真是有區別。

在巴黎車展上,我們看到了道達爾贊助的雷諾F1賽車、標緻3008 DKR 賽車和208WRX 賽車,在208 WRX 的宣傳片上我甚至看到添加道達爾快馳潤滑油的片段,所以我很好奇到底賽用機油跟我們民用機油的相似度有多少。

為此我特意來到了道達爾集團位於巴黎的總公司,和他們的拉力和耐力賽經理聊了一下。

道達爾多年來积極支持各大國際知名賽事,如世界房車錦標賽WTCC、世界耐力錦標賽WEC、世界拉力錦標賽WRC,一級方程式比賽F1等等,併為贊助車隊提供高品質的潤滑油產品和技術支持。

這些參賽車輛在運行過程中擁有非常高的轉速,這樣的環境對賽車發動機及潤滑油都有着嚴苛的考驗,所以賽車用油或多或少都與民用油有所不同,尤其是像F1這樣對速度要求十分高的賽事,所需的機油和民用油差別則更大,但在賽事嚴苛的使用環境中,機油可以得到深度的測試,賽後進行樣本分析,再把數據應用到民用產品當中。

和賽事中純性能取向不同,一款良好的民用機油應該具備以下特性,我們可以拿道達爾快馳9000 5W-40汽車潤滑油舉個例子:

它有哪些特性呢?:

1、全合成產品,性能穩定可本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

PL/SQL編程急速上手

  結構化查詢語言(SQL)是第四代編程語言的典型,這種命令式的語言更像一種指令,使用它,你只需要告訴計算機“做什麼”,而不用告訴計算機“怎麼做”。第四代編程語言普遍具有簡單、易學、能更快的投入生產等優點,但也失去了部分第三代編程語言(C,C++,Java等)的靈活性。PL/SQL 在 SQL 的基礎上,保留了部分第三代編程語言特性,它主要運行在 Oracle 數據庫上,它同時兼備了第四代語言簡單、易用的特點,又保留了高級程序設計語言的靈活性與完整性,這使得開發人員可以只使用 PL/SQL 就能進行複雜業務邏輯的編寫。

 

一  PL/SQL 簡介

 

  1,簡介

  標準 SQL 提供了定義和操縱數據庫對象的能力,但與傳統高級編程語言相比,由於其具有更高的抽象性,所以註定缺乏諸多高級編程語言的特性,比如封裝函數、流程控制、進行錯誤檢測和處理等。

  PL/SQL 是 Oracle 在標準 SQL 的基礎上進行功能擴充后的一門編程語言,這使它保留了部分第三代編程語言的部分特性,比如變量聲明、流程控制、錯誤處理等。

  PL/SQL 的全稱是 Procedural Language/SQL,即過程化結構查詢語言,正如其名所示,PL/SQL 增加了過程性語言中的結構,以對標準 SQL 進行擴充。在PL/SQL 中,最基本的程序單元是語句塊(block),所有的程序都應該由各種塊構成,塊與塊之間可以相互嵌套。在塊中,可以定義變量,執行條件判斷,循環等。

 

  2,開發工具

  Oracle 官方提供了兩款開發工具:SQL*Plus 和 Oracle SQL Developer。前者是一款命令行開發工具,後者則擁有方便的圖形化操作界面(類似SQL Server 的 SSMS)。

  除了官方提供的兩款工具外,PL/SQL Develpoer 是一款由第三方公司開發的,非常流行的 Oracle 數據庫集成開發環境。除此之外,市面上還有很多其他工具也具備 Oracle 數據庫開發的能力,大家可以根據需要選擇合適的開發工具。

  3,基本概念

  如果你對 SQL Server 有一定了解,你應該知道,它裏面可以創建很多的數據庫,用於存儲不同業務或系統的數據,每個數據庫都有單獨的數據文件(物理磁盤存儲的)。Oracle 中有點不同,嚴格來說 Oracle 通常只有一個數據庫,然後通過表空間和方案來實現多業務的數據分離。

  Oracle 通過表空間來存儲不同的內容,表空間是數據庫的邏輯劃分,每個數據庫至少有一個表空間(SYSTEM 表空間)。為了便於管理和提高運行效率,可以使用一些附加表空間來劃分用戶和應用程序。例如:USER 表空間供一般用戶使用,RBS 表空間供回滾段使用,一個表空間只能屬於一個數據庫。

  方案是另一個 Oracle 中特有的概念,方案是比表空間更細粒度的另一種單元,方案用於存放用戶相關的信息。通常每個用戶都對應一個方案,並且名稱一樣。多個用戶可以共用一個表空間,但不能通用一個方案,正是由於這種方案-用戶一一對應的關係,所以我們通常也把方案理解成用戶權限所能及的對象的集合。

 

二  PL/SQL基礎

 

  1,SQL 與 PL/SQL

  前面提到,PL/SQL 是對標準 SQL 的擴展,所以,在 PL/SQL 中不僅可以執行 SQL 語句,還支持很多增強的特性,比如在 SQL 語句中使用變量、使用 PL/SQL 定義的函數等。在 PL/SQL 語句塊中,可以使用 SQL 語句操作數據庫,它支持所有的 SQL 數據操作、游標和事務處理命令,支持所有的 SQL 函數、操作符,完全支持 SQL 數據類型。

  需要注意的是:在 PL/SQL 語句塊中,不能直接使用 DDL 語句,這是因為 PL/SQL 引擎在編譯時會檢測語句塊中所涉及的對象,如果其不存在,通常都會引發錯誤,導致 DDL 語句執行失敗。

  為了解決這類綁定性錯誤,可以使用動態SQL,即把需要執行的 DDL 操作存儲在字符串中,並通過 execute immediate 來執行這個字符串,從而達到間接執行 DDL 操作的目的。

  

  2,數據定義

  數據管理主要使用 DDL 數據定義語言:create、alter、drop。

  創建表和約束:

 1 --在列后添加約束
 2 create table table_name  3 (  4     col1 type constraint,  5  ...  6 )  7 --單獨添加約束
 8 create table table_name  9 ( 10  col1 type, 11  ...., 12  constration cons_name cons_type 13 ) 14 --在Oracle中創建表和約束與標準SQL相同

  創建索引和視圖:

 1 --創建索引(非唯一)
 2 --默認系統會在具有unique和primary key的列上創建唯一約束
 3 create index index_name on (col1...);  4 --當提供多個列時,即創建複合索引
 5 --創建視圖
 6 create or replace view view_name  7 as
 8 select ...;  9 --創建,如果已存在則修改視圖
10 create view ...
11 as
12 ... 13 with read only; 14 --創建只讀的視圖(推薦)

  修改表或視圖:

1 --為表增加新的列
2 alter table table_name 3 add col_name type constration; 4 --移除表中已有的列
5 alter table table_name 6 drop column col_name;

  刪除數據庫對象:

1 --刪除表
2 drop table table_name; 3 --刪除視圖
4 drop view view_name; 5 ...

  

  3,數據查詢

  A:標準查詢

    Oracle 中的數據查詢遵循 SQL 標準,常規查詢請移步我的《SQL入門,就這麼簡單》。

  B:dual 表

    dual 是 Oracle 系統中對所有用戶可用的一個實際存在的表,它不能用來存儲信息,在實際開發中只能用來執行 SELECT 語句,我們可以用它來獲取系統信息,比如獲取當前系統日期,或輸出一些測試信息。

1 --獲取系統日期
2 select sysdate from dual; 3 --轉換日期格式
4 select to_char(sysdate,'yyyy-mm-dd');
5 ...

  C: 偽列

    常用的偽列有兩個:rownum、rowid。

    在 Oracle 中沒有類似 SQL Server 中 TOP 這樣可以提取結果集前幾條記錄的關鍵字,但 Oracle 提供了一個更方便的方法,rownum 偽列。rownum 是一個動態的序號,從 1 開始,為所有查詢到的數據編號。

1 --查詢員工表中前10位員工相關信息
2 select rownum,ename,sal from emp 3 where rownum<=10; 4 -- 測試數據庫 Oracle 11g 

    使用 rownum 偽列時需要注意:rownum 是在基礎查詢之後動態添加上去的序號,所以,如果你想通過一條查詢語句實現提取結果集中間的部分記錄是不能成功的,必須使用子查詢,把 rownum 當做普通列才能實現。

1 select row_num,empno,ename,sal from ( 2     select rownum as row_num,empno,ename,sal from emp 3 )a 4 where row_num >5 and row_num <=10; 5 -- 別名是為了防止服務器把外層的rownum再次當做偽列

    同理,提取使用 order by 排序后的記錄,也需要使用子查詢。

    和 rownum 不同,rowid 偽列是和表中的數據一樣實際存在的列,它是一種數據類型,是基於 64 位編碼的 18 個字符,用來唯一的表示一條記錄物理位置的一個id。我們可以通過 rowidtochar 函數把它轉換成字符串進行显示,還可以通過它來刪除表中重複的記錄。

1 --查看rowid
2 select rowidtochar(rowid) ename,sal from emp; 3 --基於rowid刪除表中形同的記錄
4 delete from emp 5 where rowid not in ( 6     select min(rowid) from emp group by empno 7 );

  

  4,數據操縱

  數據操縱主要包含以下操作:insert、update、delete、merge。

  A:insert 插入

 1 --方式一
 2 insert into table_name(column list)--如果不提供字段列表,下面的值列表需要提供每個字段的值,即使可以為空或有默認值
 3 values 
 4 (value list),  5 (value list),  6 ....  7 --方式二
 8 insert into table_name  9 select ... 10 --從其他查詢獲取數據,並插入表,數據必須符合表的約束

  B:update 更新

1 --方式一
2 update table_name 3 set col=newValue 4 where ...--如果不提供過濾條件,則更新表中所有的列
5 --方式二
6 update table_name 7 set (column list)=
8 (select ...) 9 --通過子查詢更新表,如果只更新一列,則可以省略column list 的括號,需要注意子查詢的字段順序需要和更新的字段順序一致

  C:delete

1 --方式一
2 delete from table_name 3 where ...--如果不提供過濾條件,則會刪除所有記錄

  

  5,序列

  Oracle 中沒有 SQL Server 中 identity() 標識函數,也沒有 MySQL 中 auto_increnent 這樣的選項來實現自增的列。但 Oracle 提供了更有用的“序列”。類似一個封裝好的函數,每次執行會返回一個按指定步長增長或減小的数字。常用來為表設置自增的主鍵。

1 create sequence seq_name 2 increment by n --自增的步長,(省略該選項則)默認為1,負數表示遞減
3 start with n --序列的初始值,默認為1
4 max value n | nomaxvalue --指定最大值或沒有最大值(無限增長)
5 min value n  | nominvalue --指定最小值或沒有最小值(無限減小)
6 cycle | nocycle --規定設置的序列到達最大或最小時是否從開頭循環
7 cache n | nocache --規定是否在內存中緩存序列值,以改善性能

  通常情況下,我們只需要指定初始值,最大值和循環三項,即可創建一個序列。

1 create sequence my_seq 2 start with 1
3 nomaxvalue 4 nocycle;

  序列也是 Oracle 數據庫對象之一,序列有兩個常用的屬性:nextval、currval。

1 select my_seq.nextval from dual;--獲取下一個序列值
2 select my_seq.currval from dual;--查看當前序列值
3 --在插入數據是使用序列
4 insert into table_name 5 values
6 (my_seq.nextval,...) 7 --使用循環批量插入時非常方便

  我們可以為每個表創建單獨的序列,從而為每個表提供沒有間隙(無刪除數據或回滾等操作干擾)的自增字段作為主鍵。

  修改和刪除序列:

1 alter sequence seq_name 2 ... 3 --為了保證主鍵的變化有相同的規律可循,一般不建議修改已創建的序列
4 drop sequence seq_name

 

三  Oracle 內置函數

 

  1,字符串函數

 1 --把二進制轉換成字符
 2 select CHR(0101) from dual;  3 --連接字符串
 4 select concat(111,'aaa') from dual;  5 select 111 || 'aaa' from dual;  6 --首字母大寫
 7 select INITCAP('char') from dual;  8 --全大/小寫轉換
 9 select lower('ABC'),upper('abc') from dual; 10 --左/右填充
11 select lpad('aa',5,'*'),rpad('aa',5,'*') from dual; 12 --刪除字符串左/右指定字符(第二個參數中包含的字符都會被刪除)
13 select ltrim('aaa123aaa','1a'),rtrim('aa123aa','a') from dual; 14 --刪除左右空格
15 select trim(' aaa ') from dual; 16 --從左邊開始刪除指定字符(單個),可選參數還包括:trailing(從右邊開始),both(兩邊一起)
17 select trim(leading 'a' from 'aa123aa') from dual; 18 --從指定位置開始截取指定長度的字符串
19 select substr('abcdefg',2,3) from dual; 20 --字符替換(第二個參數中包含的字符都會被替換)
21 select translate('11aa22aa11', 'a2', 'bb') from dual; 22 --替換 NULL 值
23 select nvl(NULL,'aha') from dual;

  

  2,數學函數

 1 --絕對值
 2 select abs(-123) from dual;  3 --向上取整
 4 select ceil(1.2),ceil(-1.2) from dual;  5 --向下取整
 6 select floor(1.8),floor(-1.8) from dual;  7 --返回自然常數 e 的 n 次方
 8 select exp(5) from dual;  9 --返回以第一個參數為底的第二個參數的對數
10 select log(3,10) from dual; 11 --求模,如果第二個參數為0,則返回第一個參數
12 select mod(10,3) from dual; 13 --返回第一個參數的第二個參數次方
14 select power(23) from dual; 15 --保留指定小數位,最後一位小數四舍五入得來
16 select round(1.2345,3) from dual; 17 --保留指定小數位,其餘直接截斷
18 select trunc(1.2345,3) from dual; 19 
20 --格式化数字(格式位數應該與数字位數相同)
21 
22 --用0格式化時,如果数字位數不夠,結果會用0補齊位數
23 select to_char(123456789000,'000,000,000,000,000') from dual; 24 --用9格式化時,如果数字位數不夠,結果會用空格補齊位數
25 select to_char(123456789000,'999,999,999,999,999') from dual; 26 --使用fm格式化小數
27 select to_char(123456.258,'fm999,999,999.99') from dual; 28 --使用 $(美元) 或 L(當地) 添加貨幣符號
29 select to_char(123.456,'L999.999') from dual; 30 /* 注意貨幣符號和小數不能一起使用 */

 

  3,時間和日期函數

 1 --返回操作系統日期
 2 select sysdate from dual;  3 --返回日期部分
 4 select current_date from dual;  5 --返回日期+時間
 6 select current_timestamp from dual;  7 --返回操作系統日期—+時間(包含時區信息)
 8 select systimestamp from dual;  9 --按格式化日期為字符串
10 select to_char(sysdate,'YYYY-MM-DD HH:MM:SS') from dual; 11 --把字符串表示的日期轉換成日期類型的值返回(前後格式需保持一致)
12 select to_date('2020-05-28 17:02:00','YYYY-MM-DD HH24:MI:SS') from dual; 13 --把字符串表示的日期轉換成日期 + 時間類型的值返回(前後格式需保持一致)
14 select to_timestamp('2020-05-28 17:02:00','YYYY-MM-DD HH24:MI:SS') from dual; 15 --返回指定日期後幾個月的日期
16 select add_months(sysdate,1) from dual; 17 --返回兩個日期間間隔月數(注意正負)
18 select months_between(sysdate,to_date('2020-07-01','YYYY-MM-DD')) from dual; 19 --把日期按指定精度截斷,可選參數有yyyy(精確到年,返回當年的第一天的日期),mm(精確到月,返回當月第一天的日期),rr(精確到日,返回當天的日期)
20 select trunc(sysdate,'mm') from dual; 21 
22 /* ----------------------日期可選格式--------------------- */
23 TO_CHAR(sysdate, 'DD-MON-YYYY HH24:MI:SS') 24 TO_CHAR(sysdate, 'DD-MON-YYYY HH12:MI:SS PM') 25 TO_CHAR(systimestamp, 'DD-MON-YYYY HH24:MI:SS.FF') 26 TO_CHAR(sysdate, 'DY, DD-MON-YYYY') 27 TO_CHAR(sysdate,'Month DDth, YYYY') 28 TO_CHAR(systimestamp, 'DD-MON-YYYY HH24:MI:SS TZH:TZM') 29 TO_CHAR(sysdate, 'MM/DD/YYYY HH24:MI:SS') 30 TO_CHAR(sysdate, 'MM/DD/YY HH24:MI:SS') 31 TO_CHAR(sysdate, 'MM/DD/RRRR HH12:MI:SS PM') 32 TO_CHAR(sysdate, 'MM/DD/RR HH12:MI:SS PM')

 

  4,聚合函數

 1 --計算行數(不計算空值)
 2 select count(*) from emp;--根據所有列計算
 3 select count(comm) from emp;--根據某一列計算(注意該列是否有空值)
 4 select count(distinct deptno) from emp;--計算deptno中不同值的個數
 5 --計算列的最大/小值
 6 select max(sal),min(sal) from emp;  7 --返回中間值
 8 select median(sal) from emp;  9 --返回標準差
10 select stddev(sal) from emp; 11 --求和
12 select sum(sal) from emp; 13 --計算方差
14 select variance(sal) from emp; 15 --偽列 rownum,每條數據的序號
16 select rownum,empno,ename,sal from emp;

 

四  變量和類型

 

  1,PL/SQL 基礎

  如果想通過 PL/SQL 程序輸出內容,需要先執行以下命令,以打開輸出功能,否則即使 PL/SQL 程序正常執行,也不會有任何信息輸出。

1 set serveroutput on--可以不需要語句結束標記';',這是開發工具的命令
2 dbms_output.enable;--這是 Pl/SQL 提供的

  PL/SQL 程序由不同的 block(程序塊)組成,塊是 PL/SQL 程序的基本組成單位,塊又可以分為匿名塊和命名塊。

  一個完整的 PL/SQL 程序一般包含 3 部分:declare(聲明),execution code(執行代碼,即業務邏輯代碼),exception(異常處理),聲明和異常處理不是必須的。

1 declare
2 --... 包括變量、游標等
3 begin
4 --... 業務代碼
5 exception 6 --... 異常處理
7 end;

  讓我們來看一個最簡單的 PL/SQL 程序:

1 --注意,PL/SQL業務代碼必須運行在 begin...end 中
2 begin
3 dbms_output.put_line('hello world'); 4 end; 5 --沒有聲明和異常部分

  塊與塊之間可以相互嵌套,PL/SQL 中程序塊可以限制變量的作用域(變量的作用域問題稍後的章節將會詳細講解),另外,使用<<name>>為塊命名可以讓整個程序可讀性更好:

1 <<outer>>--oracle 11g 不允許給最外層塊命名
2 begin
3 dbms_output.put_line('outer block'); 4   <<inner>>
5   begin
6   dbms_output.put_line('inner block'); 7   end; 8 end;

  

  2,變量

  PL/SQL 中的變量在 declare 區域聲明,不需要額外的標識符,只需要提供變量名和值類型即可。

1 declare
2   v_name emp.ename%type;--通過動態獲取表中列的數據類型,來確定變量的數據類型
3   v_job  varchar(50);--直接指定具體的數據類型
4 begin
5   v_name:='&name';--通過:=為變量賦值
6 end;

  &name,這種形式是 SQL Developer 工具提供的一種變量形式:替換變量,在執行程序時,你可以手動指定變量的值,提升程序的交互性,測試程序時非常有用。需要注意的是,它並不是 PL/SQL 提供的功能,當使用 & 標識變量時,每次執行該程序都需要提供值,如果使用 && 標識,則只需要在第一次執行時提供,後續執行都默認為第一次提供的值。

  給變量賦值除了通過 := 的方式,還可以使用 select…into 的方式,直接從查詢中獲取值並賦給變量。

1 declare
2     v_job emp.job%type; 3 begin
4     select job into v_job from emp where ename=v_name;--通過select...into 為變量賦值
5     dbms_output.put_line(v_job);--輸出變量值
6 end;

  

  3,記錄類型

  當有多個邏輯相關的變量需要聲明時,我們可以使用記錄類型來封裝他們,封裝好這個東西就是記錄類型(record)。

 1 declare
 2   type emp_record is record(--這裏相當於定義了一種新的數據類型,類型名稱是emp_record,和varcahr,int等類型一樣
 3   v_name emp.ename%type,  4   v_job emp.job%type,  5   v_sal emp.sal%type  6  );  7   --記錄類型類似其他編程語言中的類
 8   v_emp_record emp_record;--聲明一個emp_record類型的變量,相當於創建一個類的實例
 9 begin
10   select ename,job,sal into v_emp_record from emp where ename='ALLEN';--注意查詢的順序必須和記錄類型中定義的順序一致
11   dbms_output.put_line(v_emp_record.v_name||' '||v_emp_record.v_job||' '||v_emp_record.v_sal); 12   --通過實例訪問相關屬性
13 end;

  %rowtype:

1 declare
2   v_emp_record emp%rowtype;--聲明一個包含指定表中所有列的rowtype變量,使用上和記錄類型完全一致,但它本質上並不是記錄類型
3 begin
4   select * into v_emp_record from emp where ename='ALLEN';--把所有的列都查詢出來賦值給該變量
5   dbms_output.put_line(v_emp_record.ename||' '||v_emp_record.sal); 6   --該變量中的屬性和表的列名完全一致,可以根據需要,只使用部分數據
7 end;

  

  4,集合

  集合類似其他編程語言中的數組,也可以通過下標來訪問數據。

  如果把它和記錄類型、變量相比教,你會發現,標量標量是用來處理單行單列數據的,記錄類型適合處理單行多列的數據,而集合則是用來處理單列多行數據的。

  Oracle 提供了三種類型的集合:索引表(又稱關聯數組)、嵌套表、可變長度數組。

  索引表可以通過数字或字符串來作為下標存儲數據,下標可以不連續,索引表的容量即是数字的最大值,但它只能存儲在內存中。

1 declare
2   type idx_table is table of varchar(20) index by pls_integer;--創建索引表類型
3   -- index by 后可選的參數有pls_integer、binary_integer、varcahr(size)和使用%type 指定的varchar2類型
4   v_idx_table idx_table;--聲明索引表類型的變量
5 begin
6   v_idx_table(1):='hello';--插入值
7   v_idx_table(2):='world'; 8   dbms_output.put_line(v_idx_table(1)||' '||v_idx_table(2)); 9 end;

  嵌套表只能使用数字作為下標,数字必須是有序的,嵌套表的容量沒有限制,可以保存到數據庫中。

 1 declare 
 2   type nest_table is table of varchar(20);--創建嵌套表類型
 3   v_nest_table nest_table:=nest_table('x');--聲明嵌套表類型的變量並初始化
 4   --未初始化的嵌套表類型實際上是一個null,如果試圖為其賦值會報錯。初始化就是調用一個和創建的嵌套表類型同名的函數,
 5   --函數的參數值類型需要和嵌套表類型定義的存儲值類型(of 后的類型)相同,並且參數的個數默認就是這個嵌套表類型變量的初始容量
 6 begin
 7   v_nest_table.extend(5);--擴充嵌套表類型變量的容量
 8   --如果要增加嵌套表的容量,需要調用extend方法(該方法將在稍後詳細說明)
 9   v_nest_table(1):='hello';--插入值
10   v_nest_table(2):='world'; 11   dbms_output.put_line(v_nest_table(1)||' '||v_nest_table(2)); 12   dbms_output.put_line(nvl(v_nest_table(3),'it is null'));--沒被使用的位置為null
13 end;

  可變長度數組和嵌套表類似,都只能使用有序的数字作為下標,可變數組在定義時必須指定容量,但在運行時可以手動的擴充其容量,所以,可變數組的真實容量也可以是無限的,可變數組也可以存儲到數據庫中。

 1 declare
 2   type varr is varray(5) of int;--創建可變數組類型
 3   v_varr varr:=varr();--聲明可變數組類型的變量並初始化
 4   --和嵌套表一樣的原因,必須初始化
 5 begin
 6   for i in 1..5 loop--循環插入值
 7  v_varr.extend();  8     v_varr(i):=i;  9     end loop; dbms_output.put_line(v_varr(1)||','||v_varr(2)||','||v_varr(3)||','||v_varr(4)||','||v_varr(5)); 10 end;

  嵌套表和可變數組能存入數據庫是指:他們可以和普通數據類型一樣,用來定義表的列。

 1 --第一步,創建一個保存在數據庫中的嵌套表類型
 2 create or replace type nest is table of varchar(20);  3 --第二步,創建一個帶有嵌套表類型列的數據表
 4 create table x(  5   x_id int,  6  x_nest nest  7 )nested table x_nest store as y;--使用nest table 指定這是一個包含嵌套表類型值的數據表,並通過 store as 創建一個關聯表來專門存儲嵌套表  8 --插入一條數據(包含初始化的嵌套表類型值)
 9 insert into x values(1,nest('x','y','z')); 10 --第三步,在PL/SQL中讀取嵌套表類型的值(多行操作使用游標)。數據表並沒有直接存儲嵌套表,所以不能直接使用select查詢,而應該在PL/SQL程序塊中查詢
11 declare
12  v_nest nest; 13 begin
14   select x_nest into v_nest from x; 15   for i in 1..3 loop 16  dbms_output.put_line(v_nest(i)); 17   end loop; 18 end;

  把可變長度數組存放到數據庫就不需要使用 nested table 和 store as 指定相關信息,而且可以直接使用 select 查詢存儲了可變長度數組的數據表。所以,通常的建議是,當只是臨時使用集合,那麼索引表是最好的選擇,如果需要把集合存入數據庫,可變數組更操作起來更簡單。

  

  5,集合常用方法

  集合的方法通過“.”點的形式調用:集合.方法。

1 集合.exists(n)--判斷是否存在某個集合的值
2 集合.count--統計集合中值的個數
3 集合.limit--查詢集合容量(長度)
4 集合.first/集合.last--集合中第一個/最後一個值的索引
5 集合.prior(n)/集合.nest(n)--指定索引位置前一個/下一個值的索引(一般用在索引表中,因為其下標可能不連續)
6 集合.extend/集合.extend(n)--為集合增加1個/n個容量(一般用在嵌套表和可變數組中)
7 集合.trim/集合.trim(n)--從集合末尾刪除1個/n個元素(一般用在嵌套表和可變數組中)
8 集合.delete/集合.delete(n)--從集合中刪除所有元素/第n個元素(一般用在索引表和嵌套表中)

   

  6,變量的作用域

 1 declare
 2  v1 int default 1;--外層塊變量v1
 3 begin
 4  dbms_output.put_line(v1);  5  --dbms_output.put_line(v2);error 必須聲明v2
 6  declare
 7   v2 int default 2;---內層塊變量
 8   v1 int default 3;  9  begin
10   dbms_output.put_line(v1);--返回3
11  end; 12 end;

  變量只在聲明的塊中起作用,內層塊可以訪問外層塊的變量,但外層塊無法訪問內層塊的變量,如果內外塊聲明的相同的變量,那麼 PL/SQL 採用就近原則。

 

五  流程控制

  

  1,case

  case 語句有兩種語法,簡單 case 語法只做等值匹配,搜索 case 語法可以做區間匹配。

  先來看簡單 case 語法:

 1 declare
 2   v_sal int;  3 begin
 4   select sal into v_sal from emp where empno=&empno;  5   case v_sal  6     when 800 then dbms_output.put_line('太少了吧');  7     when 1600 then dbms_output.put_line('這還差不多');  8     when 3000 then dbms_output.put_line('這樣更好');  9     when 5000 then dbms_output.put_line('這樣最好'); 10     else dbms_output.put_line('隨緣吧'); 11     end case; 12 end;

  搜索 case 語法:

 1 begin
 2   select sal into v_sal from emp where empno=&empno;  3   case 
 4     when v_sal<=1000 then dbms_output.put_line('太少了吧');  5     when v_sal<=1600 then dbms_output.put_line('這還差不多');  6     when v_sal<=3000 then dbms_output.put_line('這樣更好');  7     when v_sal<=5000 then dbms_output.put_line('這樣最好');  8     else dbms_output.put_line('隨緣吧');  9     end case; 10 end;

  請仔細觀察兩種語法的區別。

  

  2,if…elsif…else

 1 declare
 2   v_sal int;  3 begin
 4   select sal into v_sal from emp where empno=&empno;  5   if v_sal>=5000
 6     then dbms_output.put_line('還有頭髮嗎');  7   elsif v_sal>=3000
 8     then dbms_output.put_line('還有一半嗎');  9   else
10     dbms_output.put_line('好好珍惜頭髮啊,少年'); 11   end if; 12 end;

  請注意,PL/SQL 中的多分支結構 elsif 關鍵字與其他語言相比,少了一個字母 e,且 els 和 if 之間沒有空格。

  

  3,循環

  PL/SQL 提供了 3 種循環:loop、while、for(集合部分已經見過了)。

  在正式介紹循環之前,首先要介紹 PL/SQL 中的循環控制語句:exit,無條件結束整個循環(類似其他語言中的 break)。continue,結束本次循環,繼續下一次循環。接下里讓我們通過例子來詳細說明每個循環的使用方法。

  loop 循環:

 1 declare
 2   i int default 1;--定義,初始化循環控制變量
 3 begin
 4  loop  5     if i=5 then
 6       i:=i+1;  7       continue;--當n等於5時,直接結束本次循環,不輸出
 8     end if;  9  dbms_output.put_line(i); 10     i:=i+1;--修改循環控制變量 
11     exit when i>10;--根據循環控制比變量,判斷是否退出循環
12   end loop;--結束循環
13 end;

  while 循環:

1 declare
2   i int default 1;--定義,初始化循環控制變量
3 begin
4   while i<=10 loop--根據循環控制變量,判斷是否進入循環體
5     dbms_output.put_line(i);--循環體
6     i:=i+1;--修改循環控制變量
7   end loop;--結束循環
8 end;

  for 循環:

1 begin
2   --在for循環中,初始化循環控制變量,只需指明變量名即可,類型系統默認為数字,min..max指明控制變量的變化範圍,從min開始,到max結束
3   for i in reverse 1..10 loop--i可以被循環體引用,但不能被賦值
4   dbms_output.put_line(i);--循環體
5   --注意,因為初始化循環變量時已經指定了變化範圍,這相當於限定了循環條件,當變量從min變化到max時將自動結束循環
6   end loop;  --結束循環
7   --最後說明,reverse是可選的參數,表示循環變量從max開始,到min結束
8 end;

  

  4,雜項

  這裏要介紹兩個東西,null 語句(不是null 值)和 goto 語句。null 語句表示什麼也不做,goto 可以無條件跳轉到程序指定位置。

1 begin
2   if ... then
3  ... 4   else
5     null;--什麼也不做,但使整個語句塊更豐滿,可讀性更高
6   end if; 7 end;
 1 declare
 2   i int:=0;  3 begin
 4   <<outer>>--定義一個標籤
 5   i:=i+1;  6  dbms_output.put_line(i);  7   if i<10 then
 8     goto outer;--通過goto實現類似循環的結構
 9   else
10     null;--通過使用null讓語句塊更易讀
11   end if; 12 end;

  使用 goto 語句會破壞程序常規的執行流程,它是有別於順序、分支、循壞的另一種執行流程,如無特別需求,建議不要使用。

 

六  異常處理

  

  1,異常簡介

  無論何時何地何人,在編程的領域,總是無法避開異常。為了保證程序的健壯性,多數語言都提供了異常處理機制,PL/SQL 也不例外。

  在 PL/SQL 中,異常大致可分為兩大類:

    編譯時錯誤:程序在編寫過程中的錯誤,例如語法錯誤,訪問不存在的對象等,這類錯誤在編譯時 PL/SQL 引擎就會發現,並通知用戶。

    執行時錯誤:這類錯誤會順利通過程序的編譯環節,只能等到執行時才能被發現,比如除數是 0 。這類錯誤也是最要命的。

  

  2,異常處理語法

  我們知道,PL/SQL 程序分為三個部分:聲明區,執行區,異常處理區。基本的異常處理也包含此三個步驟:

    A:在定義區,定義異常。

    B:在執行區,觸發異常。

    C:只要執行區觸發了異常,那麼執行區後續的業務代碼都會立即停止執行,執行流程跳轉至異常處理區。

 1 declare
 2  異常變量名 exception;  3 begin
 4  ...  5  raise 異常變量名;  6  ...  7  exception  8       when 異常變量名  9         then ... 10 end;

  如果有多個異常,可以定義多個變量,並在合適的時候觸發他們,並在異常處理區通過多個 when…then 來捕獲他們,並執行特定操作。

  

  3,預定義異常

  大多數編譯時的異常,Oracle 都在內部隱式的定義好了,並且不需要在執行區手動的觸發,這類異常的處理最為簡單:

declare v_tmp varchar(10); begin v_tmp:='超過10字節的長度了'; exception when value_error then dbms_output.put_line('出現value_error錯誤!' || '錯誤編號:'|| sqlcode || '錯誤名稱' || sqlerrm); end;

  PL/SQL 中出現的錯誤,都一個錯誤號,一個錯誤編碼(sqlcode),一個錯誤名稱(sqlerrm)。在錯誤處理區通過在 when 後面指定錯誤名稱,既可捕獲到指定錯誤了。常見的預定義錯誤如下:

錯誤號 異常編碼 異常名稱 描述
ora-01012 -1017 not_logged_on 在沒有連接數據庫時訪問數據
ora-01403 100 no_date_found select…into沒有返回值
ora-01422 -1422 too_many_rows select…into結果集超過一行
ora-01476 -1476 zero_divide 除數為0
ora-01722 -1722 invalid_number 字符串和数字相加時,字符串轉換失敗
ora-06502 -6502 value-error 賦值時,變量長度不足
ora-06530 -6530 access_into_null 向null值對象賦值
ora-06592 -06592 case_not_found case語句中沒有任何匹配的值並且沒有else選項

  更多預定義異常請查詢 Oracle 11g 《Oracle 在線文檔》。

  

  4,自定義錯誤

 1 declare
 2   e_nocomm exception;--定義一個異常名稱
 3   v_comm number(10,2);  4 begin
 5   select comm into v_comm from emp where empno=&empno;  6   if v_comm is null
 7     then raise e_nocomm;--觸發自定義異常
 8   end if;  9  exception 10     when e_nocomm--捕獲自定義異常
11       then dbms_output.put_lne('該員工沒有提成'); 12     when others--捕獲未定義的錯誤 13       then dbms_output.put_line('未知錯誤 !'); 14 end;

  同一個塊中不能同時聲明一個異常多次,但不同的塊中可以定義相同的異常,在各自的塊中使用不會相互影響。

 

七  編程對象

  

  1,事務

  在 SQL Server 中,每一條 DML 語句都是一個隱式的事務,除非显示的開始一個事務,否則,這些語句執行完就立即向數據庫提交了這些更改。而在 Oracle 中,每一條 SQL 語句開始都會自動開啟一個事務,除非显示的使用 commit 提交,或退出某個開發工具而斷開連接,才會提交到數據庫,否則這些操作都只會保存在內存中。

 1 --在Oracle SQL Developer中
 2 begin
 3   insert into dept values(88,'開發部','cd');  4   savepoint a;--設置保存點a
 5   insert into dept values(88,'設計部','cd');  6  exception  7     when dup_val_on_index then
 8     dbms_output.put_line('插入出錯');  9     rollback to a;--回滾到a
10 end; 11 --這裏我們人為的製造了一個違反唯一約束的插入操作,在錯誤區捕獲該錯誤,然後回滾到保存點a
12 select * from dept;--只能查詢到開發部被插入
1 /* 在 SQL*Plus 中 */
2 SQL>select * from dept; 3 /* 連開發部都沒有被插入 */ 
1 -- 在 Oracle SQL Developer中
2 commit; 3 --現在插入已經被提交到數據庫,在SQL*Plus 中也可以查詢到了

  在多個事務併發執行時,大概率會發生:一個事務讀取到另一個事務還未提交的數據(臟讀);一個事務中不同時間點執行的同一個查詢,由於其他事務對涉及的數據進行了修改或刪除(不可重複讀)或插入(幻讀),而導致出現不一樣的結果。

  為了解決這樣的問題,Oracle 允許對事務設立隔離級別:

1 begin
2   commit; 3   set transaction read only;--只讀的事務
4   --settransaction read write;--可讀寫的事務
5   --set transaction isolation level [serializable | read commited];
6   --serializable:整個事務只能讀到當前事務開始前就以提交的數據
7   --read commited:當前事務中的查詢,只能讀到該查詢前以提交的數據(不是整個事務,而是該查詢語句。這也是 Oracle 默認的隔離級別)
8 end;

  由於一個事務中有且只能存在一條 set transaction 語句,且必須是事務的第一條語句,所以通常先使用 commit 結束前一個事務(理論上rollback也可以),以保證該語句是事務的第一條語句。

  

  2,子程序

  Oracle 中子程序事實上就是 SQL Server 中對存儲過程和用戶自定義函數的總稱。過程和函數本質上是一個命名塊,可以被存儲在數據庫中,並在合適的時候調用,這樣可以解決代碼重用的問題,並且由於它是已編譯好的代碼,所以執行起來也更快。

  過程和函數相比,過程不會返回值,常用來做數據的增刪改。而函數必須有返回值,通常用來嚮應用程序返回值。其他方面,過程和函數幾無區別。

  存儲過程:

1 --無參過程
2 create or replace procedure p2 as
3 begin
4   dbms_output.put_line('hello world'); 5 end p2; 6 --or replace:如果存在則替換存儲過程,建議使用
7 --p1:過程名
8 --as:不能省略,也可以用is代替
9 --end p2:創建完成時也要跟上過程名
 1 --帶參數的過程
 2 create or replace procedure p2(p_deptno in int)--使用括號添加過程需要的形參
 3 as
 4   v_empcount number;--定義過程中需要使用的變量,只需指定數據類型,不能添加類型所佔字節長度
 5 begin
 6   select count(ename) into v_empcount from emp where deptno=p_deptno;  7   if v_empcount>0 then
 8     dbms_output.put_line('有人');  9   else
10     dbms_output.put_line('沒人'); 11   end if; 12 end p2;--不要忘了過程名
1 --調用存儲過程
2 begin
3   p2(20);--通過()傳遞實參
4 end; 5 --call p2(20);

  函數:

 1 --創建函數
 2 create or replace function f1  3 return number--需要指定返回值類型,不需要長度
 4 as
 5 begin
 6   return 1;--需要使用return指定返回值
 7 end f1;  8 --調用函數
 9 declare 
10   v_f1 number(10); 11 begin
12   v_f1:=f1();--調用函數,並把返回值賦值給變量
13  dbms_output.put_line(v_f1); 14 end;

  在上面帶參數存儲過程中,指定形參時使用關鍵字 in,該關鍵字表示參數的模式是輸入型,可選的還有 out 輸出型,in out 輸入輸出型。如果不提供,默認是輸入型參數。

  in 模式的參數被用作輸入參數,在過程內部只能被訪問,不能被賦值。

  out  模式的參數被當做輸出參數使用,在過程內部可以被賦值,不能訪問。使用 out 類型參數時,必須在過程外部定義一個變量,用於接收過程在內部需要輸出的值,然後在調用子程序時把該變量當做形參傳入。待過程執行完畢,直接訪問外部定義的這個變量即可得到過程希望輸出的值了。

  in out 模式的參數既可以被當做輸入參數,也可以被當做輸出參數。使用方式和 out 型參數一致,但可以給這個變量一個初始化值,一併傳入過程內部。out 型參數即使傳入了初始值,也會被過程忽略。

  過程的參數模式和 MySQL 完全一致,例子可以參考我的《MySQL 編程》。函數本身就需要使用 return 返回值,所以不使用 in 或 out 指定參數模式,這樣毫無意義。

  

  3,觸發器

  Oracle 中的觸發器本質上也是一個命名的語句塊,定義的方式和 PL/SQL 語句塊差不多,但它和過程或函數不同,它只能被隱式的調用。並且不能接受任何參數。

  定義觸發器的語法:

1 create or replace trigger trigger_name--觸發器名稱
2 [before | after | instead of]--在事件之前還是之後執行觸發器中的代碼
3 trigger_event--觸發事件
4 [referenceing_caluse]--通過新的名稱引用當前正在更新的數據
5 [when trigger_condition]--指定觸發條件
6 [for each row]--指定行級觸發器(每一條記錄都觸發一次)
7 trigger_body--觸發體(程序塊)

  一個簡單例子:

 1 create test(--創建測試表
 2     id int primary key,  3     name varchar(20)  4 )  5 create or replace trigger t_test--創建觸發器
 6 after insert or update or delete--觸發操作(也可以是其中一種)
 7 on test--在表test上
 8 for each row--行級觸發器
 9 begin
10     if inserting then--在插入數據時
11         dbms_output.put_line('插入了數據,name:'||:new.name); 12     end if; 13     if updating then--在更新數據時
14         dbms_output.put_line('更新了數據,oldname:'||:old.name||',newname:'||:new.name); 15     end if; 16     if deleting then--在刪除數據時
17         dbms_output.put_line('刪除了數據,name:'||:old.name); 18     end if; 19 end;

  謂詞:new 表示引用新的數據(更新后或插入的數據),:old 引用舊的數據(被刪除的或更新前的數據)。可以在創建觸發器時通過 referencing(操作類型之後,for each row 之前) 指定新的謂詞。

1 ... 2 referencing old as test_old new as test_new 3 ... 4 --下面通過:test_old 引用修改前的數據,:test_new引用修改后的數據

  測試代碼:

1 insert into test values(1,'r'); 2 update test set name='e' where id=1; 3 delete from test where id=1; 4 --注意觀察輸出結果

  

  4,游標

  Oracle 中的游標用來處理多行多列的數據集合,包含四個步驟:定義,打開,遍歷,關閉。游標的語法如下:

1 cursor cursor_name [形參]--形參可以用來在where子句中限定游標記錄
2 [return type]--可選的指定游標返回的值類型
3 is query--通過is指定查詢(在這裏使用形參)
4 [for update[of column_list]]--允許在游標中修改表中的數據,並在游標打開期間鎖定選中的記錄

  下面是一個通過游標遍歷輸出 dept 部門信息的例子:

 1 declare
 2     deptrow dept%rowtype;--定義一個存儲記錄的變量
 3     cursor dept_cur is--通過cursor定義游標,is指定需要遍歷的結果集(一個查詢語句)
 4     select * from dept;  5 begin
 6     open dept_cur;--打開游標
 7     loop--通過循環遍歷游標中的記錄
 8         fetch dept_cur into deptrow;--通過fetch提取游標中記錄(每次一條)賦值給變量
 9         dbms_output.put_line(deptrow.deptno||':'||deptrow.dname); 10         exit when dept_cur%notfound;--通過%notfound判斷游標中是否還有記錄
11     end loop; 12     close dept_cur;--關閉游標
13 end;

  游標除了 %notfound 還有以下常用的的屬性:

1 cursor%isopen;--檢測游標是否已打開,打開返回ture,否則返回false
2 cursor%found;--檢測是否提取到值,提取到返回true,否者返回false
3 cursor%notfound;--與%found相反
4 cursor%rowcount;--統計到目前為止已提取的記錄數

  PL/SQL 中的三種循環都可以用來循環遍歷游標中的記錄,while 和 loop 相似,這裏不再舉例,for 循環專門對遍歷游標做了強化,工作中使用最多,也最方便:

1 delcare 2     cursor dept_cur is
3     select * from dept; 4 begin
5     for dept_row in dept_cur loop 6         dbms_output.put_line(deptrow.deptno||':'||deptrow.dname); 7     end loop; 8 end;

  dept_row 不需要顯式的聲明為記錄類型,PL/SQL 引擎自動隱式的聲明為 %rowtype。for 循環開始,自動打開游標,並自動提取記錄,然後賦值給dept_row,不用顯式的使用 fetch 提取記錄,循環完畢自動關閉游標並退出循環。

  

  5,包

  Oracle 中包(package)是一個工程化和面向對象的概念,它就像一個容器或命名空間,把邏輯相關的變量、類型、子程序或異常等組合起來一起存放,形成一個有序的組織單元或模塊,當我們編寫大型的複雜的應用程序時,我們就可以通過包來方便的歸類和管理各個功能模塊。

  完整的包由包規範和包體組成,但 Oracle 分開編譯的存儲包規範和包體,這又使得我們可以脫離包體使用包規範(反向不行)。包規範中主要是一些定義信息(也可以看成是 PL/SQL 提供的 API),比如記錄類型、變量、游標、異常和子程序的聲明。包體則負責實現包規範中定義的子程序。

  包規範簡單應用:

 1 create or replace package pkg1--創建包規範  2 as
 3   i int := 1;--標量變量
 4   dept_record dept%rowtype;--rowtype類型
 5   type dept_tab is table of varchar(20) index by pls_integer;--集合類型  6 end pkg1;  7 
 8 declare
 9  mydept pkg1.dept_tab;--創建一個包中集合類型的變量(通過"包.內容"的方式訪問包中的內容) 10 begin
11   select * into pkg1.dept_record from dept where deptno=10;--給包中定義的rowtype類型變量賦值 12  dbms_output.put_line(pkg1.dept_record.dname);--訪問包中的rowtype類型變量 13   dbms_output.put_line('-------------------------------------------');--分割線 14   for deptrow in (select * from dept) loop--使用游標給包中的集合賦值 15     mydept(pkg1.i) := deptrow.dname; 16     pkg1.i := pkg1.i+1;--修改包中的標量變量 17   end loop; 18   for j in 1..mydept.count loop--使用循環訪問集合 19  dbms_output.put_line(mydept(j)); 20   end loop; 21   pkg1.i := 1;--初始化包中的標量變量(防止下一次游標讀取不到數據) 22 end;

   在這個例子中,我們只創建了包規範,沒有包體,並且在包中定義了標量變量,rowtype類型(記錄類型同理),集合這些基本的數據類型,然後在 PL/SQL 程序塊中使用了他們。

  包規範中只有聲明,沒有具體的實現,事實上,包規範中的聲明的內容是公共的,對於一個方案來說,相當於一個全局的對象,在包內任何地方都能訪問他們。包規範和包體分別進行獨立的編譯和存儲,所以沒有包體,上訴例子任然能正常運行。

  另一個例子:

 1 create or replace package pkg2--創建包規範  2 as
 3   cursor dept_cur return dept%rowtype;--定義游標類型  4   procedure dept_ins(p_deptno int,p_dname varchar);--定義存儲過程  5   function f2 return varchar;--定義函數  6 end pkg2;  7 
 8 create or replace package body pkg2--創建包體  9 as
10   cursor dept_cur return dept%rowtype--創建游標 11   is
12     select * from dept; 13   procedure dept_ins(p_deptno in int,p_dname in varchar)--創建存儲過程 14   as
15   begin
16     insert into dept(deptno,dname) values(p_deptno,p_dname); 17     dbms_output.put_line('新增了部門:'|| p_deptno||','||p_dname); 18   end dept_ins; 19   function f2 return varchar--創建函數
20   is
21   begin
22     return '這是個函數'; 23   end f2; 24 end pkg2; 25 
26 
27 begin
28   for deptrow in pkg2.dept_cur loop--讀取游標 29  dbms_output.put_line(deptrow.dname); 30   end loop; 31   pkg2.dept_ins(99,'TI');--執行存儲過程 32  dbms_output.put_line(pkg2.f2());--執行函數 33 end;

  上面的例子在包體中定義了游標,存儲過程和函數,並且在包規範中也聲明了他們,這時候,存儲過程和函數、游標都是公開的了,如果在包體中創建的內容並未在包規範中定義,那麼我們說,這些內容是包私有的,不能在其他地方調用,而只能在包體內部使用。

  合理的使用包,有助於我們進行模塊化的程序開發;把邏輯相關的東西放在一個包中進行開發和管理,可以使我們的程序更加規範化;把一些重要的東西定義成包的私有內容,可以大大加強數據的安全性;另外,由於在使用包時, PL/SQL 會把整個包都加載到內存中,所以還可以提高程序運行效率。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

※別再煩惱如何寫文案,掌握八大原則!

Hook踩坑記:React Hook react-unity-webgl

  自公司前後分離上手React以來,一個坑一個坑的踩,Class的全生命周期雲里霧裡,還么屢明白,就抱上了Hook的大腿不鬆手,確實爽到飛起。修改到Hook的過程基本比較順暢,直接少了三分之一的代碼,組件更容易封裝,調試更方便,諸多優點在此不再贅述,已有各路大佬紛紛評價,此處貼上中文官方地址:React-Hook文檔。這裏主要講講修改到一塊關於 Unity 3D模型加載的踩坑記。

  背景:React 加載 Unity 3D模型 ,使用到一個插件 react-unity-webgl,感興趣的盆友可以自行查閱。

  因為Class改Hook處理語法變動,邏輯代碼基本不用怎麼改動,所以基本沒有阻力,但是當我把這塊業務代碼改成Hook時,跟模型交互時通信失敗,無法驅動模型動作。百思不得其解,弄了倆測試頁面,test_hook、test_class,只能debugger,一步一步調,發現一些端倪。

  Class 有些初始化的代碼 都寫在了constructor(props){},這個大家都明白,第一次加載頁面的時候會走。hook呢,最外層是一個大方法,之前遷移的時候就寫在方法里最頂部了,也沒什麼問題。加載模型第一句是 const unityContent = new UnityContent(參數1,參數2);兩個頁面都能加載出來模型,但是跟斷點發現hook頁面的 unityContent 對象比class的缺少了一個重要的屬性:unityInstance,通信的方法就是靠它 Send() 的,而且發現同一個對象,屬性id一直在變,原來每次修改state時,都會走聲明的這段方法,導致每次都 new 一個新的對象,導致unityInstance屬性沒有正確掛在unityContent對象上。

  在知道大概原理的情況下,搞成全局變量,在加載時判斷是否已經初始化,問題就迎刃而解了(其實費了九牛二虎之力)。

  寫過hook的盆友第一反應會想到聲明寫到useEffect,然後 [] 只執行一次才是正確的寫法。

  之所以沒有呢,是因為模型加載跟其他的業務沒什麼關係,我並不需要渲染完整個DOM在來加載,並且加載模型很費時間,必須要剛加載頁面就同時加載模型,所以才有此次踩坑記。

  總結:Hook寫在useEffect之外的代碼會多次加載(包括刷新狀態),要做好判斷,否則很容易產生bug。更推薦(官方推薦)按業務按順序把初始化方法寫到useEffect。

  本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

月銷過萬的國民小車換裝6AT 能否再一次引發爆款?

競品車型從定價上看,長安逸動的競品車型有非常多,畢竟這個價位區間的自主品牌緊湊型轎車特別多。帝豪GL指導價格:7。88-11。38萬艾瑞澤5指導價格:5。89-9。79萬海馬福美來指導價格:6。18-11。89萬長安逸動的優勢在於擁有兩廂版本與三廂版本兩種選擇餘地,可以滿足不同消費訴求的潛在買家,而兩廂版本的逸動XT說真的還是蠻多年輕人喜歡的類型。



有那麼一款車,在已經過去的十一個月平均銷量達到1.3萬台,它有着緊湊簡潔的外觀設計,也有着三廂版本與兩廂車型的區分,以此滿足不同胃口消費者的需求,它的動力總成表現平平,但平實好用,它叫長安逸動。

如今,長安逸動的下線產量已經突破300萬輛大關,而這個傲人的数字就由換裝愛信6AT變速箱的新款長安逸動來完成。搭載了全新傳動系統的逸動,將有怎樣的表現?

長安逸動

指導價格:8.99-10.39萬(1.6L 6AT版本)

由於僅僅是傳動系統的升級,長安逸動的外觀和內飾設計上並沒有什麼變化,包括車身三圍尺寸都於現款車型一模一樣,依舊維持了一種簡潔時尚的外觀造型。

長安逸動高銷量的原因也來自於較為用心質感出色的內飾裝配工藝,大量的軟質搪塑材料包裹,而且觸感較為細膩,整車內飾也會顯得高檔感比較出色。

作為最大的改動部分,愛信6AT的注入無疑是長安逸動新車上市的重頭戲,相較於之前較老式的4AT變速箱,6AT的變速箱理論上會更加省油而且也將汽車性能提升一個層級。發動機的參數沒有變化,依舊是最大馬力128匹,峰值扭矩168牛米的1.6L直噴發動機。

競品車型

從定價上看,長安逸動的競品車型有非常多,畢竟這個價位區間的自主品牌緊湊型轎車特別多。

帝豪GL

指導價格:7.88-11.38萬

艾瑞澤5

指導價格:5.89-9.79萬

海馬福美來

指導價格:6.18-11.89萬

長安逸動的優勢在於擁有兩廂版本與三廂版本兩種選擇餘地,可以滿足不同消費訴求的潛在買家,而兩廂版本的逸動XT說真的還是蠻多年輕人喜歡的類型。

以往的逸動只有手動和4AT的版本選擇,在市場反應中並不會顯得優勢明顯,而這次長安十分聰明的避開了雙離合的選擇而採用6AT,或許會讓一部分對於雙離合變速箱的潛在車主感到放心。

對於該車的購買建議是,可以考慮直接上到最頂配,10.39萬的售價並不會顯得太貴,長安的品控和做工對得起這個價格,而且在配置上,頂配逸動在無鑰匙進入、一鍵啟動、天窗、真皮多功能方向盤,自動泊車、EpS电子助力轉向、ESC車身穩定系統等科技配置裝配程度比較齊全。以上配置當然其他細分車型也有一部分搭載,但是頂配是絕對配置完善的版本。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

※別再煩惱如何寫文案,掌握八大原則!

務實省油能家用又個性 這台1.4T國貨SUV爆新消息

4T渦輪增壓發動機由東風自主研發,最大馬力140匹,峰值扭矩196牛米,傳動系統匹配5速手動變速箱,從8。17萬元的售價來看,因為雙離合的成本上升,小編預計未來AX3的售價將有所上浮。競品車型:吉利遠景SUV指導價格:7。49-10。

說到十萬級的自主SUV可以說是目前關注度超高的一個細分車型區間,雖然說自主品牌汽車的產品越來越豐富,但是依舊還有相當多的國產品牌車企進軍這個市場區間,東風風神AX3,就是這麼一款車型。

東風風神AX3

指導價格:6.97-8.77萬

(現款車型)

風神AX3在售車款僅有4AT自動擋和傳統的5速手動擋車型,在很多消費者看來傳動系統略顯寒摻,如今有媒體曝光了新款東風風神AX3的自動擋車型諜照,據悉該車未來將會在1.4T渦輪增壓車型當中搭載6速雙離合變速箱。

作為注入新的傳動系統的細分車型,風神AX3在外觀內飾設計方面並沒有什麼改動,從曝光的諜照中可以看到,AX3的換擋桿造型與當下風神另一款SUV車型AX5的造型一致,應該可以確定其變速箱是源自於格特拉克的6速濕式雙離合。

現款的風神AX3 1.4T車型搭載的1.4T渦輪增壓發動機由東風自主研發,最大馬力140匹,峰值扭矩196牛米,傳動系統匹配5速手動變速箱,從8.17萬元的售價來看,因為雙離合的成本上升,小編預計未來AX3的售價將有所上浮。

競品車型:

吉利遠景SUV

指導價格:7.49-10.19萬

吉利帝豪GS

指導價格:7.78-10.88萬

奇瑞瑞虎3

指導價格:6.89-9.29萬

全文總結:東風風神AX3並沒有特別出彩的外觀和內飾設計,以簡潔實用的風格示人,但是東風品牌的影響力還不錯,可以引得不少務實派的潛在車主注意,在十萬級自主SUV車型裏面,如今的競爭車型相當多,風神AX3要成為“國民車型”,也許要在配置和價格上做出更多的讓步。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

國產車你們真是夠了…逼得洋品牌無路可走

這是一個悲傷的故事合資品牌:國產車。你真夠了為什麼你們的設計越來越漂亮。家族式設計語言已經遍及各個車企在顏值方面雖說比較主觀但國產車的顏值普遍很高為什麼你們價低配置還比我們高。高性價比是國產車所主打的更能吸引消費者的關注為什麼你們動力越來越強了。

“國產車,你夠了”

相信這是眾多合資車型的心聲

很多年以前

我們買車的選擇很少!

合資車型來來去去

消費者都偏向於選擇那幾輛神車

像緊湊型轎車:捷達、卡羅拉

中型車:帕薩特、雅閣、凱美瑞

SUV:CRV、途觀等一系列的車型

直到今天

雖然合資車型的選擇很多

但是…

消費者選擇的車型

從每月銷量榜單就能看出來

賣得好的來來去去都是那幾輛

賣不好的車型基本都在底層掙扎

時代在進步,社會在發展

這一個囧況已經發生了改變

如同雨後竹筍那般

近幾年國產品牌集體發力

毛主席說過

星星之火可以燎原

於是…

這是一個悲傷的故事

合資品牌:國產車!你真夠了

為什麼你們的設計越來越漂亮!

家族式設計語言已經遍及各個車企

在顏值方面雖說比較主觀

但國產車的顏值普遍很高

為什麼你們價低配置還比我們高!

高性價比是國產車所主打的

更能吸引消費者的關注

為什麼你們動力越來越強了!

越來越多的自主發動機現身市場

在同排量的發動機下

自主發動機已經向合資發動機靠齊

但依舊存在一定的差距

發動機與變速箱的匹配依舊要加把勁

為什麼你們的質量越來越好了!

在整體水平上

近幾年國產車有了較大的飛躍

這包括質量上的進步

當然相比合資車型來說

國產車型的故障率會高一點

另外國產與合資的差距

主要表現在售後方面

這是國產品牌4S店急需改進的地方

國產車做得越來越好

對於我們也是好處多多!

國產車能打破合資車的垄斷

首先我們再也不需要總買合資品牌了

車型可選性越來越多

日後車型的配置越來越豐富

汽車的價格越做越便宜

這是眾多消費者最希望看到的東西本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

真正的SUV該有多硬派?帶你去看看這車有多野,上車!

硬派越野車跑鋪裝路面那舒適性真的是酸爽。所以適時四驅才是保證越野性能以及日常舒適性的最佳產物,駕駛員也不用操心驅動方面的問題,有路開過去就行了,這才符合消費者正常的用車需求。2。3T的動力到底行不行。在回程我特意試駕了2。

進入冬季,雪似乎成為了北方唯一的風景,白雪皚皚鋪滿的整片大地,江河都結成了冰,對於一個南方的孩子來說,我們都對北方的冬天十分嚮往。千里冰封的畫面很美,為了能夠進一步突顯旗下產品的性能,在北方搞起“冰雪試駕”的活動是眾多廠家每年冬季的首要任務。因為此前已經有去過東北地區的經歷,所以在行裝方面已經做到了最大程度的縮減。在東北地區的室外,帽子、手套、圍巾、厚襪子這是必需品,東北地區的室內都是有暖氣的存在,所以我也僅僅帶上了羽絨服和一件保暖的衝鋒衣。哦對了!請務必帶上秋褲。

還是得說一說北方地區的冷,在我看來這屬於物理攻擊,也可以叫乾冷,只要穿好保暖的衣服不讓呼呼的北風直吹皮膚,就能夠應付得了,而且北方地區的室內都很暖和。相比南方地區,那屬於法術攻擊,也可以叫濕冷,簡單來說就是穿多少衣服你依舊感受到那刺骨的冷,而且室內也沒有暖氣,反正走到哪兒都是冷。

40℃溫差的劇烈驟變

由於離機場的距離比較遠,所以12點45分就得登機,所以我就得提前三小時從家裡出發,記錄下當時廣州的溫度依舊在20℃左右(上機前還是得穿短袖),而長春當時的溫度已經在零下15℃左右。雖然有心理準備,但是剛下飛機那一刻,我還是冷蒙了。出了機場趕緊找到同行的廣州小分隊同仁,趕緊去往酒店休息為明天的活動做好準備。

翌日,在開過一輪簡單的產品介紹會後,我們終於開始了這一次活動——福特探險者輕奢越野體驗季Ⅲ探星之旅;走出酒店門口,7輛福特探險者已經在安靜地等候着我們,而且貼心的工作人員已經早早地把車給啟動了並且開足了暖氣,值得一說的是,或許方向盤加熱、座位加熱對於南方地區的人來說算得上是雞肋配置,但是在北方地區卻是一個非常實用的配置,除了入門版車型,探險者竟然連後排也帶有座位加熱,非常貼心。我們拿到的試駕車是一台3.5T的頂配探險者,對於一台售價為63.98萬的進口中大型SUV來說,該有的配置都會給你配備齊全,讓你無可挑剔。而區分探險者的配置水平很簡單,主要看“中網”,頂配鉑金版採用獨有的鍍鉻的蜂窩狀格柵,運動版則採用黑色的塑料材質中網,在發動機蓋撒謊那個還帶有“EXpLORER”的英文字;普通版則採用普通的鍍鉻中網。

福特探險者的車身尺寸為5037*2005*1818mm,軸距2860mm,走在哪兒都算得上是一個龐然大物,因為尺寸的問題在城市裡面駕駛也算是一件比較傷神的事情,不過在探險者上配備了併線輔助、車道偏離系統、180°前後攝像頭能夠最大程度地給你幫助你能夠在城區行駛更為從容;而提供了自動泊車輔助系統也能很好解決車主停車困難的問題。空間是這類中大型SUV所擅長的,得益於碩大的車身尺寸,探險者的座位結構為2+3+2的模式,值得一說的是探險者後排座椅都能電動按鈕調節,座椅放平后能形成一個純平極大的儲物空間,而最讓我感覺得實用的是探險者上前後均配備了足夠的USB插口,能夠讓你一家子的人都能找到USB插口充電。福特最新的SYNC 3也搭載在探險者上。

在前往松花湖的路線上,主要由城市道路高速、鄉村路段、越野路段組成。福特旗下的車型都帶有“運動”的基因,紮實的底盤表現,強悍的動力、充滿駕駛樂趣是我對這台大尺寸的探險者的評價,儘管在探險者上的這個6AT變速箱調校得很平順,在巡航時能夠將轉速拉得非常低,讓這車保持一個比較經濟的油耗,但是它在響應速度上依舊慢了半拍。

跑高速怎麼才能舒服?除了入門版,福特探險者均配備了ACC自適應巡航,能夠主動檢測前車速度,實現跟車功能。但有一點小遺憾,福特探險者輕奢越野體驗季Ⅲ來到長春已經是收官之戰,在此前這一批探險者已經跑過了全國各地,而且還挑戰了沙漠項目,跑沙漠對車輛的損耗是非常大的(自己的車還是建議不要拿去跑沙漠了)!由於傳感器的緣故,部分配置已經失效了。

北方地區還是買四驅SUV爽快

伴隨着一望無際的雪景,覆蓋冰雪的路面是非常危險的,摩擦力會大幅度下降,這樣很容易造成輪胎空轉、制動距離大幅度增加,所以在冬天你更需要更換一套“雪地輪胎”。路面在白雪覆蓋下可能暗含着結成堅冰的冰塊,讓你的輪胎瞬間失去抓地力,所以你需要一套強大的四驅系統,而福特的智能四驅系統卻能很好地解決這樣的問題,跑在冰雪的路面上,如履平地。另外這套4驅系統還提供普通模式、泥地模式、沙地模式、雪地模式選擇,而且在行車過程中也能自主切換,足以讓你應對各種路況。

說實話,有很多人都在糾結這一個適時四驅的問題!因為分時四驅才是越野的王者,其實這並沒有絕對的事情,分時四驅都應用在硬派越野車上,如果你不是越野迷,又不是拿去跑異常極端的越野道路,你真需要分時四驅?硬派越野車跑鋪裝路面那舒適性真的是酸爽!所以適時四驅才是保證越野性能以及日常舒適性的最佳產物,駕駛員也不用操心驅動方面的問題,有路開過去就行了,這才符合消費者正常的用車需求。

2.3T的動力到底行不行?

在回程我特意試駕了2.3T版本的車型,跟野馬同款的發動機,經過重新調校提供276匹馬力,410牛米的動力,拖動這樣一台重達2噸多的SUV是完全夠用的,雖然同位6AT的變速箱,但是在調校上跟3.5T版本的車型也會有所不同。在相應方面比3.5T更敏捷,輕踩油門立馬會作出降擋的動作,能帶給你更為輕快的感覺。

隨着一邊享受探險者給你帶來澎湃動力快感的同時,周圍的溫度已經降至零下20多度,所以…無論是相機還是手機,掉電飛快,甚至已經自動關機了,於是有了以上烤蘋果這一幕,貌似能給蘋果公司打了一個小廣告。

探星之旅得等到晚上!

當然就是觀星!在這樣一個零下20多度的氣溫下,頂着嚴寒,跑到了郊外,架起一台望遠鏡探索神秘的銀河系。只可惜我並不是天文愛好者,配上多雲的天氣,感覺那天的月亮還是挺大的,上圖是通過望遠鏡拍攝下來的月亮圖片。

來到活動的尾聲,這樣冰天雪地的地方,我們怎麼少得了高山滑雪?極限運動是眾多男孩子心中所追求的,踩着滑雪板,享受從高山上飛馳下來的快感可以用一個“爽”字形容。但這隻是我自己瞎想出來的快感,因為作為新手的我只能在初級滑道做起了最強王者。

44.98-63.98萬的售價值嗎?

福特探險者已經連續26年成為北美最暢銷SUV,高達700萬+的全球銷量也足以證明它是一款熱門SUV,但在我國汽車市場上依舊屬於一台少眾車型。因為同價位可選的車型實在太多,但它整體的表現還是值得肯定。

福特探險者擁有大氣的外觀、豐富的配置、領先同級的動力水平,無疑競爭力十足!但是進口美系車都有一個比較大的缺點——粗獷,雖然用料很足,但是內飾的設計並不會給你帶來太多的高級感,甚至會讓給你覺得略顯粗糙;在配置上全系使用鹵素的遠光燈源實在配不上它該有的身份,這些地方都是有待改進的!拋開這些問題,如果真要購買這台車,相信我會選擇49.98萬的2.3T精英版或者追求運動個性,選擇59.98萬3.5T的運動版。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

開發內容分解的9個角度

在開發工作中,我們常常要將整體的開發內容分解成一些較小的部分,分而治之。 原因不限於以下幾種:

  • 分解和抽象使得開發內容更容易被理解。
  • 可以將分解后的開發內容分配給多人開發。
  • 分解后的開發時間更容易估算,進度更易於衡量,有利於做計劃。

古人說“橫看成嶺側成峰”,意指從不同的角度觀察事物時會得到不同的抽象。開發工作與之類似,當開發者從不同的角度進行分解工作時,會對開發內容產生不同的理解,因此分解后得出的產物可能也並不相同。從哪些角度對開發內容的分解才是最優的?這往往沒有固定的答案,要由分解的目的決定。下面會介紹9種常見分解角度。

 

本文鏈接:https://www.cnblogs.com/hhelibeb/p/13070646.html

轉載請註明

形式與結構

形式與結構,指的是開發內容中全部的開發對象,以及它們之間的關係。比如,一個客戶信用檢查程序可能包含表、視圖、鎖對象、接口、類等一些開發對象,它們之間會存在一定的連接關係。

從這個角度分解的優點在於它十分具體,有一些屬性可以通過求和直接得到,例如,表和字段的數量意味着要增加多少種存儲信息。

對形式的分析也可以提示開發者將連接關係較多的東西歸為一組,如果把它們分解到不同的地方,可能會導致複雜度增加,需要很多額外的工作來傳遞信息,對開發內容的分析和理解將變得困難。

功能

形式代表了靜態存在的對象,而功能是指它們能做什麼。功能是開發工作的價值體現。

一般來說,程序的命名即可提現它的功能。比如“供應商信用檢查程序”顯然指出了程序的功能是檢查供應商的信用。如果將這個程序從功能角度分解,可以分解為設定信用額度的功能、計算佔用額度的功能、集成到付款/採購流程的功能、從外部系統查詢供應商信用的功能等。

按功能分解開發對象是最直觀的分解方式之一,它有助於開發者從系統整體層面思考問題。比如,如果要考慮程序的性能問題,從功能角度的分解可以讓人分析各個子功能的性能如何、它們集成到一起時有可能發生什麼問題。又比如,如果要增加一個“黑名單/白名單”子功能的話,我們可以從功能角度審視這一新功能對其它各個子功能產生何種影響。

設計的自由度

如果能把緊密耦合的對象歸為一個模塊,並使之與外界盡可能的隔離,就能在模塊內部得到更大的自由度。

這裏以abap-data-validator為例,該項目的每個檢查規則都位於單獨的類中,這些類實現了同一個接口ZIF_ADV_CHECK,如下圖。這使得每個類的開發者不需要與其它類的開發者共享任何信息,可以在自己負責的類中任意發揮,實現功能。而ZIF_ADV_CHECK約束了這些類,使它們遵循相同的檢查接口約定。

 

另一種思路是把這些檢查功能都放置在同一個類中,用不同的類方法實現它們,如下圖。顯而易見,這樣做的好處是降低了總體複雜度(方法數不變,類減少為1個),缺點是不同的方法會共享類的信息,有可能出現一些跨方法的東西,這會降低設計的自由度。對檢查接口的約束也成為了一種隱式的規則,這會增大開發者的心智負擔,容易產生誤解。

 

 

這兩種做法沒有絕對的優劣,abap-data-validator選擇了前者,是因為開發者在經過權衡后認為,為了讓社區的同行方便地增加自己的新的檢查規則,付出增加一定的複雜度的代價是可以接受的。雖然到目前為止尚還沒有人給這個項目貢獻新規則。

程序的進化

程序的功能通常有不斷增加的趨勢 ,我們把功能增加的過程稱為進化。從進化的角度進行分解時,開發者需要考慮如何讓新舊功能方便地結合。以創建採購訂單的程序為例,如果考慮到程序未來會有對訂單進行其它檢查的需求,那麼就要分解出單獨的檢查模塊,並提供接口。這樣的話,如果要增加供應商信用檢查功能,那麼只要通過這個接口來實現就好。從進化角度的分解可以讓程序在在進化中保持架構的穩定。

系統間的集成

系統間集成的工作常常會出現很多誤解,因為系統間通常只靠接口交流,其它信息完全是隱藏的。未知帶來了思維盲區和錯誤假設。我之前也寫過博客感慨這類工作的不易(《 關於
接口開發和聯調的一些感想 》)。 從集成角度分解開發內容時,一個重要目標是盡可能
避免誤解。這要求,

  • 接口要易於測試。這樣可以增加接口的可信度,測試也有利於人們理解接口的功能。
  • 接口的表面複雜度要低。這意味着要對接口內部進行分解,將複雜度轉移到下層,或者將某些副作用轉移到接口之外的其它地方。

技術更新

我們時常需要使用新技術替換舊技術,這會為我們帶來功能、性能或者KPI上的收益。從技術更新的角度考慮開發內容的分解時,就要把特定技術相關的部分分離,從而使得在不影響其它部分的情況下將技術變化,或者讓新舊技術可以同時運行,逐步替換舊技術。

銷售

有時,出於營銷與銷售的目的,程序的某些特性需要可以組合、開關、調節、修飾。這時,開發者需要從銷售的角度思考開發內容的分解,做出可定製的程序,滿足銷售的目的。

投資

對於老闆們來說,開發是一項針對未來的投資。他們預先支付薪水,接着期望開發者們交付的東西能幫助公司節約開支、獲取收入。他們的心中可能存在一個簡單公式,用來衡量程序開發工作的意義:

利潤 = 收入 – 費用

付給開發人員的錢可以被看做費用,那麼,收入在哪裡?分解開發內容時,要注意分解后的模塊可以在一定的投資下產生價值,並且需要論證如果有後續投資的話可以產生更多價值。否則老闆們可能會認為把開發人員裁掉才是更經濟的選擇。

組織架構

康威定律指出:

設計系統的架構受制於產生這些設計的組織的溝通結構。

就像程序模塊間存在信息傳遞的問題一樣,不同的團隊之間的溝通也會存在問題。程序的分解應該和組織形成匹配的關係,這樣可以避免一些額外的工作和糟糕的結果。

以上文提到過的為例,開源社區的開發成員之間只有鬆散的連接關係,因此,如果該項目的目標是讓社區成員參与開發,那麼就要盡可能地減少檢查類之間的共享信息,選取第一種分解方式。如下圖,

反之,如果這完全是個內部項目,由單人開發,且完成後接口幾乎不會發生變化,那麼第二種分解方式可能更為合適。如下圖,

總結

本文介紹了開發內容分解的9個角度,這些角度在具體的實踐中可能有重合或者衝突。從不同的角度考慮分解工作可以讓我們產生不同的理解,更全面地審視自己的工作。但要注意的是分解並非越多越好,比如在設計自由度中我們提到分解導致的複雜度增加也會成為代價。要從整體考慮和觀察開發內容,選取合適的角度。本文也沒有涵蓋所有的分解角度。

  本文的主要思想來自於《 系統架構》,結合了個人的一些開發實踐,有興趣了解更多的話可以看這本書。                       本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

走私野生動物製品 7中國人遭馬拉威判刑

摘錄自2020年7月21日中央社報導

2019年3月,九名中國人及四名馬拉威人因走私野生生物,遭馬拉威警方與野生動物管理局 突襲後落網。

馬拉威法院今天(21日)宣布,此走私集團的領袖林勻華及其妻子張晴華(Quin Hua Zhang,音譯)違法持有犀牛角與槍械,將被監禁11年。另兩位中國人因藏匿犀牛角,遭判刑七年;另三人持有穿山甲鱗片及象牙,被判六年刑期。兩名馬拉威人非法擁有象牙及河馬牙,被判18個月的有期徒刑。

法新社報導,這九名罪犯隸屬非洲南部最活耀的野生生物走私集團。

馬拉威國家公園管理處官員庫姆奇德瓦(Brighton Kumchedwa)向法新社表示:「馬拉威再也不是這些野生動物走私犯的樂園了。」

生物多樣性
國際新聞
馬拉威
走私
犀牛角
象牙

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

日導演評《福島50英雄》:「引發災難的責任者,突然變成正義的英雄」

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益