首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

以 Java 註解動態產生建表 SQL:從 Think in Java 實作談起

     編輯:關於SqlServer

閱讀《Think in Java》註解章節後深受啟發,嘗試以自訂註解搭配反射機制,自動產生建立資料表的 SQL 指令。這不僅是練習,更能窺見 Hibernate 等 ORM 框架的核心運作原理。

核心註解設計

1. @DBTable - 表層級註解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
    String name() default "";
}
  • @Target(ElementType.TYPE):限定用於類別、介面、列舉。
  • @Retention(RUNTIME):執行期保留,供反射讀取。
  • name():指定表名,預設為類別名大寫。

2. @Constraints - 欄位約束註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
    boolean primaryKey() default false;
    boolean allowNull() default true;
    boolean unique() default false;
}

3. @SQLInteger / @SQLString - 欄位型別註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
    String name() default "";
    Constraints constraints() default @Constraints;
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
    int value() default 0;       // VARCHAR 長度
    String name() default "";
    Constraints constraints() default @Constraints;
}

TableCreator 處理器:反射掃描並組裝 SQL

public class TableCreator {
    public static void main(String[] args) {
        createTable(Member.class);
    }

    private static void createTable(Class<?> cl) {
        DBTable dbTable = cl.getAnnotation(DBTable.class);
        if (dbTable == null) { System.out.println("無 @DBTable 註解"); return; }

        String tableName = dbTable.name().isEmpty() 
            ? cl.getSimpleName().toUpperCase() : dbTable.name();

        List<String> columnDefs = new ArrayList<>();
        for (Field field : cl.getDeclaredFields()) {
            Annotation[] anns = field.getDeclaredAnnotations();
            if (anns.length == 0) continue;

            String columnName = null;
            if (anns[0] instanceof SQLInteger) {
                SQLInteger sInt = (SQLInteger) anns[0];
                columnName = sInt.name().isEmpty() 
                    ? field.getName().toUpperCase() : sInt.name();
                columnDefs.add(columnName + " INT " + getConstraints(sInt.constraints()));
            } else if (anns[0] instanceof SQLString) {
                SQLString sStr = (SQLString) anns[0];
                columnName = sStr.name().isEmpty() 
                    ? field.getName().toUpperCase() : sStr.name();
                columnDefs.add(columnName + " VARCHAR(" + sStr.value() + ")" 
                    + getConstraints(sStr.constraints()));
            }
        }

        StringBuilder sql = new StringBuilder("CREATE TABLE " + tableName + "(");
        for (String col : columnDefs) {
            sql.append("\n ").append(col).append(",");
        }
        String ddl = sql.substring(0, sql.length() - 1) + ");";
        System.out.println("Table creation SQL for " + cl.getName() + " is :\n" + ddl);
    }

    private static String getConstraints(Constraints con) {
        StringBuilder sb = new StringBuilder();
        if (!con.allowNull()) sb.append(" NOT NULL");
        if (con.primaryKey()) sb.append(" PRIMARY KEY");
        if (con.unique()) sb.append(" UNIQUE");
        return sb.toString();
    }
}

執行結果範例

建表 SQL 輸出結果

心得與延伸

這個簡易實作揭示了「註解 + 處理器」的核心模式:Hibernate、MyBatis 等框架本質上也是在執行期掃描實體類別的註解(或 XML),動態組裝 SQL。理解此原理,有助於深入掌握 ORM 運作機制,未來擴充自訂 CRUD 邏輯也更得心應手。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved