1. 程式人生 > >從IO看資料庫底層實現原理

從IO看資料庫底層實現原理

瘋哥說過,科學的態度永遠是嚴謹的,孜孜不倦的,追根究底的,我想各位歇斯底里的時候也純粹覺得這個是放屁。但是事實就是事實,容不得半點捏造。

最近研究了Hibernate中的一些問題,發現除了快取機制,還有些問題也值得我們深思,在hibernate嚴格限定Java包裝類和工具類與相應資料庫底層資料型別的對映的時候,各位是否想過,為什麼要這麼對映,也許你會說這個是hibernate3.0的規範而已,但是當初為什麼指定這樣的規範呢,也許各位沒有去深究,暫時我們拋開這個問題不談,這裡只說明一件事,那就是要積極的思考為什麼? 

學習完了各種資料庫,學習了各種SQL查詢語句後,你對資料庫瞭解多少,其底層是怎麼實現的?昨天和瘋哥就一個IO問題討論許久,回家後突然對資料庫的實現原理茅塞頓開,下面我就把我這兩天的一點總結和大家一起分享分享,希望大家不要見笑,共同交流,共同提高: 

1.首先我們要明白資料庫到底是怎麼儲存的: 

在Oracle中,我們的資料儲存在表中,我們的表儲存在表空間中,而表空間直觀的看就是幾個資料.dbf檔案,在驚訝Oracle和眾多資料庫的查詢速度之快的時候,我們自己讀取檔案的時侯就算運用了貌似很牛逼的各種快取機制來實現快速的從檔案中得到檔案中的資料,如果遍歷資料檔案,那麼絕對會出現全資料檔案遍歷的問題,那麼我們聯絡實際來尋求一種更加好的方式。 

2.生活的例項: 

在我們的生活中,長沙這麼大的城市我們想找一間房子或者酒吧,那麼就必須得到地址,否則就會漫無目的的到處亂撞,更合理的是遍歷整個城市的所有地點,我的天,這樣的效率該何其低下。得到地址和資料檔案聯絡起來的關係貌似不大,但是其中必有牽連,要不然牛叉的資料庫哪裡來的有理論支撐? 

3.解決方式: 

既然我們可以與地址掛鉤,你可能已經想到了將檔案逐條讀出,然後放入記憶體,然後根據地址去找,這樣做的話固然可以,但是對於突然地斷電,或者記憶體容量不夠的突發狀況的時候,就應該尋求更加穩妥和更加節約昂貴資源的方法,即:在檔案中按照地址來進行查詢和修改 

4:關於檔案偏移量: 
檔案不比記憶體,有相應的地址,但是我們可以採取另外一種類似於記憶體地址的方式,那就是檔案偏移量: 
在百度上面有人做了這樣的解答:檔案偏移:檔案開始的第一個位元組偏移量為0之後每經過一個位元組偏移量就加1 。對,我們就是要將檔案按照一定的格式和順序儲存,我們以後去讀取的時候只需要在相應的“地址簿”中獲取檔案偏移量,然後直接去操作IO進行讀取或者修改,就達到了快速的對資料檔案進行讀取和修改的問題。 


那麼我們用Java的IO包 中的RandomAccessFile類來模擬一下這樣的場景: 

首先介紹一下這個類,這個類稱之為隨機讀取檔案類,或者是隨機訪問檔案類,適應隨機讀取檔案,但是一般將它用於處理定長資料,何謂定長資料呢?則是每條記錄按照相應的格式並且擁有相同的位元組長度,這樣處理起來才能更加的方便,IO才知道到底從哪裡開始讀取資料和獲取資料,同樣的在網路上的斷點續傳,多執行緒下載就是這樣的理論的經典實現,但是現在我們不拘泥與理論,上程式碼: 

public class Employee {
	private String name;
	private int age;
	public static final int len = 8;// String 型的定長,相當於資料庫中的型別長度

	public Employee(String name, int age) {
		if (name.getBytes().length >= len) {
			this.name = name.substring(0, len);
		} else {
			while (name.getBytes().length < len) {
				name += "\u0000";// 空白 ,佔8b
			}
			this.name = name;
		}
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
}

// 我現在建立幾個物件進行儲存:
public class TestRandomAccessFile {
	public static void main(String[] args) throws Exception {

		Employee e1 = new Employee("張三", 23);
		Employee e2 = new Employee("zhangsan", 35);
		Employee e3 = new Employee("li張三", 67);

		RandomAccessFile rf = new RandomAccessFile(new File("C:/employee.txt"),
				"rw");

		rf.write(e1.getName().getBytes());
		rf.writeInt(e1.getAge());
		rf.write(e2.getName().getBytes());
		rf.writeInt(e2.getAge());
		rf.write(e3.getName().getBytes());
		rf.writeInt(e3.getAge());

		rf.close();

		RandomAccessFile raf = new RandomAccessFile(
				new File("C:/employee.txt"), "r");
		raf.skipBytes(12);

		byte[] buf = new byte[8];
		int i = raf.read(buf);
		System.out.println("i= " + i);
		System.out.println(new String(buf).trim() + raf.readInt());

		raf.seek(24);
		raf.read(buf);
		System.out.println("i= " + i);
		System.out.println(new String(buf).trim() + raf.readInt());
	}
}


結果如下: 
i= 8 
zhangsan35 
i= 8 
li張三67 


在對資料進行指定位置的讀取的時候,其他的修改和快速檢索的實現和類似於資料庫建立索引的實現的問題其實就是將所在的檔案讀取偏移量儲存與一個B-tree中進行快捷所有的功能。如果你想做的更加完善,那麼請參考MS-SQL中的經典理論著作,資料庫系統原理。 


到此我相信大家對我文章開始的那個問題,即為什麼嚴格限定型別對映和資料庫欄位定長的問題,有了一個比較清晰的答案。這裡我就不廢話了,希望各位學的愉快。