详解Java注解实现自己的ORM
搞过Java的码农都知道,在J2EE开发中一个(确切地说,应该是一类)很重要的框架,那就是ORM(Object Relational Mapping,对象关系映射)。它把Java中的类和数据库中的表关联起来,可以像操作对象那样操作数据表,十分方便。给码农们节约了大量的时间去摸鱼。其实它的本质一点都不复杂,而最核心的就是怎么实现对象和表之间的转换。之前对反射和注解有了一点了解,所以就试着来实现咱们自己的缝合怪。
首先,需要建立一个「表格」:
/** * 类注解,将类注解成数据库表 * * @author xiangwang */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DBTable { String name() default ""; }
然后,定义需要的数据库数据类型:
/** * 字段类型枚举 * * @author xiangwang */ public enum Type { CHAR, STRING, BOOLEAN, INTEGER, LONG, FLOAT, DOUBLE, DATETIME } /** * 数据库字段类型 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ColumnType { Type value() default Type.INTEGER; }
再来完善字段相关信息:
/** * 字段信息 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExtraInfo { String name() default ""; int length() default 0; } /** * 明确字段约束 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; // 还可以增加默认值 }
把他们拼起来,成为完整的字段描述:
/** * 拼装注解,形成完整的字段嵌套注解 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TableColumn { ColumnType columntype() default @ColumnType; ExtraInfo extrainfo() default @ExtraInfo; Constraints constraints() default @Constraints; }
最后,创建实体类,应用刚才写好的这些注解:
/** * 用户实体类 * * @author xiangwang */ @DBTable(name = "User") public class User { @TableColumn( columntype = @ColumnType(Type.INTEGER), extrainfo = @ExtraInfo(name = "id", length = 4), constraints = @Constraints(primaryKey = true)) private String id; @TableColumn( columntype = @ColumnType(Type.STRING), extrainfo = @ExtraInfo(name = "name", length = 32), constraints = @Constraints(primaryKey = false, allowNull = false, unique = true)) private String name; @TableColumn( columntype = @ColumnType(Type.INTEGER), extrainfo = @ExtraInfo(name = "age", length = 4), constraints = @Constraints(primaryKey = false)) private Integer age; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
来看看ORM是怎么工作的吧:
/** * 解析类型注解 */ private static String getColumnType(ColumnType columntype) { String type = ""; switch (columntype.value()) { case CHAR: type += "CHAR"; break; case STRING: type += "VARCHAR"; break; case BOOLEAN: type += "BIT"; break; case INTEGER: type += "INT"; break; case LONG: type += "BIGINT"; break; case FLOAT: type += "FLOAT"; break; case DOUBLE: type += "DOUBLE"; break; case DATETIME: type += "DATETIME"; break; default: type += "VARCHAR"; break; } return type; } /** * 解析信息注解 */ private static String getExtraInfo(ExtraInfo extrainfo) { String info = ""; if (null != extrainfo.name()) { info = extrainfo.name(); } else { return null; } if (0 < extrainfo.length()) { info += " (" + extrainfo.length() + ")"; } else { return null; } return info; } /** * 解析约束注解 */ private static String getConstraints(Constraints con) { String constraints = ""; if (con.primaryKey()) { constraints += " PRIMARY KEY"; } if (!con.allowNull()) { constraints += " NOT NULL"; } if (con.unique()) { constraints += " UNIQUE"; } return constraints; }
做了那么多的铺垫,终于到了临门一脚了,实现一个缝合怪了:
/** * 临门一脚:实现一个缝合怪 */ private static void createTable(List<String> list) { for (String className : list) { Class<?> clazz; try { clazz = Class.forName(className); DBTable dbTable = clazz.getAnnotation(DBTable.class); if (dbTable == null) {// 无DBTable注解 continue; } // 转大写 String tableName = clazz.getSimpleName().toUpperCase(); StringBuilder sql = new StringBuilder("CREATE TABLE " + tableName + "("); for (Field field : clazz.getDeclaredFields()) { // 反射得到注解 Annotation[] anns = field.getDeclaredAnnotations(); if (anns.length < 1) { continue; } String columnInfo = ""; // 类型判断 if (anns[0] instanceof TableColumn) { TableColumn column = (TableColumn) anns[0]; String type = getColumnType(column.columntype()); columnInfo = getExtraInfo(column.extrainfo()); // 代替( columnInfo = columnInfo.replace("(", type + "("); columnInfo += getConstraints(column.constraints()); } sql.append("\n " + columnInfo + ","); } // 删除尾部的逗号 String tableCreate = sql.substring(0, sql.length() - 1) + "\n);"; System.out.println(tableCreate); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
验证效果的时候到了:
public static void main(String[] args) { Class<?> clazz = User.class; List<String> list = new ArrayList<>(); list.add(clazz.getName()); createTable(list); }
当然,实际的运营于生产环境中的ORM框架可要比这个小玩意复杂多了。但千变万变,原理不变,ORM的核心——反射+ 注解——就是这么玩的。
到此这篇关于Java注解实现自己的ORM的文章就介绍到这了,更多相关Java注解ORM内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
原文出处:https://www.cnblogs.com/xiangwang1111/archive/2022/10/15/167
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了Swagger中@ApiIgnore注解的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-21
- 本篇文章是对C#中WinForm控件之Dock顺序调整进行了详细的分析介绍,需要的朋友参考下...2020-06-25
校验非空的注解@NotNull如何取得自定义的message
这篇文章主要介绍了校验非空的注解@NotNull如何取得自定义的message,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-29- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了WebStorm无法正确识别Vue3组合式API的解决方案,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...2021-02-18
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
antd Form组件方法getFieldsValue获取自定义组件的值操作
这篇文章主要介绍了antd Form组件方法getFieldsValue获取自定义组件的值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
- @Autowired 注解的主要功能就是完成自动注入,使用也非常简单,但这篇文章主要给大家介绍了关于Spring为什么不推荐使用@Autowired注解的相关资料,需要的朋友可以参考下...2021-11-03
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03