2023年8月21日 星期一

Linux Mint在升級後,Docker就無法安裝的解決方法

【前言】

前幾天,我把VM上的Linux Mint從21.1升級到了21.2,然後再來安裝Docker時,Docker就一直出錯,再也裝不起來了。後來解決了,解決方法如下。

【解決過程】

 先來看看情況是怎樣?

cheeren@cheeren-virtual-machine:~$ sudo apt-get update

[sudo] cheeren 的密碼:         

已有:1 http://free.nchc.org.tw/ubuntu jammy InRelease

已有:2 http://free.nchc.org.tw/ubuntu jammy-updates InRelease                  

已有:3 http://free.nchc.org.tw/ubuntu jammy-backports InRelease                

已有:4 https://dl.google.com/linux/chrome/deb stable InRelease                 

略過:5 http://ftp.tku.edu.tw/Linux/LinuxMint/linuxmint victoria InRelease      

已有:6 http://ftp.tku.edu.tw/Linux/LinuxMint/linuxmint victoria Release        

已有:7 http://packages.microsoft.com/repos/code stable InRelease               

已有:8 https://packages.microsoft.com/repos/edge stable InRelease              

已有:9 http://security.ubuntu.com/ubuntu jammy-security InRelease              

正在讀取套件清單... 完成

cheeren@cheeren-virtual-machine:~$ sudo apt-get install \

    ca-certificates \

    curl \

    gnupg \

    lsb-release

正在讀取套件清單... 完成

正在重建相依關係... 完成  

正在讀取狀態資料... 完成  

lsb-release 已是最新版本 (11.1.0ubuntu4)。

ca-certificates 已是最新版本 (20230311ubuntu0.22.04.1)。

curl 已是最新版本 (7.81.0-1ubuntu1.13)。

gnupg 已是最新版本 (2.2.27-3ubuntu2.1)。

升級 0 個,新安裝 0 個,移除 0 個,有 2 個未被升級。

cheeren@cheeren-virtual-machine:~$ sudo mkdir -p /etc/apt/keyrings

cheeren@cheeren-virtual-machine:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

檔案 '/etc/apt/keyrings/docker.gpg' 已存在. 是否覆寫?(y/N) y

cheeren@cheeren-virtual-machine:~$ echo \

  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \

  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

cheeren@cheeren-virtual-machine:~$ sudo apt-get update

已有:1 http://free.nchc.org.tw/ubuntu jammy InRelease

已有:2 http://free.nchc.org.tw/ubuntu jammy-updates InRelease                  

已有:3 http://free.nchc.org.tw/ubuntu jammy-backports InRelease                

已有:4 https://dl.google.com/linux/chrome/deb stable InRelease                 

已有:5 http://packages.microsoft.com/repos/code stable InRelease               

略過:6 http://ftp.tku.edu.tw/Linux/LinuxMint/linuxmint victoria InRelease      

已有:7 http://ftp.tku.edu.tw/Linux/LinuxMint/linuxmint victoria Release        

已有:8 https://packages.microsoft.com/repos/edge stable InRelease

已有:9 http://security.ubuntu.com/ubuntu jammy-security InRelease

略過:10 https://download.docker.com/linux/ubuntu victoria InRelease

錯誤:11 https://download.docker.com/linux/ubuntu victoria Release

  404  Not Found [IP: 13.35.35.17 443]

正在讀取套件清單... 完成

E: The repository 'https://download.docker.com/linux/ubuntu victoria Release' does not have a Release file.

N: Updating from such a repository can't be done securely, and is therefore disabled by default.

N: See apt-secure(8) manpage for repository creation and user configuration details.


這裡出錯了,所以不能更新。不解決這個問題的話是無法繼續安裝的。

先來看看最重要的檔案出了什麼問題?先看看repository哪裡不對。


cheeren@cheeren-virtual-machine:~$ cat /etc/apt/sources.list.d/docker.list 

deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu   victoria stable


沒錯,問題就出在這裡。由於我目前所在的OS的是Linux Mint,而不是Ubuntu。


這裡要說明要如何修改/etc/apt/sources.list.d/docker.list:

首先,看看版本出了什麼問題:


cheeren@cheeren-virtual-machine:~$ cat /etc/os-release | grep -i codename

VERSION_CODENAME=victoria

UBUNTU_CODENAME=jammy


原來是CODENAME的問題!

Linux Mint的CODENAME目前是victoria,而若是對照Ubuntu,Ubuntu目前版本的CODENAME則是jammy。我現在Docker所使用的安裝套件是Ubuntu所用的套件,所以,要把/etc/apt/sources.list.d/docker.list中,所有victoria改成jammy即可。

這裡要注意權限,因為這個檔案只能有ROOT權限才能修改。修改完後請繼續:


cheeren@cheeren-virtual-machine:~$ sudo vi /etc/apt/sources.list.d/docker.list


修改好了之後,重來一次:


cheeren@cheeren-virtual-machine:~$ sudo apt-get update

略過:1 http://ftp.tku.edu.tw/Linux/LinuxMint/linuxmint victoria InRelease

已有:2 http://free.nchc.org.tw/ubuntu jammy InRelease                          

已有:3 https://dl.google.com/linux/chrome/deb stable InRelease                 

已有:4 http://ftp.tku.edu.tw/Linux/LinuxMint/linuxmint victoria Release        

已有:5 http://free.nchc.org.tw/ubuntu jammy-updates InRelease                  

已有:6 http://free.nchc.org.tw/ubuntu jammy-backports InRelease                

下載:7 https://download.docker.com/linux/ubuntu jammy InRelease [48.9 kB]      

已有:8 http://packages.microsoft.com/repos/code stable InRelease               

已有:9 https://packages.microsoft.com/repos/edge stable InRelease              

已有:10 http://security.ubuntu.com/ubuntu jammy-security InRelease  

下載:12 https://download.docker.com/linux/ubuntu jammy/stable amd64 Packages [21.4 kB]

取得 70.3 kB 用了 2s (36.8 kB/s)    

正在讀取套件清單... 完成

cheeren@cheeren-virtual-machine:~$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

正在讀取套件清單... 完成

正在重建相依關係... 完成  

正在讀取狀態資料... 完成  

下列的額外套件將被安裝:

  docker-buildx-plugin docker-ce-rootless-extras git git-man liberror-perl

  libslirp0 pigz slirp4netns

建議套件:

  aufs-tools cgroupfs-mount | cgroup-lite git-daemon-run | git-daemon-sysvinit

  git-doc git-email git-gui gitk gitweb git-cvs git-mediawiki git-svn

下列【新】套件將會被安裝:

  containerd.io docker-buildx-plugin docker-ce docker-ce-cli

  docker-ce-rootless-extras docker-compose-plugin git git-man liberror-perl

  libslirp0 pigz slirp4netns

升級 0 個,新安裝 12 個,移除 0 個,有 2 個未被升級。

需要下載 118 MB 的套件檔。

此操作完成之後,會多佔用 435 MB 的磁碟空間。

是否繼續進行 [Y/n]? [Y/n] 


以下略過......


設定 git (1:2.34.1-1ubuntu1.10) ...

執行 man-db (2.10.2-1) 的觸發程式……

執行 libc-bin (2.35-0ubuntu3.1) 的觸發程式……


看看是否安裝成功?


cheeren@cheeren-virtual-machine:~$ docker --version

Docker version 24.0.5, build ced0996


cheeren@cheeren-virtual-machine:~$ sudo docker version

Client: Docker Engine - Community

 Version:           24.0.5

 API version:       1.43

 Go version:        go1.20.6

 Git commit:        ced0996

 Built:             Fri Jul 21 20:35:18 2023

 OS/Arch:           linux/amd64

 Context:           default


Server: Docker Engine - Community

 Engine:

  Version:          24.0.5

  API version:      1.43 (minimum version 1.12)

  Go version:       go1.20.6

  Git commit:       a61e2b4

  Built:            Fri Jul 21 20:35:18 2023

  OS/Arch:          linux/amd64

  Experimental:     false

 containerd:

  Version:          1.6.22

  GitCommit:        8165feabfdfe38c65b599c4993d227328c231fca

 runc:

  Version:          1.1.8

  GitCommit:        v1.1.8-0-g82f18fe

 docker-init:

  Version:          0.19.0

  GitCommit:        de40ad0

cheeren@cheeren-virtual-machine:~$ 


成功了!

2023年8月9日 星期三

有什麼Linux工具,可以產生隨機複雜的密碼?

 Windows上,從網路上可以找到免費工具來產生複雜的密碼(雖然來源可疑)。而在Linux上呢,有三種Open Source的Linux工具可以用來生成隨機且複雜的密碼,分別是pwgen、apg和openssl:

pwgen

pwgen:是一種用於生成隨機密碼的工具,可以生成包含字母、數字和符號的密碼。您可以使用以下命令安裝:

以下是Ubuntu的安裝方法:

sudo apt-get install pwgen

以下是Rocky Linux 9.2的安裝方法 (本文中,所有在Rocky Linux上的安裝方法均適用於CentOS 7/8以及RHEL):

