Java內嵌資料庫-H2資料庫

H2是開源的輕量級Java資料庫。它可以嵌入Java應用程式中或以客戶端-伺服器模式執行。H2資料庫主要可以配置為作為記憶體資料庫執行,這意味著資料將不會持久儲存在磁碟上。由於具有嵌入式資料庫,因此它不用於生產開發,而主要用於開發和測試。

可以在嵌入式模式或伺服器模式下使用此資料庫。以下是H2資料庫的主要功能-

極快的開源JDBC API

在嵌入式和伺服器模式下可用;記憶體資料庫

基於瀏覽器的控制檯應用程式

佔用空間小-jar檔案大小約為1。5MB

H2資料庫的功能

H2資料庫的主要特點如下-

這是一個非常快的資料庫引擎。

H2是開源的,並用Java編寫。

它支援標準的SQL和JDBC API。它也可以使用PostgreSQL ODBC驅動程式。

它具有嵌入式和伺服器模式。

H2支援

叢集

多版本併發

它具有強大的安全功能。

附加功能

以下是H2資料庫的一些其他功能-

H2是基於磁碟的或記憶體中的資料庫和表,只讀資料庫支援,臨時表。

H2提供事務支援(已提交讀),兩階段提交的多個連線,表級鎖定。

H2是基於成本的最佳化程式,使用遺傳演算法進行復雜查詢(零管理)。

H2包含可滾動和可更新的結果集支援,大結果集,外部結果排序,函式可以返回結果集。

H2支援加密資料庫(AES),SHA-256密碼加密,加密功能和SSL。

H2資料庫中的元件

為了使用H2資料庫,您需要具有以下元件-

網路瀏覽器

H2控制檯伺服器

這是一個客戶端/伺服器應用程式,因此伺服器和客戶端(瀏覽器)都需要執行它。

H2資料庫-安裝

H2是用Java編寫的資料庫。透過使用JDBC,我們可以輕鬆地將此資料庫嵌入到我們的應用程式中。我們可以在許多不同的平臺或任何版本的Java Runtime Environment上執行它。但是,在安裝資料庫之前,應在系統中安裝Java。

驗證Java安裝

如果系統中安裝了JDK,請嘗試以下命令來驗證Java版本。

java –version

如果JDk成功安裝在系統中,那麼我們將獲得以下輸出。

java version “1。8。0_91”

Java(TM) SE Runtime Environment (build 1。8。0_91-b14)

Java HotSpot(TM) 64-Bit Server VM (build 25。91-b14, mixed mode)

如果系統中未安裝JDK,則訪問下面的Install JDK連結。

安裝H2資料庫

我們可以在許多不同的平臺上執行此資料庫。在本章中,我們將學習在Windows上安裝H2資料庫的知識。

以下是在Windows作業系統上安裝H2資料庫的步驟。

步驟1:下載H2設定檔

從給定的連結下載最新版本的H2資料庫。在此連結中,您將獲得兩種型別的H2資料庫的最新版本。一種是Windows Installer型別(即。exe檔案),另一種是其他作業系統的與平臺無關的zip檔案。

下載。exe檔案後,單擊Windows安裝程式以下載Windows支援的H2資料庫。在這種情況下,我們將使用H2資料庫的1。4。192版本。

步驟2:安裝H2資料庫

下載後,我們在下載目錄中獲得了H2 Windows安裝程式檔案(即h2-setup-yyyy-mm-dd。exe)。要開始H2資料庫的安裝過程,請雙擊安裝程式檔案。

以下螢幕是安裝過程的第一步。提供一個我們要在其中安裝H2資料庫伺服器的路徑,如以下螢幕快照所示。

Java內嵌資料庫-H2資料庫

如上面的螢幕截圖所示,預設情況下它將以

C:\ ProgramFiles(x86)\ H2

作為目標資料夾。單擊下一步繼續進行下一步。彈出以下螢幕。

Java內嵌資料庫-H2資料庫

在上面的螢幕截圖中,單擊“安裝”按鈕以開始安裝過程。安裝後,我們得到以下螢幕截圖。

Java內嵌資料庫-H2資料庫

單擊完成以完成安裝過程。

步驟3:驗證H2資料庫安裝

安裝後,讓我們驗證系統中的資料庫安裝。單擊Windows→鍵入H2控制檯→單擊H2控制檯圖示。連線到URL

http:// localhost:8082

。在連線時,H2資料庫將要求資料庫註冊,如以下螢幕截圖所示。

Java內嵌資料庫-H2資料庫

在上面的對話方塊中填寫所有詳細資訊,例如“儲存的設定”,“設定名稱”,“驅動程式類”,“ JDBC URL”,“使用者名稱”和“密碼”。在JDBC URL中,指定資料庫的位置和資料庫名稱。使用者名稱和密碼是資料庫的使用者名稱和密碼的欄位。單擊連線。

彈出資料庫歡迎頁面,如以下螢幕截圖所示。

Java內嵌資料庫-H2資料庫

H2資料庫-選擇

Select命令用於從一個或多個表中獲取記錄資料。如果我們設計一個選擇查詢,那麼它將以結果表的形式返回資料,稱為

結果集

句法

SELECT語句的基本語法如下-

SELECT [ TOP term ] [ DISTINCT | ALL ] selectExpression [,。。。]

FROM tableExpression [,。。。] [ WHERE expression ]

[ GROUP BY expression [,。。。] ] [ HAVING expression ]

[ { UNION [ ALL ] | MINUS | EXCEPT | INTERSECT } select ] [ ORDER BY order [,。。。] ]

[ [ LIMIT expression ] [ OFFSET expression ] [ SAMPLE_SIZE rowCountInt ] ]

[ FOR UPDATE ]

要獲取所有可用欄位,請使用以下語法。

SELECT * FROM table_name;

考慮具有以下記錄的CUSTOMER表-

+——+——————+——-+——————-+——————+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+——————-+——————+

| 1 | Ramesh | 32 | Ahmedabad | 2000。00 |

| 2 | Khilan | 25 | Delhi | 1500。00 |

| 3 | kaushik | 23 | Kota | 2000。00 |

| 4 | Chaitali | 25 | Mumbai | 6500。00 |

| 5 | Hardik | 27 | Bhopal | 8500。00 |

| 6 | Komal | 22 | MP | 4500。00 |

| 7 | Muffy | 24 | Indore | 10000。00 |

+——+——————+——-+——————-+——————+

要獲取客戶表以及給定的資料,請執行以下查詢。

CREATE TABLE CUSTOMER (id number, name varchar(20), age number, address varchar(20),

salary number);

INSERT into CUSTOMER values (1, ‘Ramesh’, 32, ‘Ahmedabad’, 2000);

INSERT into CUSTOMER values (2, ‘Khilan’, 25, ‘Delhi’, 1500);

INSERT into CUSTOMER values (3, ‘kaushik’, 23, ‘Kota’, 2000);

INSERT into CUSTOMER values (4, ‘Chaitali’, 25, ‘Mumbai’, 6500);

INSERT into CUSTOMER values (5, ‘Hardik’, 27, ‘Bhopal’, 8500);

INSERT into CUSTOMER values (6, ‘Komal’, 22, ‘MP’, 4500);

INSERT into CUSTOMER values (7, ‘Muffy’, 24, ‘Indore’, 10000);

以下命令是一個示例,它將獲取CUSTOMER表中可用的客戶的ID,名稱和薪水欄位。

SELECT ID, NAME, SALARY FROM CUSTOMERS;

上面的命令產生以下結果。

+——+——————+——————+

| ID | NAME | SALARY |

+——+——————+——————+

| 1 | Ramesh | 2000。00 |

| 2 | Khilan | 1500。00 |

| 3 | kaushik | 2000。00 |

| 4 | Chaitali | 6500。00 |

| 5 | Hardik | 8500。00 |

| 6 | Komal | 4500。00 |

| 7 | Muffy | 10000。00 |

+——+——————+——————+

使用以下查詢來獲取CUSTOMERS表的所有欄位。

SQL> SELECT * FROM CUSTOMERS;

上面的查詢產生以下結果-

+——+——————+——-+——————-+——————+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+——————-+——————+

| 1 | Ramesh | 32 | Ahmedabad | 2000。00 |

| 2 | Khilan | 25 | Delhi | 1500。00 |

| 3 | kaushik | 23 | Kota | 2000。00 |

| 4 | Chaitali | 25 | Mumbai | 6500。00 |

| 5 | Hardik | 27 | Bhopal | 8500。00 |

| 6 | Komal | 22 | MP | 4500。00 |

| 7 | Muffy | 24 | Indore | 10000。00 |

+——+——————+——-+——————-+——————+

H2資料庫-插入

SQL INSERT語句用於將新的資料行新增到資料庫中的表。

句法

以下是INSERT INTO語句的基本語法。

INSERT INTO tableName

{ [ ( columnName [,。。。] ) ]

{ VALUES

{ ( { DEFAULT | expression } [,。。。] ) } [,。。。] | [ DIRECT ] [ SORTED ] select } } |

{ SET { columnName = { DEFAULT | expression } } [,。。。] }

使用此INSERT語句,我們可以在表中插入新記錄或新行。使用DIRECT子句時,結果將直接影響目標表,而無需任何中間步驟。但是,在為表的所有列新增值時,請確保值的順序與表中的列的順序相同。

讓我們以一個示例為例,嘗試將以下給定記錄插入到Customer表中。

ID

名稱

年齡

地址

薪水

1個

拉梅什

32

艾哈邁達巴德

2000

2

吉蘭

25

新德里

1500

3

考希克

23

哥打

2000

4

柴尾

25

孟買

6500

5

哈迪克

27

博帕爾

8500

6

科馬爾

22

MP

4500

7

瑪菲

24

印多爾

10000

透過執行以下命令,我們可以將所有給定的記錄獲取到客戶表中。

INSERT INTO CUSTOMER VALUES (1, ‘Ramesh’, 32, ‘Ahmedabad’, 2000);

INSERT INTO CUSTOMER VALUES (2, ‘Khilan’, 25, ‘Delhi’, 1500);

INSERT INTO CUSTOMER VALUES (3, ‘kaushik’, 23, ‘Kota’, 2000);

INSERT INTO CUSTOMER VALUES (4, ‘Chaitali’, 25, ‘Mumbai’, 6500);

INSERT INTO CUSTOMER VALUES (5, ‘Hardik’, 27, ‘Bhopal’, 8500);

INSERT INTO CUSTOMER VALUES (6, ‘Komal’, 22, ‘MP’, 4500);

INSERT INTO CUSTOMER VALUES (7, ‘Muffy’, 24, ‘Indore’, 10000);

H2資料庫-更新

UPDATE查詢用於更新或修改表中的現有記錄。我們可以將WHERE子句與UPDATE查詢一起使用來更新所選行,否則所有行都會受到影響。

句法

以下是UPDATE查詢的基本語法。

UPDATE tableName [ [ AS ] newTableAlias ] SET

{ { columnName = { DEFAULT | expression } } [,。。。] } |

{ ( columnName [,。。。] ) = ( select ) }

[ WHERE expression ] [ ORDER BY order [,。。。] ] [ LIMIT expression ]

在此UPDATE語法中,我們可以使用AND或OR子句組合多個條件。

考慮具有以下記錄的CUSTOMER表。

+——+——————+——-+——————-+——————+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+——————-+——————+

| 1 | Ramesh | 32 | Ahmedabad | 2000。00 |

| 2 | Khilan | 25 | Delhi | 1500。00 |

| 3 | kaushik | 23 | Kota | 2000。00 |

| 4 | Chaitali | 25 | Mumbai | 6500。00 |

| 5 | Hardik | 27 | Bhopal | 8500。00 |

| 6 | Komal | 22 | MP | 4500。00 |

| 7 | Muffy | 24 | Indore | 10000。00 |

+——+——————+——-+——————-+——————+

如果要獲取客戶表以及給定的資料,請執行以下查詢。

CREATE TABLE CUSTOMER (id number, name varchar(20), age number, address varchar(20),

salary number);

INSERT into CUSTOMER values (1, ‘Ramesh’, 32, ‘Ahmedabad’, 2000);

INSERT into CUSTOMER values (2, ‘Khilan’, 25, ‘Delhi’, 1500);

INSERT into CUSTOMER values (3, ‘kaushik’, 23, ‘Kota’, 2000);

INSERT into CUSTOMER values (4, ‘Chaitali’, 25, ‘Mumbai’, 6500);

INSERT into CUSTOMER values (5, ‘Hardik’, 27, ‘Bhopal’, 8500);

INSERT into CUSTOMER values (6, ‘Komal’, 22, ‘MP’, 4500);

INSERT into CUSTOMER values (7, ‘Muffy’, 24, ‘Indore’, 10000);

以下命令是一個示例,它將為ID為6的客戶更新ADDRESS-

UPDATE CUSTOMERS SET ADDRESS = ‘Pune’ WHERE ID = 6;

現在,CUSTOMERS表將具有以下記錄。我們可以透過執行以下查詢來檢查客戶表記錄。

SELECT * FROM CUSTOMERS;

上面的查詢產生以下結果。

+——+——————+——-+——————-+——————+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+——————-+——————+

| 1 | Ramesh | 32 | Ahmedabad | 2000。00 |

| 2 | Khilan | 25 | Delhi | 1500。00 |

| 3 | kaushik | 23 | Kota | 2000。00 |

| 4 | Chaitali | 25 | Mumbai | 6500。00 |

| 5 | Hardik | 27 | Bhopal | 8500。00 |

| 6 | Komal | 22 | Pune | 4500。00 |

| 7 | Muffy | 24 | Indore | 10000。00 |

+——+——————+——-+——————-+——————+

要修改CUSTOMERS表中的所有ADDRESS和SALARY列值,我們不需要使用WHERE子句。UPDATE查詢將如下所示-

UPDATE CUSTOMERS SET ADDRESS = ‘Pune’, SALARY = 1000。00;

現在,CUSTOMERS表將具有以下記錄。我們可以透過執行以下查詢來檢查客戶表記錄。

SELECT * FROM CUSTOMERS;

上面的查詢產生以下結果-

+——+——————+——-+————-+————-+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+————-+————-+

| 1 | Ramesh | 32 | Pune | 1000。00 |

| 2 | Khilan | 25 | Pune | 1000。00 |

| 3 | kaushik | 23 | Pune | 1000。00 |

| 4 | Chaitali | 25 | Pune | 1000。00 |

| 5 | Hardik | 27 | Pune | 1000。00 |

| 6 | Komal | 22 | Pune | 1000。00 |

| 7 | Muffy | 24 | Pune | 1000。00 |

+——+——————+——-+————-+————-+

H2資料庫-刪除

SQL DELETE查詢用於從表中刪除現有記錄。我們可以將WHERE子句與DELETE查詢一起使用,以刪除選定的記錄,否則將刪除所有記錄。

句法

以下是delete命令的通用查詢語法。

DELETE [ TOP term ] FROM tableName [ WHERE expression ] [ LIMIT term ]

上面的語法從表中刪除行。如果指定了TOP或LIMIT,則最多刪除指定的行數(如果為null或小於零,則沒有限制)。

考慮具有以下記錄的CUSTOMER表。

+——+——————+——-+——————-+——————+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+——————-+——————+

| 1 | Ramesh | 32 | Ahmedabad | 2000。00 |

| 2 | Khilan | 25 | Delhi | 1500。00 |

| 3 | kaushik | 23 | Kota | 2000。00 |

| 4 | Chaitali | 25 | Mumbai | 6500。00 |

| 5 | Hardik | 27 | Bhopal | 8500。00 |

| 6 | Komal | 22 | MP | 4500。00 |

| 7 | Muffy | 24 | Indore | 10000。00 |

+——+——————+——-+——————-+——————+

以下命令將刪除ID為6的客戶的詳細資訊。

DELETE FROM CUSTOMERS WHERE ID = 6;

執行上述命令後,透過執行以下命令檢查Customer表。

SELECT * FROM CUSTOMERS;

上面的命令產生以下輸出-

+——+——————+——-+——————-+——————+

| ID | NAME | AGE | ADDRESS | SALARY |

+——+——————+——-+——————-+——————+

| 1 | Ramesh | 32 | Ahmedabad | 2000。00 |

| 2 | Khilan | 25 | Delhi | 1500。00 |

| 3 | kaushik | 23 | Kota | 2000。00 |

| 4 | Chaitali | 25 | Mumbai | 6500。00 |

| 5 | Hardik | 27 | Bhopal | 8500。00 |

| 7 | Muffy | 24 | Indore | 10000。00 |

+——+——————+——-+——————-+——————+

如果要從CUSTOMERS表中刪除所有記錄,則不要使用WHERE子句。DELETE查詢如下。

DELETE FROM CUSTOMER;

執行上述命令後,Customer表中將沒有可用的記錄。

H2資料庫-備份

BACKUP是用於將資料庫備份放入單獨的。zip檔案中的命令。物件沒有被鎖定,並且在進行備份時,事務日誌也會被複制。執行此命令需要管理員許可權。

句法

以下是Backup命令的通用語法。

BACKUP TO fileNameString;

在此示例中,讓我們將當前資料庫的備份

複製

backup.zip

檔案中。相同地使用以下命令。

BACKUP TO ‘backup。zip’;

執行上述命令後,您將在本地檔案系統中獲取backup。zip檔案。

H2資料庫-通話

CALL是屬於H2資料庫伺服器的SQL命令。此命令用於計算簡單表示式。它在單個列欄位中返回給定表示式的結果。當它返回結果陣列時,該陣列中的每個元素都顯示為列值。

句法

以下是CALL命令的通用語法。

CALL expression;

我們可以在這種語法中使用算術表示式。

讓我們舉個例子,並使用呼叫命令執行算術表示式(15 * 25)。

CALL 15*25;

上面的命令產生以下輸出。

H2資料庫-說明

EXPLAIN命令顯示一條語句的執行計劃。當我們使用EXPLAIN ANALYZE命令執行語句時,查詢計劃將包括每個表的實際行掃描計數。

句法

以下是EXPLAIN命令的通用語法。

EXPLAIN { [ PLAN FOR ] | ANALYZE } { select | insert | update | delete | merge}

連同此語法,我們可以使用選擇,插入,刪除和合並。

本示例說明ID為1的客戶的查詢計劃詳細資訊。

EXPLAIN SELECT * FROM CUSTOMER WHERE ID = 1;

上面的命令產生以下輸出-

Java內嵌資料庫-H2資料庫

H2資料庫-合併

MERGE命令用於更新現有行並將新行插入表中。使用此命令時,主鍵列起著重要的作用。它用於查詢行。

句法

