Hibernate 使用注解做元数据

1. 前言

本节课将和大家一起讲解元数据概念,通过注解的方式实现 Hibernate 操作数据库。

这一切,会让工作变得更加简单、直接!!本节课程你将学习到:

  • 什么是元数据;
  • Hibernate 中有哪些注解;
  • JPA 是什么。

2. 元数据

什么是元数据

先举一个生活中的例子:你买了一袋面粉,想用来揉几个包子,发几个馒头……

可以把面粉当成原始数据,包子、馒头是你运用你的技能加工之后的成品数据。这里的技能相当于开发者的编程能力

但是!元数据到底是什么!!!

买面粉的时候面粉袋上有很多说明,面粉出自何地、面粉的净重量有多少……

这些信息对于你的加工过程有很大的参考价值。面粉的出生地让你知道什么地方出产的面粉适合做馒头、什么地方出产的面粉适合做面包……

净重量能告诉你最后能生产几个包子、几个馒头……如果人多,就应该多买几袋,至少能让你在款待客人时表现的美丽又大方。

元数据的标准概念是用来描述数据的数据!

换一句容易理解的话,面粉是数据,用来包装面粉的面粉袋上的说明信息就是元数据。

大家知道持久化对象吧:POJO+XML。XML描述的映射信息就是用来描述学生对象数据的元数据。

3. Hibernate 中使用注解

Hibernate 中,通过元数据的方式描述映射关系,其表达语法有 2 种:

  • 其一: XML 语法;
  • 其二: 本节课程要给大家隆重推荐的是注解语法。

注解语法本质就是 Java 语法。

3.1 什么是注解

注解相当于开发者给代码添加的注释,对,注释也是元数据,但注释是开发者之间进行交流用的,编译器和JVM都会当它不存在。

注解就不同了:

  • 告诉编译器和 JVM 如何正确使用其所标注的数据;
  • 注解是 JAVA5.0 后推出的一种新的编程思想;
  • Java 里面可以用来和 public、static 等关键字一样来修饰类名、方法名、变量名。

3.2 使用注解重构代码

现在使用注解方式重构前面代码,使用之前先秀出 Hiernate 中常用的几个注解:

  • @Table:描述实体类对应的表名;
  • @Idclass:指定充当主键的类;
  • @Entity: 标注类是实体类;
  • @Id: 描述哪个属性对应表中的主键字段;
  • @Column:指定与属性对应的字段名;
  • @Basic:等价于没有定义注解的属性;
  • @Transient :属性不被持久化。

不要指望一下记住它们,还是通过使用的过程逐步理解为上策。

友情提示:心急吃不了热豆腐!!

修改学生类

@Entity  
public class Student {
    private Integer stuId;
    private String stuName;
    private String stuSex;
    public  Student(Integer stuId, String stuName, String stuSex) {
        super();
        this.stuId = stuId;
        this.stuName = stuName;
        this.stuSex = stuSex;
    }  
    public Student(String stuName, String stuSex) { 
        super();
        this.stuName = stuName;
        this.stuSex = stuSex;
    }         
    public Student() {
        super();
    }      
    @Id      
    public Integer  getStuId() {
        return stuId;      
    }      
    public void  setStuId(Integer stuId) {
        this.stuId = stuId;      
    }      
    public String  getStuName() { 
        return stuName;  
    }      
    public void  setStuName(String stuName) {
        this.stuName = stuName;     
    }      
    public String  getStuSex() {    
        return stuSex;      
    }      
    public void  setStuSex(String stuSex) {
        this.stuSex = stuSex; 
    } 
}  

这样可以吗?是的,可以啦。

用放大镜扫描一下上面的学生类,好不容易看到 2 个注解:

  • @Entity:标注这个类是持久化类;
  • @Id:标注这个属性是标识属性,必须给出。

不要怀疑,对于 Hibernate 来说已经足够,需要知道的常识是:

对于其它没有标注任何注解的属性,Hibernate 默认为数据库的表中有与属性同名的字段。

替换主配置文件

<mapping resource="com/mk/po/Student.hbm.xml" />

替换成:

<mapping class="com.mk.po.Student" />

运行测试实例

// 配置对象
Configuration  configuration = new  Configuration().configure();
// 服务注册
ServiceRegistry  serviceRegistry =new ServiceRegistryBuilder().applySettings(configuration.getProperties())               .buildServiceRegistry();
// 会话工厂
SessionFactory  sessionFactory = configuration.buildSessionFactory(serviceRegistry);  
// 会话对象
Session  session = sessionFactory.openSession();
// 事务对象
Transaction  transaction = null;
try {
    // 打开事务
    transaction = session.beginTransaction();  
    // 添加一条学生信息
    Student  student = new Student(2, "Configuration02", "男");  
    session.save(student);
    transaction.commit();
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
} 
}  

