常用hibernate注解:表关联,字段属性注解
现在主流的的ORM就属hibernate和mybatis了。两者相比之下,hibernate更加灵活,部分SQL功能可以使用丰富的注解实现,而mybatis一般都是构建原生的SQL实现的。
1.基本注解
实现hibernate的核心应该就属Entity。一个简单的JOPO,我们添加@Entity标注这是一个实体类,默认使用类名作为表名,使用字段名作为列明,一个完整的Entity类的结构就对应一张数据库中的表。
我们使用@Table(name="newTableName") 注解自定义表名 使用@Column(name="newColumnName") 注释自定义列明 @Column还可以使用nullbale属性配置是否可空,使用length指定长度。
@Entity @Table(name = "simple") @Data public class simpleTable { @Id @Column(nullable = false, length = 36) private String id; @Column(name = "column") private String id; }
这个类最终会被转化为一张表,名字叫simple,里面包含2个varchar类型的列。
2.表关系注解
一张表可能与某张表存在关联,比如classrom和student存在一对多的关系,反过来就是多对一的关系,表也可能是关联自生,一般用于表示一些简单的层级关系。比如公司的组织构架.存在具体某个人身兼多职的情况.那么单个岗位下有多个人,单个人可以又多个岗位。
2.0 一对一关系
针对一对一的情况,比如一个学生对应一张课桌。student作为主控方包含了一个Desk的外键(desk_id),所谓主控方就是能改变关联关系的一方。如下定义,student表在数据库中只存了一个desk的id,但在实体中是具体的Desk类。
@JoinColumn不写会生成一张中间表
public class student() { @OneToOne(cascade=CascadeType.ALL,optional=true) //注释本表中指向另一个表的外键。 @JoinColumn(name="deskId") private Desk desk; }
2.1 一对多关系
针对一对多的情况,我们使用@OneTOMany注解表示,hibernate会自动帮我们设置数据库中的外键。CascadeType用于设置级联属性,比如级联更新 级联删除等。
mappedBy 用在一对多关系中是【一】的一方,其值是存在【多方】的表的列名。在这里会在student类中增加classromno列。
查询某个classrom的时候会自动查询出班级中所有的学生。
当然子表默认都是懒加载模式,没用到的话,是不会自动查询出所有的学生的。
@Entity @Table(name = "classrom") @Data public class ClassRom{ @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "classromno") private Setstudents; }
2.2 多对一关系
现在我们反过来在学生表上加上多对一的关系注解,使用@ManyToOne表示多对一的关系,CascadeType属性和@OneTOMany中的一样,@JoinColumn设置了一个列用于保存classrom的id,在这里会新增名为classrom_id的列指向对应的classrom。如果不加@JoinColumn则会生成一张中间表,包含了这2张表的id。
@Entity @Table(name = "student") @Data public class Student{ @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "classromid") private ClassRom classRom; }
2.3 多对多关系
每个学生都要上多门课程,每门课程又有诺干个学生,这属于多对多的关系。@Id表示这个是id列。@GeneratedValue和@GenericGenerator用于表示这个是hibernate管理的uuid类型的值。
@ManyToMany表示多对多的关系,多对多肯定需要中间表,所以不需要 @JoinColumn和mappedBy
@Entity @Data public class Student { @Id @GeneratedValue(generator = "idGenerator") @GenericGenerator(name = "idGenerator", strategy = "uuid") private String id; private String sName; @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY) private Setcourses = new HashSet<>(); }
3.关于DTYPE
假定我定义了个实体People,然后定义了2个子类Student和Teacher。默认设置下,最终在数据库层面只会生成一张people表,people包含了所有资源额外的字段,这个时候我们再从people表读取数据,怎么判断
某一行的数据是应该被实例化成父类还是某个子类的?
这个问题类似于json反序列化时候的多台问题:我该怎么把一个对象序列化成一个接口,或者某个数据可能是某个父类的多个实现类中的任意一个。
hibernate的解决办法和json的解决办法一致,直接标记应该创建成哪个类的实例。在people表中会有个dtype字段,里面存的值是具体的类名,读取的时候直会按类名生成对象。