以下是MERGE命令的通用語法。

MERGE INTO tableName [ ( columnName [,。。。] ) ]

[ KEY ( columnName [,。。。] ) ]

{ VALUES { ( { DEFAULT | expression } [,。。。] ) } [,。。。] | select }

在以上語法中,KEY子句用於指定主鍵列名稱。連同VALUES子句,我們可以使用基本值插入,也可以使用select命令將另一個表值檢索並存儲到該表中。

在此示例中,讓我們嘗試將新記錄新增到“客戶”表中。以下是表中新記錄的詳細資訊。

欄名

ID

8

名稱

洛克希

年齡

32

地址

海得拉巴

薪水

2500

使用以下查詢,讓我們將給定記錄插入到H2資料庫查詢中。

MERGE INTO CUSTOMER KEY (ID) VALUES (8, ‘Lokesh’, 32, ‘Hyderabad’, 2500);

上面的查詢產生以下輸出。

Update count: 1

讓我們透過執行以下查詢來驗證Customer表的記錄。

SELECT * FROM CUSTOMER;

上面的查詢產生以下輸出。

ID

名稱

年齡

地址

薪水

1個

拉梅什

32

艾哈邁達巴德

2000

2

吉蘭

25

新德里

1500

3

考希克

23

哥打

2000

4

Chaitali

25

孟買

6500

5

哈迪克

27

博帕爾

8500

6

科馬爾

22

MP

4500

7

瑪菲

24

印多爾

10000

8

洛克希

32

海得拉巴

2500

現在讓我們嘗試使用

Merge

命令更新記錄。以下是要更新的記錄的詳細資訊。

欄名

ID

8

名稱

洛基

年齡

32

地址

海得拉巴

薪水

3000

使用以下查詢將給定記錄插入到H2資料庫查詢中。

MERGE INTO CUSTOMER KEY (ID) VALUES (8, ‘Loki’, 32, ‘Hyderabad’, 3000);

上面的查詢產生以下輸出。

Update count: 1

讓我們透過執行以下查詢來驗證Customer表的記錄。

SELECT * FROM CUSTOMER;

上面的查詢產生以下輸出-

ID

名稱

年齡

地址

薪水

1個

拉梅什

32

艾哈邁達巴德

2000

2

吉蘭

25

新德里

1500

3

考希克

23

哥打

2000

4

Chaitali

25

孟買

6500

5

哈迪克

27

博帕爾

8500

6

科馬爾

22

MP

4500

7

瑪菲

24

印多爾

10000

8

洛基

32

海得拉巴

3000

H2資料庫-顯示

SHOW是用於顯示錶的架構,表或列的列表的命令。

句法

以下是SHOW命令的通用語法。

SHOW { SCHEMAS | TABLES [ FROM schemaName ] |

COLUMNS FROM tableName [ FROM schemaName ] }

以下命令可用於獲取當前資料庫中的表列表。

SHOW TABLES;

上面的命令產生以下輸出。

TABLE_NAME

TABLE_SCHEMA

顧客

上市

電磁脈衝

上市

H2資料庫-建立

CREATE是一個通用的SQL命令,用於在H2資料庫伺服器中建立表,模式,序列,檢視和使用者。

建立表格

建立表是用於在當前資料庫中建立使用者定義表的命令。

句法

以下是“建立表”命令的通用語法。

CREATE [ CACHED | MEMORY ] [ TEMP | [ GLOBAL | LOCAL ] TEMPORARY ]

TABLE [ IF NOT EXISTS ] name

[ ( { columnDefinition | constraint } [,。。。] ) ]

[ ENGINE tableEngineName [ WITH tableEngineParamName [,。。。] ] ]

[ NOT PERSISTENT ] [ TRANSACTIONAL ]

[ AS select ]

透過使用Create Table命令的通用語法,我們可以建立不同型別的表,例如快取表,記憶體表和臨時表。以下是描述與給定語法不同的子句的列表。

CACHED

-快取表是常規表的預設型別。這意味著行數不受主儲存器的限制。

記憶體

-記憶體表是臨時表的預設型別。這意味著記憶體表不應太大,索引資料將保留在主記憶體中。

TEMPORARY-

在關閉或開啟資料庫時刪除臨時表。基本上,臨時表有兩種型別- 全域性型別-所有連線均可訪問。本地型別-當前連線可訪問。

臨時表的預設型別是全域性型別。臨時表的索引保留在主記憶體中,除非使用CREATE CACHED TABLE建立臨時表。

ENGINE-

僅當使用自定義表實現時才需要ENGINE選項。

NOT PERSISTENT-

這是一個修飾符,用於將完整的表資料保留在記憶體中,並且在關閉資料庫時所有行都會丟失。

TRANSACTIONAL-

這是一個提交開放事務的關鍵字,此命令僅支援臨時表。

在此示例中,讓我們使用以下給定資料建立一個名為tutorials_tbl的表。

序號

欄名

資料型別

1個

ID

整數

2

標題

Varchar(50)

3

作者

Varchar(20)

4

提交日期

日期

以下查詢用於與給定的列資料一起建立表

tutorials_tbl

CREATE TABLE tutorials_tbl (

id INT NOT NULL,

title VARCHAR(50) NOT NULL,

author VARCHAR(20) NOT NULL,

submission_date DATE

);

上面的查詢產生以下輸出。

(0) rows effected

建立架構

建立模式是用於在特定授權下(在當前註冊的使用者下)建立與使用者相關的模式的命令。

句法

以下是“建立模式”命令的通用語法。

CREATE SCHEMA [ IF NOT EXISTS ] name [ AUTHORIZATION ownerUserName ]

在以上通用語法中,AUTHORIZATION是用於提供相應使用者名稱的關鍵字。此命令是可選的,這意味著如果我們不提供使用者名稱,則它將考慮當前使用者。執行命令的使用者必須具有管理員許可權以及所有者。

該命令在此連線中提交一個開啟的事務。

在此示例中,讓我們使用以下命令在SA使用者下建立一個名為

test_schema

的架構。

CREATE SCHEMA test_schema AUTHORIZATION sa;

上面的命令產生以下輸出。

(0) rows effected

建立序列

序列是一個概念,用於透過遵循id或任何隨機列值的序列來生成數字。

句法

以下是create sequence命令的通用語法。

CREATE SEQUENCE [ IF NOT EXISTS ] newSequenceName [ START WITH long ]