测试代码还是原来的测试代码!只是新增了一条数据!进入 MySQL 瞧一瞧,数据如假包换的插入成功。

图片描述

是不是感觉如春风般温暖!对 Hibernater 的感受又增加了很多。

简直让人无法相信,2 个注解就映射成功。但是,这是有前提条件的:

  • 应用程序中的类名关系数据库中的表名同名时,使用一个@Entity 注解足够;

  • 类名和表名不一样时,则需使用 @Table(表名)注解告诉 Hibernate

  • 应用程序中类中的属性名数据库表中的字段名同名时,Hibernate自会心领意会。

    实质是没有提供注解的属性默认使用了@Basic 注解。

  • 如果属性名字段名不同名时,请使用 @Column ( name=“stuName”) 注解明确告诉 Hibernate

  • 如果类中某一个属性本就没有对应字段名,仅仅是方便程序中某些需求,这时需要在此属性上加上 @Transient,让 Hibernate 对此属性视之不理。

3.3 注解的位置

注解说:我可不是随便的代码!

每一个注解都有自己位置。

  • 如同 @Entity、@Table 是类级别注解,对类做整体说明;
  • 如同 @Id、@Column、@Transient 这几个注解是属性、方法级别的,可对属性或方法做说明,如下:
  @Id
  private Integer stuId;
  @Column
  private String stuName;

  @Id
  public Integer getStuId() {
      return stuId;
  }
  @Column
  public String getStuName() {
      return stuName;
  }

如上 2 种方式都可告诉 Hibernate 如何映射表中的对应字段。既然有 2 种方案,必然会有优劣之分(有比较就会有差别的哲学)。

提问时间:建议使用哪一种方式?

-------------------启动自问自答模式----------------------

建议把注解放在属性对应的 get 方法上。
为什么?

----------------------让你思考0.5秒钟------------------

时间到!公布答案。

不管是放在属性上面还是放在 get 方法上面,Hibernate 都要使用反射机制,如果直接反射属性,则是对 OOP 封装特性的挑战。

虽然使用反射可以在底层为所欲为,但作为有良知的开发者来讲,则要从规范上杜绝破坏 OOP 规则的事情。
当然这只是建议!最后的选择由你决定。

3.4 XML 还是注解

这个可没有人能给出最终答案!俗语说得好,即使是低微如一粒尘土,也有自己的价值,XML 映射和注解映射都有自己的应用场景。

注解相对而言集中性较好,在一个类文件中,且符合 Java 语法规范,更易获得开发者喜欢。

4. JPA

考查观察力的时刻,请问 @Entity 注解在哪一个包中?

不是使用 Hibernate 注解吗,还用问,肯定是在 Hibernate 相关联的包中!

恭喜你!答错了。

前面所使用的注解清一色都在 javax.persistence 包中,标准的 Java 包,这个包全称 Java Persistence API(持久化API)。

奇怪了吧?这么厉害,Java 官方在推出 JDK 类库时就为Hibernate 准备了这些注解,不是吧,难不成 Java 语言研发者能预测 Hibernate 将会横空出世,且能成为 “网红”(互联网网络上知名的软件)提前做了拥抱 Hibernate 的准备?

NO,事情的原因是这样子的。

Jdbc 大家都在用,且都感受到其冗余、无脑的操作流程,于是针对优化 Jdbc 操作的框架如雨后春笋(此处使用夸张修饰)。

框架的出现是好事情,但多了,就不一定是好事情,对于开发者来说因业务需求可能需要在不同规范的框架中切过来切过去,开发者的时间都浪费在框架选择上了。

Java 官方要管一管了,于是在 J2EE5.0 后推出了 JPA 注解规范:

  • JPAJava 持久化解决方案,与 Hibernate 一样负责把数据保存进数据库;
  • JPA 只是一种标准、规范,而不是框架;
  • JPA 自身并没有具体的实现,类似于Jdbc规范;
  • 旨在是规范 ORM 框架,使 ORM 框架有统一的接口、统一的用法。

一句话概之,以后不管是开发 Jdbc 框架也好,升级框架也好,请遵循JPA接口规范。

JPA是想当任我行,一统 Jdbc 框架混乱的局面。

对开发者是好事,以 Java JPA 的统一接口方式使用框架。

Hibernate 在 3.x 版本后开始支持JPA规范!!!

老板也不用为开发者切换框架的时间付出报酬了。

5. 小结

本节课了解了元数据概念,并使用注解的方式重构了前面的代码,完成了类似的数据插入操作。

本节课中也探讨了某些注解的使用,更多注解一起期待在后面的课堂内容中再相逢。

最后和大家聊了聊 JPA,一个官方的持久化方案!值得拥有。