阅读之前我们带着几个小问题去阅读下面文中的内容,本文以Hibernate
框架理解ORM
框架映射的实现原理。
ORM
映射框架中的entity
(实体类)名字和表名不一致是如何与数据库表名对应的?entity
(实体类)中的属性采用驼峰命名
,以:userName
,和数据库表中user_Name
是如何对应的?- 为什么
Hibernate
通过entity
(实体类)就能完整的得到SQL
语句?
下面我们完成一个ORM
框架中entity
(实体类) 与表字段不一致,却能生成完整的SQL语句的案例。
在使用Hibernate
框架时,我们会创建实体类,创建字段去对应数据库表以及字段会使用到核心的两个注解,@Table
和@Column
,其他的@Entity
、@Id
等注解我们就先忽略,重点在原理上。
@Table 注解
该注解在使用时让实体类与表名对应,@Table("user_table")
,这个注解其实就相当于起了一个别名的作用,我们可以尝试自定义一个注解模仿还原该注解。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTable {
String value();
}
关于自定义注解,我就不做过多解释了。
@Column 注解
该注解用于实体类字段上,相当于该字段的别名,使其和数据库表中的列(Column
即:列)对应。我们去自定义个和@Column
注解相当的注解。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyColumn {
String columnName();
int columnLength();
String columnType();
}
实体类
@MyTable("user_table")
public class User {
@MyColumn(columnName="user_name",columnLength=5,columnType="String")
private String userName;
@MyColumn(columnName="user_age",columnLength=5,columnType="int")
private int userAge;
@MyColumn(columnName="user_id",columnLength=5,columnType="int")
private int userId;
@MyColumn(columnName="user_gender",columnLength=1,columnType="int")
private int gender;
// 省略get/set/构造/toString等方法
}
现在我们完成了两个核心的注解,实体类也和数据库表对应了,那么下一步就是通过实体类生成SQL
。
生成SQL
想要生成完整的SQL,就需要拿到表名,字段名。刚才在通过我们自定义的两个注解和数据库表已经做了一个映射了。那么我们怎么才能拿到呢?我们可以通过 反射
!
import java.lang.reflect.Field;
public class MyOrmTest {
public static void main(String[] args) throws ClassNotFoundException {
System.out.println(selectUserTable());
}
public static String selectUserTable() throws ClassNotFoundException {
// 通过反射获取到Class
Class<?> classForName = Class.forName("orm.test.User");
// 获取注解@MyTable
MyTable table = classForName.getAnnotation(MyTable.class);
// 获取到类的所有字段
Field[] Fields = classForName.getDeclaredFields();
// 拼接SQL
StringBuffer sb = new StringBuffer();
sb.append(" select ");
// 获取注解@MyTable的值
String tableName = table.value();
// 迭代类中所有字段,获取字段上注解@MyColumn的值并拼接SQL
for (int i = 0; i < Fields.length; i++) {
Field field = Fields[i];
MyColumn column = field.getAnnotation(MyColumn.class);
sb.append(" " + column.columnName() + " ");
if (i == Fields.length - 1) {
sb.append(" from ");
} else {
sb.append(",");
}
}
sb.append(" " + tableName);
return sb.toString();
}
}
ORM
很多的细节,比如字段类型的处理等等,就不去了解了,我们了解ORM
和核心原理即可。