[ INCREMENT BY long ]

[ MINVALUE long | NOMINVALUE | NO MINVALUE ]

[ MAXVALUE long | NOMAXVALUE | NO MAXVALUE ]

[ CYCLE long | NOCYCLE | NO CYCLE ]

[ CACHE long | NOCACHE | NO CACHE ]

此通用語法用於建立序列。序列的資料型別為

BIGINT

。按照這種順序,即使回滾了事務,也永遠不會重複使用值。

在此示例中,讓我們使用以下查詢建立一個名為

SEQ_ID

的序列。

CREATE SEQUENCE SEQ_ID;

上面的查詢產生以下輸出。

(0) rows effected

H2資料庫-更改

ALTER是用於透過向

alter

命令新增不同的子句來更改表結構的命令。根據場景,我們需要在alter命令中新增相應的子句。在本章中,我們將討論alter命令的各種情況。

修改表新增

Alter Table Add是用於將新列以及相應資料型別新增到表中的命令。此命令在此連線中提交事務。

句法

以下是“更改表新增”命令的通用語法。

ALTER TABLE [ IF EXISTS ] tableName ADD [ COLUMN ]

{ [ IF NOT EXISTS ] columnDefinition [ { BEFORE | AFTER } columnName ]

| ( { columnDefinition } [,。。。] ) }

在此示例中,我們將在表

tutorials_tbl中

新增新列

start_date

。start_date的資料型別為Date。以下是新增新列的查詢。

ALTER TABLE tutorials_tbl ADD start_date DATE;

上面的查詢產生以下輸出。

(6) rows effected

更改表新增約束

更改表新增約束是用於向表新增不同約束的命令,例如主鍵,外來鍵,非null等。

如果所需的索引尚不存在,則會自動建立它們。無法禁用唯一約束檢查​。該命令在此連線中提交一個開啟的事務。

句法

以下是“更改表新增約束”命令的通用語法。

ALTER TABLE [ IF EXISTS ] tableName ADD constraint [ CHECK | NOCHECK ]

在此示例中,讓我們使用以下查詢將主鍵約束

(tutorials_tbl_pk)新增

到表

tutorials_tbl

的列ID中。

ALTER TABLE tutorials_tbl ADD CONSTRAINT tutorials_tbl_pk PRIMARYKEY(id);

上面的查詢產生以下輸出。

(6) row (s) effected

更改表重新命名約束

此命令用於重新命名特定關係表的約束名稱。該命令在此連線中提交一個開啟的事務。

句法

以下是“更改表重新命名約束”命令的通用語法。

ALTER TABLE [ IF EXISTS ] tableName RENAME oldConstraintName TO newConstraintName

使用此語法時,請確保舊的約束名稱應與相應的列一起存在。

在此示例中,我們將表

tutorials_tbl

的主鍵約束名稱從

tutorials_tbl_pk

更改為

tutorials_tbl_pk_constraint

。以下是這樣做的查詢。

ALTER TABLE tutorials_tbl RENAME CONSTRAINT

tutorials_tbl_pk TO tutorials_tbl_pk_constraint;

上面的查詢產生以下輸出。

(1) row (s) effected

變更表變更列

此命令用於更改特定表的列的結構和屬性。更改屬性意味著更改列的資料型別,重新命名列,更改標識值或更改選擇性。

句法

以下是“ Alter Table Alter Column”命令的通用語法。

ALTER TABLE [ IF EXISTS ] tableName ALTER COLUMN columnName

{ { dataType [ DEFAULT expression ] [ [ NOT ] NULL ] [ AUTO_INCREMENT | IDENTITY ] }

| { RENAME TO name }

| { RESTART WITH long }

| { SELECTIVITY int }

| { SET DEFAULT expression }

| { SET NULL }

| { SET NOT NULL } }

在上面的語法中-

RESTART-

命令更改自動遞增列的下一個值。

SELECTIVITY-

命令設定列的選擇性(1-100)。基於選擇性值,我們可以對列的值進行成像。

SET DEFAULT-

更改列的預設值。

SET NULL-

將列設定為允許NULL。

SET NOT NULL-

將列設定為允許NOT NULL。

在此示例中,我們將使用以下查詢將表

tutorials_tbl

的列從

Title

重新命名為

Tutorial_Title

ALTER TABLE tutorials_tbl ALTER COLUMN title RENAME TO tutorial_title;

上面的查詢產生以下輸出。

(0) row(s) effected

以類似的方式,我們可以使用ALTER命令執行不同的場景。

H2資料庫-刪除

DROP是從通用SQL語法中提取的命令。此命令用於從記憶體中刪除資料庫元件及其結構。我們將在本章中討論Drop命令的不同情況。

放置表

刪除表是刪除相應表及其結構的命令。

句法

以下是Drop Table命令的通用語法。

DROP TABLE [ IF EXISTS ] tableName [,。。。] [ RESTRICT | CASCADE ]

如果我們使用的是RESTRICT並且存在具有依賴檢視的表,則該命令將失敗。當我們使用CASCADE關鍵字時,將刪除所有從屬檢視。

在此示例中,我們將使用以下查詢刪除名為test的表。

DROP TABLE test;

上面的查詢產生以下輸出。

(6) row (s) effected

刪除架構

刪除模式是從資料庫伺服器刪除相應模式的命令。它不適用於當前架構。

句法

DROP SCHEMA [ IF EXISTS ] schemaName

在此示例中,我們將使用以下查詢刪除名為

test_schema

的架構。

DROP SCHEMA TEST_SCHEMA;

上面的查詢產生以下輸出。

(0) row(s) effected

掉落順序

刪除序列是用於從表結構中刪除序列的命令。

句法

以下是“丟棄序列”命令的通用語法。

DROP SEQUENCE [ IF EXISTS ] sequenceName

該命令在此連線中提交一個開啟的事務。

在此示例中,我們將刪除一個名為

sequence_id的序列

。以下是命令。

DROP SEQUENCE sequence_id;

上面的命令產生以下輸出。

(0) row (s) effected

放下檢視

刪除檢視是用於刪除現有檢視的命令。如果使用CASCADE子句,所有從屬檢視也將被刪除。

句法

以下是Drop View命令的通用語法。

DROP VIEW [ IF EXISTS ] viewName [ RESTRICT | CASCADE ]

在此示例中,我們將使用以下查詢刪除名為

sample_view

的檢視。

DROP VIEW sample_view;

上面的查詢產生以下輸出。

(0) row (s) effected

H2資料庫-截斷

TRUNCATE是用於從表中刪除資料的命令。與不帶WHERE子句的DELETE FROM不同,此命令無法回滾。該命令在此連線中提交一個開啟的事務。

句法

以下是truncate命令的通用語法。

TRUNCATE TABLE tableName

在此示例中,我們將使用以下查詢截斷名為

test

的表。

TRUNCATE TABLE test;

上面的查詢產生以下輸出。

(6) row (s) effected

H2資料庫-提交

COMMIT是來自SQL語法的命令,用於提交事務。我們可以提交特定事務,也可以提交當前執行的事務。

句法

COMMIT命令有兩種不同的語法。

以下是commit命令提交當前事務的通用語法。

COMMIT [ WORK ]

以下是commit命令提交特定事務的通用語法。

COMMIT TRANSACTION transactionName

例子1

在此示例中,讓我們使用以下命令來提交當前事務。

COMMIT

上面的命令產生以下輸出。

Committed successfully

例子2

在此示例中,我們將使用以下命令提交名為

tx_test

的事務。

COMMIT TRANSACTION tx_test;

上面的命令產生以下輸出。

Committed successfully

H2資料庫-Grant

Grant是來自SQL語法的命令,用於向表,使用者或角色授予許可權。執行此命令需要管理員許可權。該命令在此連線中提交一個開啟的事務。

在本章中,我們將討論Grant命令的不同情況。

授予權

授予許可權是用於向表,使用者或角色提供管理員許可權的命令。

句法

以下是Grant命令的通用語法。

GRANT { SELECT | INSERT | UPDATE | DELETE | ALL } [,。。。] ON

{ { SCHEMA schemaName } | { tableName [,。。。] } }

TO { PUBLIC | userName | roleName }

在此示例中,我們將使用以下命令將測試表授予只讀許可權。

GRANT SELECT ON TEST TO READONLY

上面的命令產生以下輸出。

Grant successfully

授予更改任何架構

授予任何模式更改許可是向相應使用者授予模式更改許可權的命令。

句法

以下是Grant Alter Any Schema命令的通用語法。

GRANT ALTER ANY SCHEMA TO userName

在此示例中,我們將向一個名為

test_user

的使用者授予更改模式的特權。確保test_user存在。以下是授予更改特權的查詢。

GRANT ALTER ANY SCHEMA TO test_user;

上面的查詢產生以下輸出。

Granted successfully to test_user

H2資料庫-儲存點

SAVEPOINT是用於臨時儲存事務的命令。最好在事務中維護儲存點,因為在必要時將事務回滾到相應的儲存點會很有幫助。

句法

以下是Savepoint命令的通用語法。

SAVEPOINT savepointName

在此示例中,我們將使用以下命令建立一個名為Half_Done的儲存點。

SAVEPOINT Half_Done;

上面的命令產生以下輸出。

Savepoint created

H2資料庫-回滾

ROLLBACK是SQL語法中的命令,用於將事務回滾到Savepoint或上一個事務。透過使用此命令,我們可以回滾到特定的儲存點,也可以回滾到先前執行的事務。

句法

ROLLABCK命令有兩種不同的語法。

以下是rollback命令的通用語法。

ROLLBACK [ TO SAVEPOINT savepointName ]

以下是回滾命令對特定事務的通用語法。

ROLLBACK TRANSACTION transactionName

例子1

在此示例中,我們將使用以下命令將當前事務回滾到名為

sp1_test

的儲存點。

ROLLBACK sp1_test;

上面的命令產生以下輸出。

Rollback successfully

例子2

在下面的示例中,我們將使用給定的命令回滾名為

tx_test

的完整事務。

ROLLBACK TRANSACTION tx_test;

上面的命令產生以下輸出。

Rollback successfully

H2資料庫-JDBC連線

H2是一個JAVA資料庫。我們可以使用JDBC與該資料庫進行互動。在本章中,我們將看到如何與H2資料庫建立JDBC連線以及如何與H2資料庫建立CRUD操作。

通常,建立JDBC連線有五個步驟。

步驟1-

註冊JDBC資料庫驅動程式。

Class。forName (“org。h2。Driver”);

步驟2-

開啟連線。

Connection conn = DriverManager。getConnection (“jdbc:h2:~/test”, “sa”,“”);

步驟3-

建立一條語句。

Statement st = conn。createStatement();

步驟4-

執行一條語句並接收結果集。

Stmt。executeUpdate(“sql statement”);

步驟5-

關閉連線。

conn。close();

在繼續建立完整程式之前,我們需要將

h2-1.4.192.jar檔案

新增到CLASSPATH。我們可以從資料夾

C:\ Program Files(x86)\ H2 \ bin中

獲得此

jar

建立表格

在此示例中,我們將編寫一個用於建立表的程式。考慮一個名為

Registration

的表,該表具有以下欄位。

序號

欄名

資料型別

非空

首要的關鍵

1個

ID

2

第一

瓦爾查(255)

沒有

沒有

3

持續

瓦爾查(255)

沒有

沒有

4

年齡

沒有

沒有

以下是一個名為

H2jdbcCreateDemo

的示例程式。

import java。sql。Connection;

import java。sql。DriverManager;

import java。sql。SQLException;

import java。sql。Statement;

public class H2jdbcCreateDemo {undefined

// JDBC driver name and database URL

static final String JDBC_DRIVER = “org。h2。Driver”;

static final String DB_URL = “jdbc:h2:~/test”;

// Database credentials

static final String USER = “sa”;

static final String PASS = “”;

public static void main(String[] args) {undefined

Connection conn = null;

Statement stmt = null;

try {undefined

// STEP 1: Register JDBC driver

Class。forName(JDBC_DRIVER);

//STEP 2: Open a connection

System。out。println(“Connecting to database。。。”);

conn = DriverManager。getConnection(DB_URL,USER,PASS);

//STEP 3: Execute a query

System。out。println(“Creating table in given database。。。”);

stmt = conn。createStatement();

String sql = “CREATE TABLE REGISTRATION ” +

“(id INTEGER not NULL, ” +

“ first VARCHAR(255), ” +

“ last VARCHAR(255), ” +

“ age INTEGER, ” +

“ PRIMARY KEY ( id ))”;

stmt。executeUpdate(sql);

System。out。println(“Created table in given database。。。”);

// STEP 4: Clean-up environment

stmt。close();

conn。close();

} catch(SQLException se) {undefined

//Handle errors for JDBC

se。printStackTrace();

} catch(Exception e) {undefined

//Handle errors for Class。forName

e。printStackTrace();

} finally {undefined

//finally block used to close resources

try{undefined

if(stmt!=null) stmt。close();

} catch(SQLException se2) {undefined

} // nothing we can do

try {undefined

if(conn!=null) conn。close();

} catch(SQLException se){undefined

se。printStackTrace();

} //end finally try

} //end try

System。out。println(“Goodbye!”);

}

}