sudo yum install epel-release -y

sudo yum install pwgen perl-Digest-SHA -y

 

然後,您可以使用以下命令生成一組包含 16 個字符的隨機密碼:

pwgen 16 1

pwgen 16 1

pwgen的缺點在於只會出現大小寫字母和數字,不會有特殊符號。其實,這樣對大部份應用上來說已經是相當足夠了;尤其部份網路銀行或部份購物網站,密碼無法使用特殊符號,這時候完全適合使用;然而,對於一般在目前黑客到處橫行的網路環境下使用來說,的確比較容易被有心人暴力破解。

 

apg

apg:另一種用於生成隨機密碼的工具,可以生成包含字母、數字和符號的密碼。您可以使用以下命令安裝:

以下是Ubuntu上的安裝方式法:

sudo apt-get install apg

以下是Rocky Linux 9.2上的安裝方法:

sudo yum install apg -y

然後,您可以使用以下命令生成一組包含 16 個字符的隨機密碼:

apg -a 1 -n 1 -m 16 -x 16 -M SNCL

用apg產生一組16個字符的密碼

apg本來就是為了自動生成複雜密碼用的。上述指令的參數在此說明一下:-M可以指定產生的是什麼符號,大寫是必須有,小寫則只是可能會有。然後S代表特殊符號,N代表數字,C代表大寫,L代表小寫。-m代表最少幾個字母。-x代表最多幾個字母。-n出現幾組。-a使用的演算法。

Ubuntu版本的apg如果你什麼參數都不下,預設的輸出是六組長度不一的密碼,而且在密碼後方還註明記憶的方式:

Ubuntu上apg的預設輸出







是不是超強大的?

apg是這三者當中可以產生最混亂隨機字串的一種工具,功能最強安裝又簡單,是三種方式中我最推薦使用的。但是它的缺點是參數多,光是要記就很頭痛。然而Ubuntu版本的又更強大。建議用在需要產生複雜密碼的場合。

 

openssl

openssl:一種用於加密和解密資料的工具,也可以用於生成隨機密碼。您可以使用以下兩道命令中的任一種來生成一組包含 16 個字符的隨機密碼,上面那道指令可以產生含有特殊符號的;下列那道指令卻只會生成數字和a到f的小寫文字(其實就是16位元數字):

openssl rand -base64 16 | cut -c1-16

openssl rand -hex 16 | cut -c1-16

OpenSSL產生的祕碼




openssl在大部份的Linux/BSD都有,大概應該預設安裝就在系統中,可以說唾手可得。但是BASE64編碼方式有其限制,也就是說,可能不夠隨機,較易被破解。尤其上述的第二種產生出來的密碼,極度不安全,所以非常不建議使用。

要使用openssl產生的密碼的場合,應該是在你沒有安裝軟體的權限,又緊急需要產生密碼的情況下吧。

來個結語吧。

目前大家在用的Windows,無論是Windows 10還是Windows 11,都已經可以啟動WSL(Windows Subsystem for Linux,適用於Linux的Windows子系統)。所以,你可以從Microsoft Store上安裝Linux,比如我就裝了Ubuntu 22.04 LTS。當你如果像我一樣安裝了Linux,那麼你就可以裝上一些Linux的Open Source應用來使用,不必再被Windows的圖形界面給捆綁。像本文介紹的三種產生密碼的工具,就變成你一定會有的好工具,何不樂哉?


2018年5月10日 星期四

重新出發

曾經,我花了不少力氣,在家裡架了一台伺服器。其實呢,現在伺服器也都還在。
但是,自從舊的伺服器掛掉後,我就再也提不起勁把它恢復了。
所以,多年來我寫的一些技術文章也就一去不回了。
這幾年,整個世界可以說大大翻轉了好幾圈。
年輕的時候,總是覺得中老年人總是技術慢慢跟不上時代。那時有種不屑的感覺,自己自認即使到那年紀時候應該還能保持技術的領先吧。
但是,當伺服器掛掉的那一刻,我突然了解了,那台伺服器中的東西,我可是花了不少歲月累積下來的,東西多到我幾乎有一大半的細節已經完全不記得了,我必須很努力回想,才有辦法重製;更大的一部份我早遺忘當初是如何做的。當我在想辦法要儘量回復的過程,突然有很深的無力感出現。所以,伺服器就只有最基本的回復。至於裡面的文章,就讓它隨風而逝了。

過去這八年,其實我書看不少。但是呢,電腦方面的書越看越少,歷史人文的書越看越多。
拍照還是有拍,但是,找我外拍的人都有自己的事,我也就慢慢無法再有新的滿意的作品。
一直想把我的照片圖庫改版,卻找不到好的工具。想自己寫,卻被 Object-C 語言給搞到提不起勁來。人年紀一大,學習能力真的會衰退,我現在真的終於相信了。雖然 Swift 看起來可能可以給我一點希望,但是,年紀一大,好像就不再像年輕時,什麼東西都想自己一磚一瓦的重新建構。

這八年我身上最大的變化就是手邊的所以 IT 設備,居然沒一台灌微軟的作業系統。這是我年輕的時候絕對不可能相信的事。電腦是 Mac,手機是 iPhone,平板是 iPad,伺服器是 FreeBSD,連 Mac 上的 VM 都只有 Linux 和 BSD。猛一回頭,發現我手邊完全沒有微軟的東西,八年過去,連 Windows 變成什麼模樣,我都不知道了。

技術上更是一日千里,有些年輕的時候沒好好用功的東西,現在真的後悔得不得了。最後悔的大概是沒好好把統計學好好念完。雖說不是完全不懂,但是如果說懂,真的會很心虛。看著一堆新名詞一個一個出來。連年輕時技術在前面的 Web 技術,漸漸也落人之後了。

PostgreSQL 自從伺服器掛掉後,就沒再深入研究。那時是 8.x 版吧,現在都進入 10.4 版,11 版眼見就要出來了。中間,我還分心去研讀新的 NoSQL 系統,後來發現其實那只是新的一類應用才需要用到這類工具,大部份現在的資訊系統,還是很強烈依賴著傳統的資料庫系統。而且,隨著新的應用的出現,像 PostgreSQL 這類的老工具也時與俱進,比我所熟悉的 8.X 版補強不少,剛好可以接上新的應用。

所以,我想乾脆不要自己架新的 Blog 了,就把 Blogger 當成新家來把自己的所見所聞放在這裡發表。至於舊的文章,目前正努力把可以救得回來的幾篇文章儘量救回,看能救幾篇算幾篇了。這個 Blog 可能不再只是偏重 PostgreSQL 和攝影,音樂、歷史等我最近有看過的東西,我就在這裡發表不嚴謹,純綷是中年歐基桑的碎碎念吧。

2017年2月9日 星期四

中村修二來台演講有感

昨天,發明藍光 LED 的中村修二教授來台演講。媒體完全沒有報導,我也是今天在「民報」才看到這個新聞:藍光之父看好Li-Fi取代Wi-Fi 勉學子找出自己喜歡的事比進名校重要。

回想年輕的時候,我可是相當用功的學生。那是上個世紀的事了。在大學時,上「半導體物理」課,我們講到 LED,發光二極體,老師講解紅光 LED 和綠光 LED 的發光原理,順便提到黃光 LED 是由這兩種化合物混合而成。也講到 LED 的發光原理。是電子雪崩的結果,大量的電子、電洞在能階轉換時射出的電磁波,就是我們看到的光線。因為每種半導體就只有固定的能階轉變,所以可以發出的光線波長接近固定。也因為所有的電子都會釋放出電磁波,所以發光效率極高,也不會像其它的發光源一樣,部份或者甚至大部份變成熱能浪費掉。

至於 LED 白光,就因為一直找不到藍光的發光源,這個 LED 的聖杯,所以做不到。只要找到藍光 LED 的原料,紅、綠、藍三原色到齊了,所有顏色就能由這三種 LED 原料混合而成。

我後來才知道,其實在那個 1980 年代末期,其實物理學家早就從理論上找到發藍光的材料了,只是發光效率極差,無法量產。當時老師還預言,藍光 LED 在這個世紀(二十世紀)被發明的可能性不大,應該要等到下個世紀才有可能被發明吧!

一直到了時序進入 1990 年代,念了台大電機碩士班,我們教授們的看法也是如此。但是,就在我出社會不到五年,我居然在市場上看到白光LED出現,那時二十世紀還沒結束呢!後來,我在書上看到了一個公司的名號 - 日亞化學。我當時簡直嚇壞了。我在念研究所時,學長們在用鐵芯時,常常感嘆,日本的材料工業真的是嚇死人的高技術,很多材料我們台灣根本做不出來,日本人卻早已量產,那些功能超強的鐵芯就是代表之一(也怪我們台灣當初的教育實在封閉,我那時連稀土材料的「介紹」都從沒在書上看過)。現在我面前那顆明亮的白光 LED,更是證明學長們的話。

所以「日亞化學」這四個關鍵字就一直留在我的腦海中。

