利用反射和註解模擬ORM框架中的自動建表功能

天堂2013發表於2016-12-21

在Mybatis當中,可能我們經常會用到在一個方法上加上註解,如:@Insert,@Update,@Delete,@Select,加上這些註解後,框架就能幫助我們執行sql語句,那框架是如何實現的呢?今天筆者就使用註解和反射的知識模擬了一個自動建資料表的功能,當然只是一些簡單的程式碼,重要的是其中的原理。

加入我們現在有一個JavaBean,那麼我們如何利用反射和註解實現,讓資料庫自動幫我們建立一張和該JavaBean對應的資料表呢?

首先我們得弄清楚JavaBean和資料表結構的對應關係:


類對應表,屬性對應列,物件對應資料庫中表的一條記錄,那麼建立一張表就需要表名,列名,則我們可以分別在類上加上註解,用來得到表名,在屬性上加上註解,得到列名。

具體程式碼如下:

先定義兩個註解:

類上的註解:

package com.tiantang.annotation;

import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 類的註解,對應於資料庫中的表
 * @author LiuJinkun
 *
 */
@Target(TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTable {
	/**
	 * 對應資料庫的表名
	 * @return
	 */
	String value();
}
屬性上的註解:

package com.tiantang.annotation;

import static java.lang.annotation.ElementType.FIELD;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 屬性的註解,對應於資料庫中的列
 * @author LiuJinkun
 *
 */
@Target(FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyField {
	/**
	 * 表的列名
	 * @return
	 */
	String columnName();
	
	/**
	 * 每一列的長度
	 * @return
	 */
	int length();
	
	/**
	 * 列的型別
	 * @return
	 */
	String type();
}




注意,這裡在自定義註解時,需要把註解的宣告週期設定成RetentionPolicy.RUNTIME,因為反射是在程式執行時才能使用的,因此要想用反射獲取到註解,則需要註解在程式執行時還存在著。

定義的JavaBean類:

package com.tiantang.annotation;

@MyTable("students")
public class Student {

	@MyField(columnName = "student_id", length = 6, type = "int")
	private int id;

	@MyField(columnName="name",length=20,type="varchar")
	private String name;

	@MyField(columnName="address",length=30,type="varchar")
	private String address;
	
	@MyField(columnName="phone",length=20,type="varchar")
	private String phone;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

}

測試類:在測試類中,當程式執行時,利用反射獲得類和屬性的註解,然後拼接SQL語句:

package com.tiantang.annotation;

import java.lang.reflect.Field;

public class Client {
	
	public static void main(String[] args) throws Exception {
		//用於拼接sql語句
		StringBuffer sql=new StringBuffer();
		
		Class<?> clazz=Class.forName("com.tiantang.annotation.Student");
		//獲取類上的註解
		MyTable myTable=clazz.getAnnotation(MyTable.class);
		String tableName=myTable.value();
		sql.append("CREATE TABLE "+tableName+" ( ");
		//獲取類的屬性
		Field[] fields=clazz.getDeclaredFields();
		
		for(Field f:fields){
			//獲取屬性上的註解
			MyField myField=f.getAnnotation(MyField.class);
			//拼接sql語句
			sql.append(myField.columnName()+" "+myField.type()+"("+myField.length()+"),");
		}
		//因為該sql語句最後會多一個逗號,這裡將其刪除
		sql.deleteCharAt(sql.length()-1);
		sql.append(")");
		//列印sql語句
		System.out.println(sql.toString());
	}

}
這樣SQL語句就拼接完成了,接下來執行sql語句就簡單了,讀者可以自行測試。這樣我們就簡單的實現利用反射和註解根據JavaBean的結構來自動建表的功能。當然,在框架裡面自動建表大部分都是通過解析XML配置檔案來實現的。



相關文章