將以上程式儲存到H2jdbcCreateDemo。java中。透過在命令提示符下執行以下命令來編譯並執行上述程式。

\>javac H2jdbcCreateDemo。java

\>java H2jdbcCreateDemo

上面的命令產生以下輸出。

Connecting to database。。。

Creating table in given database。。。

Created table in given database。。。

Goodbye!

執行完之後,我們可以檢查使用H2 SQL介面建立的表。

插入記錄

在此示例中,我們將編寫一個用於插入記錄的程式。讓我們將以下記錄插入到Registration表中。

ID

第一

持續

年齡

100

扎拉

阿里

18歲

101

馬納茲

法特瑪

25

102

扎伊德

可汗

30

103

住友

道德的

28

以下是一個名為

H2jdbcInsertDemo

的示例程式。

import java。sql。Connection;

import java。sql。DriverManager;

import java。sql。SQLException;

import java。sql。Statement;

public class H2jdbcInsertDemo {undefined

// JDBC driver name and database URL

static final String JDBC_DRIVER = “org。h2。Driver”;

static final String DB_URL = “jdbc:h2:~/test”;

// Database credentials

static final String USER = “sa”;

static final String PASS = “”;

public static void main(String[] args) {undefined

Connection conn = null;

Statement stmt = null;

try{undefined

// STEP 1: Register JDBC driver

Class。forName(JDBC_DRIVER);

// STEP 2: Open a connection

System。out。println(“Connecting to a selected database。。。”);

conn = DriverManager。getConnection(DB_URL,USER,PASS);

System。out。println(“Connected database successfully。。。”);

// STEP 3: Execute a query

stmt = conn。createStatement();

String sql = “INSERT INTO Registration ” + “VALUES (100, ‘Zara’, ‘Ali’, 18)”;

stmt。executeUpdate(sql);

sql = “INSERT INTO Registration ” + “VALUES (101, ‘Mahnaz’, ‘Fatma’, 25)”;

stmt。executeUpdate(sql);

sql = “INSERT INTO Registration ” + “VALUES (102, ‘Zaid’, ‘Khan’, 30)”;

stmt。executeUpdate(sql);

sql = “INSERT INTO Registration ” + “VALUES(103, ‘Sumit’, ‘Mittal’, 28)”;

stmt。executeUpdate(sql);

System。out。println(“Inserted records into the table。。。”);

// STEP 4: Clean-up environment

stmt。close();

conn。close();

} catch(SQLException se) {undefined

// Handle errors for JDBC

se。printStackTrace();

} catch(Exception e) {undefined

// Handle errors for Class。forName

e。printStackTrace();

} finally {undefined

// finally block used to close resources

try {undefined

if(stmt!=null) stmt。close();

} catch(SQLException se2) {undefined

} // nothing we can do

try {undefined

if(conn!=null) conn。close();

} catch(SQLException se) {undefined

se。printStackTrace();

} // end finally try

} // end try

System。out。println(“Goodbye!”);

}

}

將以上程式儲存到H2jdbcInsertDemo。java中。透過在命令提示符下執行以下命令來編譯並執行上述程式。

\>javac H2jdbcInsertDemo。java

\>java H2jdbcInsertDemo

上面的命令產生以下輸出。

Connecting to a selected database。。。

Connected database successfully。。。

Inserted records into the table。。。

Goodbye!

讀取記錄

在此示例中,我們將編寫一個用於讀取記錄的程式。讓我們嘗試從表

Registration中

讀取所有記錄。

以下是一個名為

H2jdbcRecordDemo

的示例程式。

import java。sql。Connection;

import java。sql。DriverManager;

import java。sql。ResultSet;

import java。sql。SQLException;

import java。sql。Statement;

public class H2jdbcReadDemo {undefined

// JDBC driver name and database URL

static final String JDBC_DRIVER = “org。h2。Driver”;

static final String DB_URL = “jdbc:h2:~/test”;

// Database credentials

static final String USER = “sa”;

static final String PASS = “”;

public static void main(String[] args) {undefined

Connection conn = null;

Statement stmt = null;

try {undefined

// STEP 1: Register JDBC driver

Class。forName(JDBC_DRIVER);

// STEP 2: Open a connection

System。out。println(“Connecting to database。。。”);

conn = DriverManager。getConnection(DB_URL,USER,PASS);

// STEP 3: Execute a query

System。out。println(“Connected database successfully。。。”);

stmt = conn。createStatement();

String sql = “SELECT id, first, last, age FROM Registration”;

ResultSet rs = stmt。executeQuery(sql);

// STEP 4: Extract data from result set

while(rs。next()) {undefined

// Retrieve by column name

int id = rs。getInt(“id”);

int age = rs。getInt(“age”);

String first = rs。getString(“first”);

String last = rs。getString(“last”);

// Display values

System。out。print(“ID: ” + id);

System。out。print(“, Age: ” + age);

System。out。print(“, First: ” + first);

System。out。println(“, Last: ” + last);

}

// STEP 5: Clean-up environment

rs。close();

} catch(SQLException se) {undefined

// Handle errors for JDBC

se。printStackTrace();

} catch(Exception e) {undefined

// Handle errors for Class。forName

e。printStackTrace();

} finally {undefined

// finally block used to close resources

try {undefined

if(stmt!=null) stmt。close();

} catch(SQLException se2) {undefined

} // nothing we can do

try {undefined

if(conn!=null) conn。close();

} catch(SQLException se) {undefined

se。printStackTrace();

} // end finally try

} // end try

System。out。println(“Goodbye!”);

}

}