所以 2014 年的諾貝爾物理學獎給了真正發明藍光 LED 的「藍光之父」中村修二,我一點也不意外,這是他該得到的,因為藍光 LED 根本就是半導體物理在二十世紀末的聖杯呀!

當然,後來我也買了中村修二教授出的自傳書,我才慢慢了解他孤身一人投入藍光發光物質的心路歷程,對他的更是打從心裡崇拜。

我當初就有想過,一旦發明了白光 LED,那麼首先目前在市面上的筆記型電腦的背光源就會變成LED,這樣筆記型電腦就會變薄,用電量仮大減、續電能力會更長。再來,手機也不會再是綠色背光。LED也會變得多彩多姿。那時候其是 Compaq 也出了一台 Windows CE 的數位助理,我猜想,平板電腦應該也會大量出現吧?

那時候我絕對不會預測到 iPhone、iPad的出現,以及對未來整個世界的巨大改變。

果然,由於藍光 LED 的出現,世界的變化遠遠超出我在當時的想像。

中村修二,就是舉起那個聖杯的聖者。

2011年3月24日 星期四

如何在 Ubuntu 下安裝 PostgreSQL 9.0 和 pgAdmin III 1.12.0

按照「官方說法」,PostgreSQL 9 的 Ubuntu 套件會在 11.04 版釋出時隨著釋出。所以這篇文章的時效性可能只有一個月不到,但是我仍然決定丟上來。因為世事難料,誰都不會想到日本會發生 9.0 強震,並且引發史上第二大的海嘯,還一併發生史上第二嚴重的核子安全事件;那誰又能預知 PostgreSQL 或 pgAdmin III 在下一版的 Ubuntu (11.04) 發行後,是不是還能保持最新版本的更新。別忘了,RHEL/CentOS/Fedora Core 版本的 PostgreSQL rpm 套件,仍然是社群版本的更新速度是最快的。如果你一直只是跟隨 Redhat 官方版本,那恐怕早就被怪客搞得七葷八素了。
自從 Ubuntu 10.04 後,我發現 Ubuntu 官方的 PostgreSQL 相關核心套件的更新速度,好像整個停頓下來了。尤其是 pgAdmin III,不但新的 1.12.0 版一直沒出現,連舊的版本,你都無法用軟體中心或者是 apt-* 工具來更新。PostgreSQL 更是停留在 8.4.x 版。當然,如果你是舊版使用者,那麼停留在舊版無所謂,但是 9.0 自從 2010 年 9 月發布至今,都已經半年了,而且連 9.0 版的相關書籍都出版了半年了,Ubuntu 的 PostgreSQL 套件還停留在 8.X 版,對於開發者來說,這個停滯的時間也太久了一點。幸好社群中有位 Martin Pitt,幫大家把新版套件整理好,只要照著以下的方式,就可以繼續「無縫地」繼續利用 Ubuntu 的「更新管理員」保持最新版本的 PostgreSQL,謝謝 Mr. Pitt!  
Martin 把更新套件放到 Ubuntu Launchpad 上了,他也在下列這個網頁,有一些些的說明,我這篇文章也是參考他的說明的:
https://launchpad.net/~pitti/+archive/postgresql


首先,要讓 Ubuntu 軟體中心可以參考到更新套件,你必需把新的套件庫參考網址,加到 /etc/apt/sources.list 中。
$ sudo vi /etc/apt/sources.list
要把 Pitt 維護的 PostgreSQL 套件加入參考,就要在 /etc/apt/sources.list 中加入下面幾行:
## Postgres 9 hasn't been backported yet.  Manually added repos.
deb http://ppa.launchpad.net/pitti/postgresql/ubuntu lucid main
deb-src http://ppa.launchpad.net/pitti/postgresql/ubuntu lucid main
第一行說明得很清楚,官方還沒支援 PostgreSQL 9,目前這個套件庫只是「暫時」性的。加上後,接著要把更新者的數位簽章加進來:
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8683D8A2
這裏需要解釋的是 --recv-keys 8683D8A2。這個是 Pitt 這個更新的 PPA Signing Key。什麼是 PPA Signing Key 呢?那是給第三方套件維護者的一個數位簽章,這個簽章在套件更新時可以判別套件是「合法」的由原始維護者放上去,而不用擔心是不是來源被怪客拿去放木馬。如果你沒有把數位簽章放進來,那麼將來一旦有新的版本要更新時,更新管理員會更新失敗。接著要更新「軟體來源」清單,方法是:
$ sudo apt-get update
好了,再來就可以開開心心地在 Ubuntu 上安裝 PostgreSQL 9,以及 pgAdmin III 了!
$ sudo apt-get install postgresql-9.0
$ sudo apt-get install pgadmin3
除此之外,如果你打算把 server instrumentation 也裝起來也行,按照以下指令,一下子就可以裝好了:
$ sudo apt-get install postgresql-contrib-9.0
$ sudo -u postgres psql -U postgres -d postgres < /usr/share/postgresql/9.0/contrib/adminpack.sql

後續更新:最近我迷上一套新的 Linux 發行套件:Linux Mint,Linux Mint 是由 Ubuntu 延伸出來的新套件,所以宣稱可以接受所有 Ubuntu 的套件。因此,我就試著在 Linux Mint 上按照 Ubuntu 的安裝方法試著裝裝看。結果是令人十分滿意,一字不改的就可以在 Linux Mint 上安裝 PostgreSQL。沒圖沒真相嗎?好,我貼一下 pgAdmin III 看看,雖然看不出所安裝的套件,但是有接觸過 LInux Mint 的朋友們,應該對它的桌面一片綠色印象深刻吧。

2010年11月9日 星期二

PostgreSQL 的版本

這個標題,可能很多人看都不看,就略過這篇文章,就像我在上 PostgreSQL 課程的時候,我的投影片裏有一頁提到查看 PostgreSQL 版本的方法。而這一頁被一些意見比較多的學生私下抱怨,認為我在灌水,增加篇幅。而我想略過不看這篇文章的朋友,大概也是認為這篇文章不重要吧。其實不然,尤其是當你碰到的伺服器,不是由你全新安裝的,而是要幫忙維護的舊系統時,目前所安裝的版本,就要相當當心並注意了!
先提一下,PostgreSQL 安裝時,server 和 client 可以是不同版本。而這種版本的不一致,的確有潛在的危險可能會發生。如果 client 端比較舊,那還無所謂;但是若是 server 端的版本較舊時,你就要當心了。
你想要知道伺服器的版本,那可以從 psql 或 pgAdmin III 直接下 SQL 指令:
postgres=# SELECT version();
即可。如果你使用 psql,等下了指令後,接著會跳出類似下列的結果:
然後你要結束,請按下 q 就可以跳回 psql。看起來這堆資訊似乎「過多」了點。主要的重點在於前面幾個字,也就是 PostgreSQL 8.4.5。在 PostgreSQL 的版本編號,是由 Major.Minor.Maintenance 組成。Major 就是主要版本號碼,Minor 為次要版本編號,Maintenance 則為維護版本編號。其實按照 PostgreSQL 的慣例,只有  Major 是無意義的,PostgreSQL 的版本都是由 Major.Minor 來區分版本版次的。每個版次功能上都會有所不同,資料檔的格式也都多少有變化。而且這些變化在過去 8.x 版間是大得嚇人,等一下我再引用另一篇文章來說明。所以我的另一篇文章「PostgreSQL 在 FreeBSD 上的大版本升級」裏,大版本升級指的就是像 8.2 升級到 8.3 版這樣 Major.Minor 的改版升級。而 Maintenance 則是功能上沒有改變,而是修正被發現的 BUG,尤其出現安全性的漏洞時,會立即更新的版本。所以每當出現新維護版本時,我反而會比較急著通知。相反的,像 9.0 版出來的消息,我反而只是輕描淡寫的帶過。因為功能增加並不意味著有立即升級的急迫性,反而是維護版本的出現,常常是意味著有安全性的漏洞待補。
好了,正式提到主題。為什麼我們接手維護一套舊系統時,知道它的版本版次對管理者那麼重要?先讓我們來看看 PostgreSQL Release Support Policy。這個網頁開宗明義第一段就說了:「The PostgreSQL project aims to fully support a major release for five years, under the terms of the Versioning policy.」喔!原來 PostgreSQL 每一個主要版本只會維護五年!在同一個網頁中,有一個表格,叫做「End Of Life (EOL) dates」,也就是該版次最終維護日期,現在是 2010 年11 月,所以表格目前是這樣的(這篇文章是 2010 年發表,請讀者注意):
Releases which have already reached an EOL release are italicized:
VersionEOL DateRelease Date
PostgreSQL 7.4October 2010 (extended)November 2003
PostgreSQL 8.0October 2010 (extended)January 2005
PostgreSQL 8.1November 2010November 2005
PostgreSQL 8.2December 2011December 2006
PostgreSQL 8.3February 2013February 2008
PostgreSQL 8.4July 2014July 2009
PostgreSQL 9.0September 2015September 2010
Note: Versions 8.1 and earlier are not supported on Windows platforms
這也就難怪目前 PostgreSQL 官方網站的右上角,只有 8.1.22 版以上的版本,已經看不到 8.0 和 7.4 版了:
如果各位有注意到 PostgreSQL 2010-10-05 Security Update 的安全更新通告,會注意到第一段的最後一行有這樣的文字:This is the final update for PostgreSQL versions 7.4 and 8.0. 正式宣告這兩個版本的結束。其實呢,如果按照 PostgreSQL 官方的 Versioning policy 版本控制策略,是早該結束的兩個版次,如今延長到上個月,終於壽終正寢。接著 8.1 版也將在本月宣告結束[1]。所以這幾個版本,即使有安全上的漏洞,將來也不會再去維護、更新,這樣對於在線上的服務而言,是相當危險的事,所以要早早規劃大版本的更新。
事實上,不僅是因為版本控制策略,讓我們非得注意版本的更新。在 8.0 到 8.3 版,這四個版本當中,資料庫核心內部其實也私下做了相當大的變革。我們來看看一篇發表於去年(2009)九月底的一篇報告:PostgreSQL history。這篇文章的標題和目前你在看的這篇文章一樣,會讓你誤以為在介紹 PostgreSQL 早期的歷史,其實不是,它是在介紹從 8.0 版到 8.4 版間的變革。內容詳情,請各位自行點閱,我們來看這篇文章的結論。這篇文章的作者,把 8.0 到 8.4 這五個版本,一一的跑測試數據,得到了兩個表格:

