java 自动创建mysql表_根据JavaBean 自动生成数据库表
有了一个框架,只需要配置好数据库连接,就可以在java代码层操控database,对于写个model便在数据库中创建了一张表而感到十分神奇,隐约想起以前看《Thinking in Java》中关于注解(Annotation)一张中对于自动生成SQL语句的操作。首先略微介绍下注解(亦称为与数据metadata(ORM-对象/关系映射中的核心))。Annotation源自JavaSE1.5,内置3个标
有了一个框架,只需要配置好数据库连接,就可以在java代码层操控database,对于写个model便在数据库中创建了一张表而感到十分神奇,隐约想起以前看《Thinking in Java》中关于注解(Annotation)一张中对于自动生成SQL语句的操作。
首先略微介绍下注解(亦称为与数据metadata(ORM-对象/关系映射中的核心))。
Annotation源自JavaSE1.5,内置3个标准注解,4个元注解:
(1)java.lang.*中的@Override,@Deprecated, @SuppressWarnings
(2)java.lang.annotations.*中的@Target, @Inherited, @Retention, @Documented
对于后4个元注解,稍后再在代码中解释。
对于一个创建表的SQL Create语句,我们要确定几个元素:表名,列名,列名类型,类型长度,约束等,这些都可以在实体类的属性加以注解说明来实现。
对于表名注解:


1 1 packageannotiation;2 2 import java.lang.annotation.*;3 3
4 4 @Inherited //允许子类继承父类中的注解
5 5 @Documented //将此注解包含在Javadoc中
6 6 @Target(ElementType.TYPE) //类、接口(包括注解类型)或枚举类型声明
7 7 @Retention(RetentionPolicy.RUNTIME) //VM在运行时保留注解,从而通过反射获取信息
8 8
9 9 public @interfaceDBTable {10 10 public String name() default ""; //注解未赋值是,默认为空
11 11 }
View Code
对于字段注解:(这边先只设定了String类型,其实实际情况没这么单纯,下篇再优化)


1 1 packageannotiation;2 2 import java.lang.annotation.*;3 3
4 4@Inherited5 5@Documented6 6 @Target(ElementType.FIELD) //域声明(包括枚举类型实例)
7 7@Retention(RetentionPolicy.RUNTIME)8 8
9 9 public @interfaceSQLInteger {10 10 String name() default "";11 11 Constraints constraints() default @Constraints; //约束注解,详细见下面代码
12 12 }
View Code
对于约束注解:


1 packageannotiation;2 import java.lang.annotation.*;3
4@Inherited5@Documented6@Target(ElementType.FIELD)7@Retention(RetentionPolicy.RUNTIME)8
9 public @interfaceConstraints {10 boolean primaryKey() default false; //主键,默认为空
11 boolean allowNull() default true; //默认允许为空
12 boolean unique() default false; //默认允许重复
13 }
View Code
实体类:


1 packagemodel;2
3 import annotiation.*;4
5 @DBTable(name = "User") //设置表名为User
6 public classUser {7 @SQLString(size = 50) //设置字段 username, varchar(50)
8String username;9
10 @SQLString(size = 50)11String password;12
13 @SQLString(size = 30, constraints = @Constraints(primaryKey = true)) //设置为主键
14String handle;15
16 static intmemberCount;17
18 public String getUsername() { returnusername; }19
20 public void setUsername(String username) { this.username = username; }//个人感觉set方法可以去掉
21
22 public String getPassword() { returnpassword; }23
24 public void setPassword(String password) { this.password =password; }25
26 public String getHandle() { returnhandle; }27
28 public void setHandle(String handle) { this.handle =handle; }29
30 public String toString() { returnhandle; }31 }
View Code
准备工作之后,就是如何根据注解和反射拼接SQL语句:


1 packagecreator;2 import java.lang.reflect.*;3 import java.lang.annotation.*;4 import java.util.*;5
6 importannotiation.Constraints;7 importannotiation.DBTable;8 importannotiation.SQLString;9
10
11 public classTableCreator {12 private static String getConstraints(Constraints constraints) { //获取字段约束属性
13 String cons = "";14 if (!constraints.allowNull()) {15 cons += " NOT NULL";16}17 if(constraints.primaryKey()) {18 cons += " PRIMARY KEY";19}20 if(constraints.unique()) {21 cons += " UNIQUE";22}23 returncons;24}25
26 /*这边还需要通过IO来遍历指定model包下所有实体类, 如上,待下一篇优化
27 private static ArrayList getTables() {
28 ArrayList tables = new ArrayList();
29 Package pckg = Package.getPackage("model");
30 Class>[] cls = pckg.;
31 for (Class> cl : cls) {
32 tables.add(cl.getName());
33 }
34 return tables;
35 }
36*/
37
38 public static String getSql() throwsClassNotFoundException {39 String sql = null;40 //ArrayList tables = getTables();
41 String[] tables = {"model.User"};42 for(String className : tables) {43 /*44 String[] table = className.split("\\.");
45 for (String tb : table) {
46 System.out.println(tb);
47 }
48*/
49 Class> cl = Class.forName(className); //通过类名得到该实体类
50 DBTable dbtable = cl.getAnnotation(DBTable.class); //通过注解得到表明
51 String tableName = dbtable.name().length() > 1 ?dbtable.name() : cl.getName().toUpperCase();52 /*comments
53 System.out.println("tableName: " + tableName);
54*/
55 List columns = new ArrayList();56 for (Field field : cl.getDeclaredFields()) { //得到该类下所有属性
57 String columnName = null;58 Annotation[] annotations =field.getAnnotations();59 if (annotations.length < 1) {60 continue;61}62 if (annotations[0] instanceofSQLString) {63 SQLString sStr = (SQLString)annotations[0];64 columnName = sStr.name().length() < 1 ?field.getName() : sStr.name();65 columns.add(columnName + " VARCHAR(" + sStr.size() + ")" +getConstraints(sStr.constraints()));66}67}68
69 StringBuilder sb = new StringBuilder("Create Table " + tableName + "(");70 for(String column : columns) {71 sb.append("\n " + column + ","); //拼接各个字段的定义语句
72}73 sql = sb.substring(0, sb.length() - 1) +");";74}75 System.out.println("=========" + sql + "========="); //测试输出
76 returnsql;77}78 }
View Code
输出的语句应该是:


1Create Table User(2 username VARCHAR(50),3 password VARCHAR(50),4 handle VARCHAR(30) PRIMARY KEY);
View Code
既然有了SQL语句,只需要通过JDBC连接数据库执行即可(其实还可以封装之后实现相同CRUD操作,下篇优化):


1 packagedbconnect;2
3 importjava.sql.Connection;4 importjava.sql.DriverManager;5 importjava.sql.SQLException;6 importjava.sql.Statement;7
8
9 public classDBConnect {10 staticConnection connect;11 static String driver = "com.mysql.jdbc.Driver";12 static String password = "thoupin'spassword";13 static String username = "thoupin";14 static String dbName = "test";15 static String url = "jdbc:mysql://localhost/" +dbName;16
17 public static void connect() { //连接
18 try{19Class.forName(driver);20 } catch(ClassNotFoundException e) {21 System.out.println("Can not find the Driver!");22e.printStackTrace();23}24
25 try{26 connect =DriverManager.getConnection(url, username, password);27 } catch(SQLException e) {28 System.out.println("Database connect failed!");29e.printStackTrace();30}31}32
33 public static void execute(String sql) { //执行语句
34Statement stmt;35 try{36 stmt =connect.createStatement();37stmt.executeUpdate(sql);38 } catch(SQLException e) {39 //TODO Auto-generated catch block
40e.printStackTrace();41}42}43
44 public static void close() { //关闭连接
45 if (connect != null) {46 try{47connect.close();48 } catch(SQLException e) {49e.printStackTrace();50}51}52}53 }
View Code
最后就是主程序了:


1 packageMain;2
3 importcreator.TableCreator;4 importdbconnect.DBConnect;5
6 public classrun {7 public static voidmain(String[] args) {8DBConnect.connect();9 try{10DBConnect.execute(TableCreator.getSql());11 } catch(ClassNotFoundException e) {12 //TODO Auto-generated catch block
13e.printStackTrace();14}15DBConnect.close();16}17 }
View Code
最后数据库中变出现了一张新表:

至此,一个自己粗糙简陋的自动生成工具算是做好了,但实际情况很复杂,远远没有这么简单, 类似不同字段类型的判断,多张表的同时创建,判断新旧表从而决定是否重新执行SQL, 实体改动对数据库的影响等等问题,就此一系列后面几篇做优化和研究。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)