將以上程式儲存到H2jdbcReadDemo。java中。透過在命令提示符下執行以下命令來編譯並執行上述程式。

\>javac H2jdbcReadDemo。java

\>java H2jdbcReadDemo

上面的命令產生以下輸出。

Connecting to a selected database。。。

Connected database successfully。。。

ID: 100, Age: 18, First: Zara, Last: Ali

ID: 101, Age: 25, First: Mahnaz, Last: Fatma

ID: 102, Age: 30, First: Zaid, Last: Khan

ID: 103, Age: 28, First: Sumit, Last: Mittal

Goodbye!

更新記錄

在此示例中,我們將編寫一個程式來更新記錄。讓我們嘗試從表

Registration中

讀取所有記錄。

以下是一個名為

H2jdbcUpdateDemo

的示例程式。

import java。sql。Connection;

import java。sql。DriverManager;

import java。sql。ResultSet;

import java。sql。SQLException;

import java。sql。Statement;

public class H2jdbcUpdateDemo {undefined

// JDBC driver name and database URL

static final String JDBC_DRIVER = “org。h2。Driver”;

static final String DB_URL = “jdbc:h2:~/test”;

// Database credentials

static final String USER = “sa”;

static final String PASS = “”;

public static void main(String[] args) {undefined

Connection conn = null;

Statement stmt = null;

try {undefined

// STEP 1: Register JDBC driver

Class。forName(JDBC_DRIVER);

// STEP 2: Open a connection

System。out。println(“Connecting to a database。。。”);

conn = DriverManager。getConnection(DB_URL,USER,PASS);

// STEP 3: Execute a query

System。out。println(“Connected database successfully。。。”);

stmt = conn。createStatement();

String sql = “UPDATE Registration ” + “SET age = 30 WHERE id in (100, 101)”;

stmt。executeUpdate(sql);

// Now you can extract all the records

// to see the updated records

sql = “SELECT id, first, last, age FROM Registration”;

ResultSet rs = stmt。executeQuery(sql);

while(rs。next()){undefined

// Retrieve by column name

int id = rs。getInt(“id”);

int age = rs。getInt(“age”);

String first = rs。getString(“first”);

String last = rs。getString(“last”);

// Display values

System。out。print(“ID: ” + id);

System。out。print(“, Age: ” + age);

System。out。print(“, First: ” + first);

System。out。println(“, Last: ” + last);

}

rs。close();

} catch(SQLException se) {undefined

// Handle errors for JDBC

se。printStackTrace();

} catch(Exception e) {undefined

// Handle errors for Class。forName

e。printStackTrace();

} finally {undefined

// finally block used to close resources

try {undefined

if(stmt!=null) stmt。close();

} catch(SQLException se2) {undefined

} // nothing we can do

try {undefined

if(conn!=null) conn。close();

} catch(SQLException se) {undefined

se。printStackTrace();

} // end finally try

} // end try

System。out。println(“Goodbye!”);

}

}

將以上程式儲存到H2jdbcUpdateDemo。java中。透過在命令提示符下執行以下命令來編譯並執行上述程式。

\>javac H2jdbcUpdateDemo。java

\>java H2jdbcUpdateDemo

上面的命令產生以下輸出。

Connecting to a selected database。。。

Connected database successfully。。。

ID: 100, Age: 30, First: Zara, Last: Ali

ID: 101, Age: 30, First: Mahnaz, Last: Fatma

ID: 102, Age: 30, First: Zaid, Last: Khan

ID: 103, Age: 28, First: Sumit, Last: Mittal

Goodbye!

刪除記錄

在此示例中,我們將編寫一個程式來刪除記錄。讓我們嘗試從表

Registration中

讀取所有記錄。

以下是一個名為

H2jdbcDeleteDemo

的示例程式。

import java。sql。Connection;

import java。sql。DriverManager;

import java。sql。ResultSet;

import java。sql。SQLException;

import java。sql。Statement;

public class H2jdbcDeleteDemo {undefined

// JDBC driver name and database URL

static final String JDBC_DRIVER = “org。h2。Driver”;

static final String DB_URL = “jdbc:h2:~/test”;

// Database credentials

static final String USER = “sa”;

static final String PASS = “”;

public static void main(String[] args) {undefined

Connection conn = null;

Statement stmt = null;

try {undefined

// STEP 1: Register JDBC driver

Class。forName(JDBC_DRIVER);

// STEP 2: Open a connection

System。out。println(“Connecting to database。。。”);

conn = DriverManager。getConnection(DB_URL,USER,PASS);

// STEP 3: Execute a query

System。out。println(“Creating table in given database。。。”);

stmt = conn。createStatement();

String sql = “DELETE FROM Registration ” + “WHERE id = 101”;

stmt。executeUpdate(sql);

// Now you can extract all the records

// to see the remaining records

sql = “SELECT id, first, last, age FROM Registration”;

ResultSet rs = stmt。executeQuery(sql);

while(rs。next()){undefined

// Retrieve by column name

int id = rs。getInt(“id”);

int age = rs。getInt(“age”);

String first = rs。getString(“first”);

String last = rs。getString(“last”);

// Display values

System。out。print(“ID: ” + id);

System。out。print(“, Age: ” + age);

System。out。print(“, First: ” + first);

System。out。println(“, Last: ” + last);

}

rs。close();

} catch(SQLException se) {undefined

// Handle errors for JDBC

se。printStackTrace();

} catch(Exception e) {undefined

// Handle errors for Class。forName

e。printStackTrace();

} finally {undefined

// finally block used to close resources

try {undefined

if(stmt!=null) stmt。close();

} catch(SQLException se2) {undefined

} // nothing we can do

try {undefined

if(conn!=null) conn。close();

} catch(SQLException se) {undefined

se。printStackTrace();

} // end finally try

} // end try

System。out。println(“Goodbye!”);

}

}

將以上程式儲存到H2jdbcDeleteDemo。java中。透過在命令提示符下執行以下命令來編譯並執行上述程式。

\>javac H2jdbcDeleteDemo。java

\>java H2jdbcDeleteDemo

上面的命令產生以下輸出。

Connecting to a selected database。。。

Connected database successfully。。。

ID: 100, Age: 30, First: Zara, Last: Ali

ID: 102, Age: 30, First: Zaid, Last: Khan

ID: 103, Age: 28, First: Sumit, Last: Mittal

Goodbye!