PostgreSQL RO OLTP performance
 Peak TPSPeak performance at # of clients
8.0.2112564
8.1.17562014
8.2.13810918
8.3.71398422
8.4.11354622

PostgreSQL RW OLTP performance
 Peak TPSPeak performance at # of clients
8.0.213612
8.1.1787310
8.2.13135814
8.3.7279518
8.4.1271312
 有沒有注意到,從 8.0 到 8.3 版,效能上已經提昇五點五倍到將近九倍!雖然到了 8.4 版因為一些安全的因素,又把一些功能改變,而讓 RW OLTP 的整體效能又降低了一些,但是還是比 8.0 版快上六倍!所以說,在 8.3 版以前的使用者,應該要早日把系統昇級到最新版本,以得到最好的效能。
好了,恭喜你看到這篇文章。如果你的系統還在 8.3 版以前的,請趁現在一口氣昇到最近的 9.0.1 版吧。搭配 9.0.1 版的 pgAdmin III 1.12 版,有革命性的功能增加,真的值得你去安裝。當然囉,如果你的系統是裝在 Ubuntu 上,那麼你應該目前還只能安裝到 8.4.5 版。最近的 9.0.x 版,必須等到下一個版本 11.04 版 Armel,才會一起出現。如果忍不到那時候的話,那就先昇級到 8.4.5 版吧。

2010年5月6日 星期四

在 Ubuntu 上的 PostgreSQL 預設存取認證方式

在 FreeBSD 和 CentOS 上,第一次著手使用 PostgreSQL 非常容易,因為 root 的密碼你會知道,所以只需要以下列這兩個指令,就可以不用知道安裝程式到底替你的 pgsql 或者 postgres 指定了什麼複雜的密碼,你都可以切成 PostgreSQL 的系統帳號,來執行該有的管理命令:
$ su
# su - pgsql (這是在 FreeBSD ,或者)
# su - postgres (這是在 CentOS 上)
在 FreeBSD 上第一步更輕鬆,因為 FreeBSD 上的 PostgreSQL port 版的預設 pg_hba.conf 設定,把 localhost 和本機使用 Unix domain socket 的權限,設成最寬鬆的 trust,所以就算不用密碼,你還是可以很輕鬆的從本機上,用 postgres 這個資料庫成員進行管理和設定的工作;只是強烈建議你,在正式上線前這些設定都應該要修改,比較安全。只是,這些事情到了 Ubuntu 上就有一點點變得複雜了,原因有二:其一在於 Ubuntu 系統設計上,預設不想讓你知道 root 密碼,故意不讓你用 su 切成 root 來做管理工作,而是希望你利用任一個 wheel 群組的使用者登入後,再用 sudo 來執行 root 才能執行的管理命令。但是上面的第二個指令卻是使用 root 的權限才做得到,所以有些書或網路上的文章,會建議你直接替 postgres 系統帳號設定密碼;但是這種建議,我認為是很蠢的。其二就在 pg_hba.conf 這個檔案的預設值。其實我很反對替 postgresql 系統帳號設密碼,因為要設到又要你自己記得起來,又要複雜到 cracker 破解不了的密碼,實在不是件容易的事。那麼要怎麼著手第一步呢?剛裝好 PostgreSQL 時,我不但不知道 root 的密碼,連 postgres 系統帳號的密碼也不知道,更別說資料庫角色 postgres 的密碼了,那要怎麼進行?我們先從 pg_hba.conf 開始,這個檔案在 Ubuntu 的 PostgreSQL port 是放在 /etc/postgresql/8.4/main/pg_hba.conf [1]。總之,我們先看看預設值這個檔的內容,我只截取有義意的最後幾行:
......(上略)
# Database administrative login by UNIX sockets
local   all         postgres                          ident

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# "local" is for Unix domain socket connections only
local   all         all                               ident
# IPv4 local connections:
host    all         all         127.0.0.1/32          md5
# IPv6 local connections:
host    all         all         ::1/128               md5
加粗的四行才是有意義的,其餘只是備註;一般來說,實際應用上,大家最後應該還是會開放讓網路上其它主機連線;但是目前還沒有,所以我們目前只需先來討論一下這四條設定。第一條和第二條事實上重覆了,我猜 Ubuntu 的 PostgreSQL 維護者是希望你把第二條改掉;比如改成像 CentOS 預設的 md5[2];第三條和第四條其實指的也是同一件事,就是 IPv4 和 IPv6 的 127.0.0.1 或 ::1/128 這兩個協定的 localhost 會使用 md5 認證方式。看起來這四條都是設定本機連線,事實上有一點點不一樣,差別就在前端程式所使用的協定。如果你有裝 pgAdmin III,那它使用的協定是 TCP/IP,適用的是第三或第四條;但是 psql 用的卻是 Unix domain socket,則是參考第二條設定。在這裏你可以注意到 Unix domain socket 的認證方法是 ident,意思是要再查閱 pg_ident.conf,就可以免密碼直接用 psql 直接連上 PostgreSQL。所以你只需要在系統中切成 postgres,你就可以直接執行管理指令,不用密碼[4]。但是,如果你是用 pgAdmin III 呢?我們看第三條,認證方法是 md5,這代表你必須輸入密碼,只是前端程式不會將你的密碼以明碼在網路上傳送,而是先用 md5 編碼後,等到了伺服器,再比對兩者的 md5 簽章結果是否一致。md5 是比 7.4 版以前的 PostgreSQL 所提供的「password」認證方式更安全的一種認證方式,當然你還可以選 gss, sspi, krb5 這些第三方的認證方式,還可以選像 pam, ldap 這類由目錄服務或是其它 PAM 模組所提供的認證方式,這方面請自行參考手冊。但是一般使用來說,md5 已經夠安全了。
但是,問題出現了,我又不知道 postgres 的密碼,那我怎麼使用 pgAdmin III 管理?答案很簡單,就是直接用 psql 設定 postgres 的資料庫密碼。但是,postgres 的系統帳號密碼我根本就不知道,叫我怎麼執行 psql 呢?其實很簡單,只要一行就可以免密碼切成 postgres:
$ sudo su - postgres
沒錯,就是這麼簡單!接著你就可以執行 psql:

然後你就可以執行更改密碼的指令:
postgres=# alter user postgres with encrypted password '你的新密碼';
ALTER ROLE
postgres=#
來,我們來看看用 pgAdmin III 是不是可以連上?先新增一個伺服器連線:

請輸入剛才設定的密碼:


這時候一定會出現「建議」,不用理會它!


哇哈哈,連上了!


第一步算是完成。再來就要開放讓網路上其它的機器可以讀取。請注意,建議設定得越嚴格越好,不要「假設」防火牆會幫你阻檔攻擊,能在這裏先把關好,就先把關好。
要放啟網路連線,有兩個設定檔要先修改,一個就是剛才的 pg_hba.conf,另一個是 postgresql.conf,兩個檔案都放在 /etc/postgresql/8.4/main 之下[1]。postgresql.conf 要修改的地方只有一處,如下圖所示:

請把上圖那行 #listen_addresses = 'localhost' 前面的「#」號[3]拿掉,把 'losthost' 改成 '*';記住,單引號千萬不要漏掉;然後存起來。這個設定,是代表 PostgreSQL 的 listener 要監聽的網路介面。如果你的伺服器有超過一個以上的網路介面卡,那麼你可以指定只監聽某個介面的查詢請求。有時為了安全,我們常會將伺服器安裝兩個介面卡,其中一個對外連,另一個對內連,而且不轉交對外的那個介面來的任何封包(也就是不讓伺服器另做路由器或防火牆用)。為了安全,我們可以只讓 PostgreSQL 監聽來自內部的查詢請求, 而不理會對外那個介面來的請求。設成 '*' 星號是貪圖方便、偷懶,代表監聽所有的網路介面。通常如果你的伺服器只有唯一一個網路介面卡時,你就可以這樣偷懶。
pg_hba.conf 則是在最後面加上你要開放的 IP。設定的規則很簡單,就像前面那堆註解說明的,請自己參考,更詳細的說明請參考手冊。如果你沒有設定 SSL 連線,那麼第一欄請使用 host 即可,用不著設成 hostnossl。第三欄建議使用 CIDR 表示法,儘量不要再用傳統的 IP network-mask 的格式。也就是說,假如你的打算開放的是 192.168.1.1 ~ 192.168.1.126,以傳統的網路遮罩應該是 255.255.255.128,那麼你可以設成 192.168.1.0/25。如果這部份你看不懂,那麼請找一本 TCP/IP 的書籍,專門翻到 IP 定址的那部份看一下,應該很容易就會懂了。第五欄,如果你的系統沒有安裝其它的第三方認證方式,建議使用 md5,不要使用 trust 或 password。indent 也儘量不要用,除非你的前端都是 Unix/Linux。以剛才這一個網段為例,這行可以參考第三條,設定成:
host    all         all         192.168.1.0/25          md5

如果是只打算開放給 192.168.2.1 這個 IP,那麼一個 IP 的網路遮罩是 255.255.255.255,CIDR 表示法是 192.168.2.1/32,可以設定成:
host    all         all         192.168.2.1/32          md5
設定好了之後,請重新啟動 PostgreSQL,重新啟動的方法是:
$ sudo service postgresql-8.4 restart
 * Restarting PostgreSQL 8.4 database server                             [ OK ]
$
如上出現 OK 就表示你的設定語法上沒有問題,但是你還是要到前端用 pgAdmin III 連線看看,如果可以連上,那麼恭喜你,成功了。
最後,特別提醒一下,pg_hba.conf 不要設定得太寬鬆。因為雖然 PostgreSQL 很安全,但是只要人做的,就無法保證完全不會出錯。我就見過兩次很嚴重的安全性 bug 的安全通告。有些高手就有辦法在短短一兩天內搞出零時差攻擊。所以這方面再小心也不為過。

[1] 這篇文章假定是在 Ubuntu 10.05 LTS - Lucid Lynx 上,所安裝的 PostgreSQL server 8.4.3_1。其它版本,像是 8.4 換成 9.0 之類的,請自行類推。Ubuntu 在這方面很討厭,把所有設定檔放在 /etc 下,把資料庫檔卻放在 /var/lib 下,不像原始的 PostgreSQL 使用 chroot,把所有檔案全放在一塊。Ubuntu 這樣的安排,卻使得一堆工具使用上出現不少困擾。
[2] 我感到納悶的是,那為何不乾脆預設值就設成 md5?因為已經有了第一行的設定,即使預設改成了 md5 又不會影響 postgres 這個預設 dba 的認證方式。目前這個樣子只是留了一條尾巴,讓使用者事後還要動手改,那何不一開始就設定好?實在令人百思不得其解!
[3] 「#」井字號代表其後是註解,PostgreSQL 會自動忽略其後的文字。
[4] 這裏我跳過了一堆細節。ident 認證方式有好幾種,比如只有單純的 ident 或是有附加的述詞;比如 same user;用以補充說明。這裏如果後面再加上 same user 述詞就代表著,只要你在系統中以某個系統帳號登入,那麼你就可以免密碼以同名的資料庫帳號直接登入資料庫。比如你在 Ubuntu 以 postgres 這個系統帳號登入,這時候你就可以直接執行 psql,而不用使用密碼即可登入資料庫,就像前面本文中的這個例子。但是如果後面沒有述詞來補充呢?預設資料庫會去找和 pg_hba.conf 同一目錄下的 pg_ident.conf。這個檔案列了一個清單,內容就是系統帳號和資料庫帳號的對照表。但是如果清單中沒列的資料庫帳號,就像是加了 same user 述句一樣的認證方式。





2009年12月8日 星期二

Npgsql

如果你常常在微軟的世界裏寫程式,你一定知道什麼是 .Net Data Provider,它就是 .NET 資料庫程式設計用的資料庫驅動程式,而 PostgreSQL 專屬的官方 .Net Data Provider 就是 Npgsql。Npgsql 目前是 PostgreSQL 的應用程式界面中,維護的速度前三名的;另兩個是 ODBC driver 和 JDBC driver。半個月前 Npgsql 釋出 2.0.7 版。這只是 2.0 版的第七個安全性更新。已經釋出一年的 2.0.x 版,實作了給 .Net 2.0 和 3.5 甚至 3.5sp1 的 .Net Data Provider 絕大部份的功能。也就是說,如果你是在用微軟的 Visual Studio 2008 寫程式,不管你是用 C#、VB 還是 C++,就是用這個 Data Provider 就對了,就算你用的是不用錢的 Visual Studio Express 也能。很可惜的是,Npgsql 的文件實在太稀有了,只有一篇整理得不太好,而且也有不少錯誤的 User's Manual。這裏我用三個小程式來展示如何使用 C# 來開發 Windows 上的應用程式。這三個程式,你可以把它們當成我在測試這個 provider 是不是實作了社群所宣稱的功能。
要開始前,請先到 Npgsql 官方網站下載最新版本的 Npgsql,目前(2009/12/2)最新的版本,如上述的,是 2.0.7 版。但是你會發現下載網頁中,光是 Npgsql2.0.7 就有好幾個檔案可以下載:
我來介紹一下,那兩個 apidocs 就是 API 的 HELP 檔,有兩種格式,一種是 Windows 專屬的 CHM 檔,另一個是 HTML 格式。接著四個 bin 就是 provider,mono2 的兩個,是給 mono 用的,mono 是 Novell/SuSE 支持的一個計劃,也就是把 .NET port 到其它系統的計劃,一般在 Linux 上都很容易可以找到 mono。過一陣子我再來介紹它,現在先知道有這回事就好。接下來的兩個檔就很重要,ms 就是給 .NET 2.0 用的,ms.net3.5sp1 則是給 .NET 3.5 SP1 用的。如果你還在用 .NET 1.1,那抱歉,請你下載 1.0.1 版,而這個版本似乎沒人在維護了。不過,我目前所認識的開發者,不是已經追到 VS 2008,保守一點的至少也在用 VS 2005 了。當然也有骨灰級的還在 VB6 下撐著,這就不在本文的服務範圍內了。所以就看你用的是哪套 VS,下載你需要的版本。最後那兩個是原始碼,用 C# 寫的。所以有志幫忙維護的(或是你不小心發現一個 bug,又沒時間等人家官方的維護版本出來),或是好奇人家怎麼寫出 .NET data provider 的可以下載原始碼下來參考。這就是 open source 的好處。
下載下來解開後,放到任何你想放的位置。當然你也可以到到系統的 GAC 中,但是我覺得沒必要,只需要開發時多做一個動作就行了,不然每次有新的維護版本出來時,要把舊版的移除還要動一堆手腳,實在太累。我的建議是建立一個新的目錄專門放 Npgsql,而且越明顯的位置越好。除非你中了木馬,否則放到明顯的地方,當你把舊版更新成新版時,會輕鬆不少。先來看看解開的情形:
有兩個目錄,一個是 bin,一個是 docs。docs 裏放的就是 HTML 版本的 API DOCs。我們要的 provider 放在 bin 這個目錄中:
注意看上圖,先不用管上面那堆放 L10N resource 檔的目錄,因為裏面沒有我們家的 zh-TW。這裏有三個 DLL,理論上我們開發桯式只需要用到 Npgsql.dll;至少我等一下要展示的三個測試程式只需用到它。記得它的位置,因為等一下我們要用到它。
我的測試環境是 Windiws 7 RC,Visual C# 2008 Express (就是 Visual Studio Express 的 C# 部份),全部是免費的。沒錯,用免費的開發工具就很好用了,我一直認為,除非你不想用 NUnit,否則用這個免錢的開發工具已經夠用了,連簡單的「重構」功能都有了,欠缺的只有可以直接用 UML 的 class diagram 來設計程式這個功能要用標準版以上才有。但是如果你不習慣用這種工具來幫你把早期架構組合起來,那麼錢乾脆省下來比較實在。
第一個程式,測試連結
第一個程式,先來一個極簡單的程式,來測測資料庫連結,因為資料庫連結是一切資料庫應用的基礎,如果連結沒辦法建立,什麼事都不用做了。所以我們就來寫一個什麼事都沒做,只拿來測試連結可不可以建立的程式。
Visual Studio Express 其實一點都不陽春,它已經可以幫你建立相當 fancy 的 GUI 骨架,你只需把骨架上加上該有的程式碼就夠了,和早期的 VB 沒什麼兩樣。它和我年輕的時候的 Delphi 一樣,當你在設計使用者界面時,IDE 其實在後面一直辛苦的幫你建立一些骨架程式,讓你省下一堆要在紙上畫圖、想像的時間。
所以我們就先在「設計工具檢視」上,拉出一個 form,然後在 Form 上擺一個 button,然後在這兩個 control 上打幾個字(不一定要和我一樣打這幾個字),就像下圖一樣:
接著第二步,把剛才下載的 Npgsql 加到參考中。方法如下,請打開「 專案(P)」/「加入參考(R)...」選單。
這時候會打開「加入參考」對話方塊,先切到「瀏覽」頁籤,然後把 Npgsql.dll 加入。
按下確定後,看看右邊的「方案總管」中的「參考」節點中是不是出現了 Npgsql?
有的話,恭喜你,可以進入第三步,打入以下的簡單程式。注意,部份的程式碼 Visual C# Express 已經幫你打好了,所以其實你需要輸入的字實在不多。
這裏有一行要改一下,就是連線字串那行。你的連線字串不可能和我的完全一樣,所以請改一下。

