ORM思想之源码分析篇:Hibernate的ORM思想分析
1. ORM的经典应用:Hibernate案例
Hibernate 就是应用 ORM 思想建立的一个框架,一般我们把它称之为全自动的 ORM 框架,程序员在使用 Hibernate 时几乎不用编写 sql 语句,而是通过操作对象即可完成对数据库的增删改查。
通过案例让大家对 ORM 思想有一个更深入的了解
1.1 创建 Maven 工程
1.2 编写 pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.4.Final</version>
</dependency>
</dependencies>
1.3 核心配置文件 hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://localhost:3306/test?serverTimezone=UTC</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="hbm2ddl.auto">update</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping class="top.lzchao.orm.entity.Book"/> <!--带有映射注解的实体类-->
<mapping resource="top/lzchao/orm/entity/Book.hbm.xml"/> <!--映射配置文件-->
</session-factory>
</hibernate-configuration>
1.4 实体类 Book.java
/**
* @author: LzCc
* @blog: https://blog.csdn.net/qq_41744145
* @description: Book 实体类
*/
public class Book {
private int id; //主键
private String name; //图书名字
private String author; //图书作者
private double price; //图书价格
// getter、setter...
}
1.5 编写映射信息
配置映射文件:Book.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="top.lzchao.orm.entity.Book" table="t_book">
<id name="id">
<column name="bid"/>
<generator class="identity"/> <!--主键的值采用自增方式-->
</id>
<property name="name">
<column name="bname"/>
</property>
<property name="author">
<column name="author"/>
</property>
<property name="price">
<column name="price"/>
</property>
</class>
</hibernate-mapping>
也可以通过注解方式:
@Entity
@Table(name = "t_book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //数据库自增
@Column(name = "bid")
private Integer id; //主键
@Column(name = "bname")
private String name; //图书名字
@Column(name = "author")
private String author; //图书作者
@Column(name = "price")
private double price; //图书价格
// getter、setter...
}
1.6 测试类
/**
* @author: LzCc
* @blog: https://blog.csdn.net/qq_41744145
* @description: BookTest
*/
public class BookTest {
private SessionFactory factory;
@Before
public void init() {
//1. 创建一个 Configuration 对象,解析 hibernate 的核心配置文件
Configuration cfg = new Configuration().configure();
//2. 创建 SessinFactory 对象,解析映射信息并生成基本的 sql
factory = cfg.buildSessionFactory();
}
@Test
public void testSave() {
//3. 得到 Session 对象,该对象具有增删改查的方法
Session session = factory.openSession();
//4. 开启事务
Transaction tx = session.beginTransaction();
//5. 保存数据
Book book = new Book();
book.setName("Spring5核心原理");
book.setAuthor("TOM");
book.setPrice(89.9);
session.save(book);
//6. 提交事务
tx.commit();
}
@Test
public void testGet() {
//3. 得到 Session 对象,该对象具有增删改查的方法
Session session = factory.openSession();
//4. 通过 Session 对象进行查询
Book book = session.get(Book.class, 1);
System.out.println(book);
//5. 释放资源
session.close();
}
@Test
public void testDelete(){
//3. 得到 Session 对象,该对象具有增删改查的方法
Session session=factory.openSession();
//4. 开启事务管理
Transaction tx=session.beginTransaction();
//5. 删除数据
Book book=new Book();
book.setId(2);
session.delete(book);
//6. 提交事务
tx.commit();;
//7. 释放资源
session.close();
}
}
该测试类使用 Hibernate 的 API 实现了图书的添加,查询和删除功能,程序员无需编写sql 语句,只需要像平时一样操作对象即可,然后由 Hibernate 框架自动生成 sql 语句,如下图所示:
添加:
查询
删除
2. Hibernate 的 ORM 实现原理
接下来我们通过上述案例来讲解一下 Hibernate 框架是如何应用 ORM 思想的,一起剖析一下 Hibernate 的内部实现原理。
其实不管使用什么框架,最终都需要生成 sql 语句,因为数据库需要的就是 sql 语句,而我们在使用 Hibernate 编码时没有编写 sql 语句,只是提供了对象,那么 Hibernate 是如何根据对象生成 sql 语句的呢?接下来我们一起跟踪并分析一下 Hibernate 5.x 的源码。
1. 跟踪第一行代码
//1. 创建一个 Configuration 对象,解析 hibernate 的核心配置文件
Configuration cfg = new Configuration().configure();
1.1 在 new Configuration()时,进行了 hibernate 的环境初始化工作,相关对象和容器被创建了出来,如下图所示:
红框中的两个对象大家要尤为注意,一个是第 158 行的 StandardServiceRegistryBuilder,一个是第 161 行的 Properties 对象,后面的源码中会重点用到这两个对象。
1.2 接下来跟踪调用 configure()方法,如下图所示:
第 244 行的 configure(…)方法会默认加载名字为 hibernate.cfg.xml 的配置文件,然后去解析该配置文件并把解析到的数据存放到一个 Properties 中(第 258 和 261 行代码)。
解析出来的数据如下图所示:
通过上图大家能很清晰得看到,hibernate.cfg.xml 中的信息被解析出来并存到了一个 Properties 中。
1.3 我们再跟踪一下第 258 行的代码,这行代码调用了 StandardServiceRegistryBuilder 对象的 config 方法,如下图所示:
第 165 行从 hibernate.cfg.xml 中解析出来映射配置文件和实体类的信息,并在第 178 行进行了合并汇总,最终存储到了 aggregatedCfgXml 中,如图所示:
总之,第一步 Configuration cfg = new Configuration().configure(); 已经把 hibernate.cfg.xml中的信息全部解析了出来并进行了存储。
2. 跟踪第二行代码
//2. 创建 SessinFactory 对象,解析映射信息并生成基本的 sql
SessionFactory factory = cfg.buildSessionFactory();
由 Configuration 对象的 buildSessionFactory(…)方法创建会话工厂(SessionFactory),该方法的代码非常多,这里只截取了部分关键代码:
* 第 723 行代码从 Properties 中得到配置文件中的数据
* 第 653 行和第 689 行分别创建 MetadataBuilder 对象并调用该对象的 build()方法解析了映射信息,然后存储到 Metadata 对象中,下列截图展示了从映射配置文件或实体类中解析出来的映射数据,包含哪个类和哪个表对应,哪个属性和哪个字段对应:
第 708 行调用 SessionFatctoryBuilder 对象的 build()方法生成 sql 语句并返回 SessionFactory 实例,下面截图展示出了生成的 sql 语句:
会话工厂(SessionFactory)在 Hibernate 中实际上起到了一个缓冲区的作用,它缓存了Hibernate 自动生成的 SQL 语句和相关映射数据,只要生成了 sql 语句,那么后面实现增删改查就不在话下。