這四個參數我在這裏請明一下。Server 是伺服器的位址,你可以使用 IP 或 Domain Name,至於 GNC 我不確定可不可以,理論上是不行。本機你可以用 localhost 或 127.0.0.1 都可以。我是用 Virtual Machine,所以用 IP 比較簡單。你可以會問,用 Virtual Machine 不是每次重開 IP 都會改嗎?我至少知道 VMware 不會,每次你的 VM 都會用同一個虛擬 IP,所以可以把它寫死也無所謂。User ID 是你的 PostgreSQL 登入帳號,建議不要用 postgres 帳號,太危險了,請另外建立一個權限小一點的帳號,專門給應用使用。Password 是密碼,如果你是用 trust 連線方式,那這個可以略過,不過我建議你還是用 MD5 比較安全。Database 是連線資料庫,一樣,建議你另建一個給應用程式使用的資料庫,然後給予連線用帳號合適的權限即可。
如果你有用 SSL 替你的連線加密,那麼,還有兩個參數你必須加入,一個是 SSL,一個是 Sslmode。SSL 預設值是 False,你必須先把它指定成 True。Sslmode 有四種,就是你用 PgAdmin III 遠端連線時的那四種模式:需要、偏好、允許、停用。在這裏,它們分別是竐定成:Require、Prefer、Allow、Disable,預設值是 Disable。
好了,接著請在應該加入程式碼的地方加入程式碼。千萬不要忘了前面的 using Npgsql; ;還有,請注意大小寫。包括這行,應該有六行要加入。定義連接字串那行後面的註解就不用跟著打了。
打好後,請按下 F5 或上方工具列上的「開始偵錯」的那個綠色三角形,執行程式。
好,如果你確定伺服器已經執行,而且防火牆有打開 5432 這個 port,就按下那個 button,也就是我的程式 UI 的「開始測試」按紐。如果沒有意外的話,下面的訊息方塊這時應該會如預期的出現:
真是很簡單,而且沒用的程式。這個程式是一切 Npgsql 的程式的基礎,一定要是 Assembly 參考建立正確,然後資料庫的遠端連線設定完全正確,也就是允許你這個 VM 所在的網段可以連上伺服器,才能出現這個訊息方塊。
如果沒出現,那麼我建議你先檢查資料庫的設定是否正確。你可以先用 pgAdim III 連線看看,如果連 pgAdmin III 都連不上,那麼肯定伺服器端一定有哪裏設定錯誤。如果沒問題,那再來檢查哪裏出錯。當然要先確定你程式沒打錯。
這個無聊的測試程式如果沒問題,那麼接著我們該來試著寫個比較有用點的程式,先寫個從伺服器擷取一些資料的程式吧。
第二個程式,接收資料
第二個程式要寫之前,請先到我之前所寫的文章「利用網路上的範例資料庫來做 SQL 練習」最後面,下載 tbl_pgsql.sql 和 pg_sample.sql 這兩個資料庫範例。這兩個範例好像在 psql 執行時會有一點問題,應該是一個 psql 的 bug,但是你若用 pgAdmin III 的「查詢工具」;也就是工具列上有一張紙上面有一隻筆跟一個 SQL 字樣的那個圖示;用它執行我確定沒問題。這個範例很極端,因為我用了中文來當資料表格名稱,也有中文來建立表格的欄位。因為 BIG5 在 PostgreSQL 的支援仍然有問題,所以這裏要建立時,請確定你目前給程式連線使用的資料庫使用的編碼是 UNICODE。在 UNICODE 下,中文是完全支援的,即使你的 Windows 的系統編碼是 MS950 連線一樣不會有任何問題。
把範例資料匯入資料庫後,接著建立一個新的專案。首先,記得如上面那個例子一樣,把 pgsql.dll 加到參考裏。其次,如下圖一樣,建立一個上面有一個 dataGridView 和一個 button 的 form。要注意 dataGridView 不要拉得太小,拉大一點。
最後在那個 button 上 double-click,打開程式碼模式,加入如下圖的程式碼。一樣別忘了 using Npgsql; 這一行,還有把連線字串改一改,改成自己的。
dataGridView1 就是我們拉的那個 dataGridView 的 name,變數名稱。就算加上那四個大括弧,也只有新增 12 行文字,如果不算那四個大括孤,則只需八行!打完後,按下 F5 或是工具列上的「開始偵錯」的那個綠色三角形,執行程式。
接著用滑鼠按下右邊那個 button,我的 button 上的文字是「載入資料」,你可以用不一樣的文字(text)。
哈!帥吧,即使內碼是 Unicode,所有中文字呈現一點問題也沒有。注意,連爛位名稱都是中文的。再注意一下這行程式碼:
         using (NpgsqlDataAdapter da = new NpgsqlDataAdapter("select * from 商品清單;", conn))
連資料表名稱都可以完全用中文的,而且和 Unicode 完全相容。
這個程式終於勉強可以算是一個「資料庫應用」了,但是仍然太陽春了,所以我們再來展示更加強大的資料庫應用,讓我們下一個程式可以新增、修改、刪除資料,而且在送往資料庫前,你還可以取消。
第三個程式,更新資料
和前兩個程式相比,接下來的這個程式長了一些,不過和真正線上使用的程式相比,依舊算是相當短的程式。
這次我們用一個隨時可以丟掉的資料表格來測試;我們姑且叫它 t3 好了。這個 t3 有兩個欄位,分別是 col1 和 col2。col1 的資料型態是 serial,也就是可以遞增的整數;col2 的資料型態是長度 5 的 varchar 或是更正式的 character varying;然後建立一個 Primary key,擁有 col1 這個欄位。
CREATE TABLE t3
(
  col1 serial NOT NULL,
  col2 character varying(5),
  CONSTRAINT t3_pkey PRIMARY KEY (col1)
);
接著可以用 pgAdmin III,輸入七個字串,分別是:一一一一一、二二二二二、三三三三三、四四四四四、五五五五五、六六六六六以及七七七七七。很無聊的資料吧?但是鑑別力超高的!XD 好,就利用這個測試資料表格和這七個很無聊的資料,我們來進行第三個測試程式。
首先,我們一樣建立一個新專案,在專案中設計一個表單,在表單中放上三個 button 和一個 dataGridView。這次這三個 button 各有用處,所以我們分在它們的 text property 中輸入「載入資料」、「取消變更」和「儲存資料」。大致上這個 form 的 control 擺放的 layout 如下圖。
這個程式比較複雜,所以一些共用的性質,比如連接字串,我們可以儘量擺在 form 一開始的程式碼中,就像下圖。除了要記得程式碼一開始要記得把 using Npgsql; 加上以外,在 Form1 的一開始,可以先把連接字串定義好。同時把共用的三個 ADO.NET 的物件先定義好。我們會用到一個 DataTable,就叫它 dt 好了;會用到一個 DataAdapter,在 Npgsql,DataAdapter 叫做 NpgsqlDataAdapter,我們給我們的 NpgsqlDataAdapter 取名為 da;還需要一個 Connection 物件,Npgsql 的 Connection 物件叫做 NpgsqlConnection,我們的 NpgsqlConnection 就取名為 conn。
這樣還不夠,我們要替我們的 ADO.NET 在 Form load 進來的時候就設定好。所以我們在我們的 form,Form1 初始化時(建構子中),把 dt、da 以及 conn 設定好,等待程式啟動時呼叫 Form1_Load 時可以馬上使用。
除此之外,在這裏,我們先建立一個 private 方法 LoadData(),這個方法的目的是把資料表格 t3 的資料載入,和剛才第二個程式的主要功用是完全一樣。不包括那兩個大括孤的四行程式碼很簡單,就是建立一個本地的 Command 物件,把它指定給 DataAdapter 的 SelectCommand,接著把 DataTable 填滿,最後把這個 DataTable 指派為我們那個 dataGridView 的 DataSource。這樣資料就會自動填入 DataGridView 中。
把這部份功能特別「取出來」,是因為程式中有兩個地方要用到,所做的重構(Extract method),再往下看就可以看到呼叫它的場合。
接著要進入主題中的重點了。程式用到四個 event,分別是 Form1 的載入 event:Form1_Load,以及三個 button 的 Click event。先注意到 Form1_Load。Form1_Load 很簡單,只呼叫 LoadData(),把 t3 資料表格載入。這樣才不會在把資料庫入前,你就按下「儲存資料」,而發生程式例外。
再來第一個,也就是「載入資料」的那個 button 的程式碼。這個部份只比 Form1_Load 多了一行,就是 dt.Clear();,它的用意就是先把 DataTable 清乾淨,不然你一直連續按這個 button,DataGridView 裏重複的資料會一直複加上去,如果發生這種狀況,接著當你結束編輯資料,按下「儲存資料」,而就在資料回存時一定會造成錯誤。因為我們的 t3 有一個 Primary Key,重複的 col1 值會發生錯誤。
第二個 button 就是「取消變更」,只要你還沒按下「儲存資料」,你按下這個 button 所有的更新都會回復。這部份的程式碼非常短,只有一行:dt.RejectChanges();,這一行會把你在 DataGridView(其實是後面的 DataTable) 上所做的變更全部放棄,恢復原來未更動前的資料。
第三個 button 是最重要的「儲存資料」,這一段程式是本程式的重點,主要的程式包含在一個 try...catch 區塊中。重點在於我用了 DataAdapter 的附屬物件 CommandBuilder。CommandBuilder 可以在你回存資料前,先把你這一次期程所編輯、更改、刪除的所有動作,建立成你的資料庫所能了解的 SQL 指令。而建立完成後,你只需把產生出來的 Command 指派給相關的 Command 物件就可以了。指派好了以後,呼叫 update 就會更新資料庫的資料。最後再呼叫 AcceptChanges,完成此次的修改。其實這一段可以再把「載入資料」button 的那兩行程式加入,會讓程式更合理;只是這個程式只是測試,不用把程式重構到如此完美。
接著按下 F5 來執行看看。程式一執行,資料馬上就被載入了。
我們先試試第二個 button,「取消變更」的功能。要試就多試一點,我們來改兩筆資料看看。我們把第三筆的資料從「三三三三三」改成「三三三三八」,同時也把第五筆「五五五五五」改成「五五五五九」。
接著按下「取消變更」,你所改的所有資料都會恢復。只要你還沒按下「儲存資料」之前,所有變更都會恢復。
再來試試「儲存資料」。這次我們修改第四筆資料,把它從「四四四四四」改成「四四四四九」;接著新增一筆「八八八八八」的資料。
按下「儲存資料」,畫面會有點亂,再按下「載入資料」,諾,資料更新了。而且顯示的順序是更新的順序。這是因為 PostgreSQL 的 MVCC,顯示的是儲存的資料的版本順序。
你可以不相信,那麼我們叫出 pgAdmin III 出來。在左邊找出 t3,按下滑鼠右鍵,找出「檢視資料」/「檢視所有資料」。
對吧,資料更新了。
好像還沒試刪除資料的功能,接著把剛才新增的第八筆資料刪除,按下「儲存資料」看看。
不相信刪掉了?沒關係,叫 pgAdmin III 出來做證。看吧!第八筆砍掉了。
看吧,連 CommandBuilder 的功能都完備了,不想繼續被微軟綁死的朋友們,要不要來試試 PostgreSQL 和 Npgsql 呀?
繼續往前走
Npgsql 被微軟的信徒抱怨最多的大概是它沒有提供一堆給 Visual Studio 用的 Data Control,所以他們認為開發速度會減慢。但是,我的看法不是這樣的。其實在 Visual Studio 2005 之後,很多控制項都有 DataSource 這項 property。所以你還是可以很快速,很方便的利用這個性質,和你的 DataTable、DataSet、DataAdapter...... 綁在一起,開發的效率不會降低。
另一個微軟的使用者比較擔心的是,一般他們設計採用的是 MS SQL Server,所以所有物件清單很容易在 MSDN 中,甚至在坊間的 ADO.NET 的書籍中查得到。但是 Npgsql 的相關物件的清單,卻不知道要如何對照?這個問題的答案更簡單。記得本文一開始,在下載那部份,在下載的檔案清單中,是不是有兩個 apidocs 的 ZIP 檔?這就是清單。你只需把這裏的東西,和 MSDN 中 Sql...... 開頭的做對照(Npgsql......),就可以完全轉換過來。換句話說,幾乎只要出現 Sql 的地方,全改成 Npgsql 就可以了。
最後要參考的是一個重要而且很多人關心的網頁。Npgsql 有哪些東西還沒做到(而不是哪些功能完成)?有清單嗎?有,這個負面表列在這裏可以找到:http://npgsql.projects.postgresql.org/roadmap.html
看到我測試的這三個程式,我相信你應該躍躍欲試了,那就開始動手吧。把越來越貴的 MS SQL Server 丟到垃圾桶,換成 PostgreSQL,把週週為了更新,都要停機一段時間的 Windows Server 換成 FreeBSD 或 Linux 吧(連 Solaris 也行喔,改天我來教教大家如何安裝)。




2008年12月18日 星期四

實作建立新的 Tablespace

上個星期發表的 PostgreSQL 的 Tablespace 只有文字說明。事實上,我曾想用圖來解說 Oracle 的 tablespace 的架構,順便也畫一張 PostgreSQL 的架構圖,但是人懶沒畫Tongue out;不是啦,其實是我不太會用繪圖軟體,等我有空再慢慢把圖補起來。但是,如果實作一下在 PostgreSQL 建立一個新的 tablespace,然後 demo 一下是做得到的。所以我就在這幾天大致上把 64 bits 版本的 PC-BSD 7.0.2 的 VM 裝好後,試著模擬新增一顆硬碟,然後在新的硬碟裏建立一個 tablespace,讓大家參考一下,順便感覺一下在 PostgreSQL 下的 tablespace 是長得什麼樣子,以便將來考量以 tablespace 來提昇效能的參考。至於 PostgreSQL 的那兩個 default tablespace,到底被系統放在什麼地方? 過幾天我再另文介紹,今天先饒了我,打字和抓圖打得好累! X(
這篇文章採用的例子是使用 PC-BSD,也就是 FreeBSD 7.0。為了不讓主題 focus 在 FreeBSD 系統面上,所以我儘量跳過 FreeBSD 新增硬碟的步驟。有興趣的朋友可以參考 FreeBSD 手冊,或是王俊斌先生所著「FreeBSD 6 架設管理與應用」。
在文章開始前,我必須先列出要建立 tablespace 的六個要件:
  1. 你必須是資料庫的 superuser。一般來說,PostgreSQL 的資料庫內第一個帳號,也就是 postgres 就是 superuser,你也可以建立一個新的,擁有 superuser 權限的帳號。
  2. PostgreSQL 必須執行在支援 symbolic links 的作業系統。這也就是之前我說 Windows 版本的 PostgreSQL 恐怕不能使用 tablespace 的原因;但是由於有一個東西叫 Cygwin,所以這一條我還得找時間在 Windows 上試一下。
  3. 要建立 tablespace 的目錄必須先存在,也就是說,PostgreSQL 本身不會幫你建立這個目錄,你必須在建立 tablespace 之前先把這個目錄建好。
  4. 上述這個目錄必須是空的。這也就是我等一下不直接用 mount 點建立,而另外再建立一個子目錄的原因;因為在掛載點,作業系統常常會多擺一兩個小東西,我可不敢隨便砍它們,免得系統出現出乎我預料外的慘事。
  5. 這個目錄的名稱長度必須小於 991 個字元。
  6. 這個目錄的擁有者,要是執行 postmaster 或 pg_ctl 程序的那個系統帳號。比如,在 FreeBSD 就是 pgsql,而 Ubuntu/RHEL/Windows 就是 postgres。這一點很容易忘掉,等一下我會特別展示,一旦忘掉,系統會怎麼回應你的。
在開始前,我打算先加上一顆硬碟,讓模擬更真實。由於我是用 VMWare 測試,所以可以很輕鬆的新增一顆「假的」硬碟。事實上真實的系統上要新增硬碟也很簡單,只需要 $$ 多一點就夠了!Tongue out 在 VMWare 上新增硬碟,必須用到 Workstation 版本,方法如下:請到 VM 選單,找到最下面一項「Settings...」按下去,這時會出現一個「Virtual Machine Settings」對話方塊,如下圖。我這張圖是已經建立好一顆 2GB 的 SCSI 虛擬硬碟的狀況。
圖一

要新增硬碟,請先按下左半邊下方的「Add...」按鍵,這時候會出現如下圖一樣的「Add Hardware Wizard」,選 Hard Disk,按 Next>。
圖一之二

這時就請遵照 Wizard 指示,一步一步做,就可以很輕鬆的新增一個「SCSI 虛擬硬碟」。在這裏我就不多做說明了。
圖一之三

加好了以後,再來就是使用 FreeBSD 的工具程式把這顆「新硬碟」Fdisk、Label,也就是建立 partition。能夠的話,修改一下 /etc/fstab,把新硬碟加上,讓系統重新開機時就會自動 mount 上。像我的例子,新硬碟叫 /dev/da1,我建立了一個 label 是 /dev/da1s1d。在 FreeBSD,SCSI 硬碟叫 da?,而 ATA/SATA 硬碟叫 ad?。我把它 mount 在 /pgdata 這個掛載點上。記得我文章一開頭說的建立 tablespace 要注意的六點的第四點嗎?這裏看來在我建立新 partition 並且把它掛在 /pgdata 時,系統在這裏塞了一個叫 .snap 的檔案。我不知道它的作用是什麼?但是為了預防萬一,我寧願不去惹它,把它留下來,所以接著我決定在它下面建立一個目錄 /pgdata/cheeren 來放 tablespace;但是,這時請注意,目前這個目錄和 /pgdata 的擁有者是 root:wheel。還記得剛才提的那六點嗎?看起來最後的第六點違背了,這在後續的動作中會產生問題。我這裏是故意這樣做,因為我發現很多人都會不小心忘記第六點,而在這裏撞牆撞半天。😛
圖二

接著建立一個 tablespace,把它放在 /pgdata/cheeren:
圖三

圖四

接著......,哇啦哇啦!哈!記得嗎?/pgdata/cheeren 的擁有者是 root,所以 pgsql 當然沒有寫入的權限:
圖五

這時候該怎麼辦?切回到 SHELL,用 su 把自己的權限切成 root,然後把 /pgdata 和它下面的所有檔案和目錄的擁有者全部改一下:
圖六

這時再切回到剛才圖四的「新表空間」對話方塊,再按一次「確定」,這次應該可以順利建立了。再來就可以把一些物件存放在這個 tablespace 裏了。這裏我建立一個 database,就放在這個新的 tablespace 'cheeren' 裏。注意看圖八,新的 database 'cheeren' 我是把它建立在 'cheeren' 表空間,而不是 pg_default:
圖七

圖八

來,我們先來看看圖九,建立成功。
圖九

再來再回到主題來。
記得我在 PostgreSQL 的 Tablespace 這篇文章中有提到說,tablespace 是以 symbolic link 連結到新的硬碟上的目錄。喔,但是看來看去,我都只有在新的硬碟上動手腳,並沒有看到原來的 $PGDATA 下有什麼更動呀?別急,我們先看看我們剛才建立的東西的 OID,回想一下,我曾經在 PostgreSQL 如何組織資料 這篇文章中提到,PostgreSQL 會以 OID 為檔名,將物件以一個一個實體檔案儲存在檔案系統中。至於資料庫,則是以和 OID 同名的目錄名稱存在。而在資料庫中的所有物件,則存在該目錄下。那我們來看看我們自己建立的新 tablespace,PostgreSQL 是不是如我們所預期的儲存呢?先來看看下一張圖:
圖十

參考一下圖十,我先切換成 pgsql,然後用客戶端程式 psql 連進去 cheeren database。然後我想查看一下 PostgreSQL 的系統表格 pg_tablespace。這個系統表格裏,正是存著整個 PostgreSQL cluster 的所有 tablespace 的清單。在圖十我先看看這個表格的定義。接著我打算 tablespace 清單列出 OID (實際檔案名,在這裏是在 $PGDATA 下的 symbolic link 的檔名)、tablespace 名和 tablespace 座落位置,正如圖十一所示:
圖十一

在圖十一裏,我多做了一件無聊的事,在 tablespace 'cheeren' 裏建立一個表格名為 foo 的資料表。事實上我用不著加上後面的 tablespace 'cheeren' 特別註明,因為我目前就在 database 'cheeren' 裏,而 database 'cheeren' 就存在於 tablespace 'cheeren';因此,這是多此一舉。無所謂,這樣定義得更清楚。接著我從系統資料表 pg_class 裏查詢 table 'foo' 的 OID,再從系統資料表 pg_database 裏查詢 database ' cheeren' 的 OID。請先來看看圖十二,先來看看在 $PGDATA 下是不是有一個 symbolic link 連到 /pgdata/cheeren?
圖十二

在 FreeBSD 上的 PostgreSQL 的 $PGDATA 是在 /usr/local/pgsql/data。我在 PostgreSQL 如何組織資料 這篇文章中曾說過,PostgreSQL 會把所有資料放在 $PGDATA 下。tablespace 這東西看起來這裏好像違反了我之前說的話,其實沒有。在圖十二中,我們可以看到,在 $PGDATA 下有一個子目錄 pg_tblspc,它裏面存放的,就是兩個預設的 tablespace 以外的 tablespace,而在這個子目錄裏,放的都只有 symbolic link。請看一下圖十二,目前 pg_tblspc 裏只有一個子目錄 16403,而 16403 就是 tablespace 'cheeren',所以我們看到 16403 其實是一個 symbolic link,連結到 /pgdata/cheeren 這個實際目錄。剛才在圖十一,可以看到 tablespace 'cheeren' 的 OID 正是 16403!
圖十三

我們再來看看圖十三,/pgdata/cheeren 裏,除了標示建立該 tablspace 的 PostgreSQL 版本的 PG_VERSION 以外,只有一個目錄 16404。從圖十一的最後一段,我們可以知道 database 'cheeren' 的 OID 正是 16404,也就是說,這個子目錄正是 database 'cheeren' 實際在檔案系統中的位置。再往下看,由於目錄 16404 之下有很多屬於 database 'cheeren' 的系統物件,所以我只列出 16xxx 的檔案,注意一下,是不是有一個 16411?從圖十一我們可以知道這個空空的檔案正是 table 'foo'!
好了,介紹到這裏,我快打不下去了。希望這樣一個 demo 可以讓您了解 PostgreSQL 的 tablespace 實際運作的情況,將來在考慮用 tablespace 來提昇效能時可以比照建立。還有,等我打完這篇文章我才想起,事實上同一個 database 裏的資料表格或 index 可以存在不同的 tablespace 裏,方法就像我在圖十一那樣,在 create table 或 create index 時附加一個 tablespace 子句特別註明。這樣子就能把資料表格和索引放在不同的硬碟,來避開兩者的存取競爭,提昇效能。

2010-3-18 補充:就在我伺服器硬碟掛掉的前兩天,William Tsai 網友留了以下的兩篇留言。因為我看都還沒看到這兩篇留言,硬碟就掛了,所以我也還沒時間測試。但是我特在此將他這份很有價值的留言留下(一字不改),請各位參考一下。待我驗證之後(無論結果如何),尤其是有關 NTFS 的 Junction 的功能後,再來寫一篇文章報告。

真是用心的好文啊

其實我也是用大象用很多年了
只是大部份的IT都仍選用Mysql為主
剛剛讀了您的PostgreSQL在 Linux/Unix下的 tablespace實作
源于我正好在測試windows 版的Postgresql 8.4版本 tableSapce管理
(其實我習慣用Linux.但這次被迫測試Windows)
因為我正在把Mysql 143Gb的data 移轉到Postgresql 上來測試大象的實力
但卻發現一個很不可思議的問題
postgresql裝在C:
所以我建了 一個新的在E: disk (size比較大) .要先建好table space的目錄 (e:\pg_big)CREATE TABLESPACE pg_big
OWNER XXXXX
LOCATION 'e:/pg_big';
這樣是ok的.也會build table 使用該tablespace 該有table 也會建立在另一顆disk .
本來還很開心
卻發現一個很恐怖的問題
您有提到Postgresql 的資枓都base on $PG_DATA
因為window沒有symbolic links
沒錯~~~~
但它的確可以work 在另一顆disk E:上
更可怕的是它居然在 c: 的$PG_DATA 中 build 出 一模一樣的資料
而且 做 DML 處理時 兩塊的資料均會同步異動
形成一種另類的 mirror disk
PostgreSQL的tablespace 在windows底下果然是個很令人失望的不滿意的地方
而且沒法子做到像oracle 那種tablespace
(一整個data file tablespace 有利于減少 inode 或是 windows 資料碎塊的問題 , 我做完 大量insert 後 disk io 因碎塊問題 performace大減)
連Mysql 都可以有連似的結構了 postgresql 居然沒有
與您分享

上篇補註

後來發現那個不是Mirror
如果你是用NTFS來玩
現在NTFS有新玩具我發現在做e : tablespace
postgresql 會在 $PG_DATA 中的tablespace 目錄建立一樣的目錄並且...
做了 類似 symbolic links 的功能
在NTFS中
有了新的結構 junction
http://en.wikipedia.org/wiki/NTFS_junction_point
所以在$PG_DATA 內建立的是對應其它disk 的 junction link
用來實現與 linux/unix 一樣的 symbolic links
與您分享囉.....







有 Creational Patterns 的原因,是否是有些狀況不適合直接用 new 建造出一個物件來用?

  沒錯!您的直覺非常準確,這正是整個創建型模式(Creational Patterns)核心要解決的根本問題。 在軟體開發中,直接使用 new 關鍵字來建立物件(例如 MyClass obj = new MyClass(); )雖然直覺又方便,但在中大型系統或需要高度擴充性的...