Hibernate原理介绍
hibernate是一个开放源代码的对象关系映射框架(ORM),它的作用就是在关系型数据库和对象之间做了一个映射。从对象(Object)映射到关系(Relation),再从关系映射到对象。这样,我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了(把关系数据库的字段在内存中映射成对象的属性)。
hibernate可以应用在任何使用JDBC的场合,既可以在java的客户端程序使用,也可以在Servlet/jsp中的Web应用中使用。最具革命意义的是,hibernate可以在应用的EJB的j2ee架构中取代cmp,完成数据持久化的重任。
运行过程
- 通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件
- 由hibernate.cfg.xml中的
<mapping resource="xxx.hbm.xml"/>
读取并解析映射信息 - 通过config.buildSessionFactory();//创建SessionFactory
- sessionFactory.openSession();//打开Sesssion
- session.beginTransaction();//创建事务Transation
- persistent operate持久化操作 //一般指Save这个方法
- session.getTransaction().commit();//提交事务
- 关闭Session
示例
配置文件
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory >
<!-- 显示实际操作数据库时的SQL -->
<property name="show_sql">true</property>
<!-- 格式化sql语句,排版 -->
<property name="foramt_sql">true</property>
<!-- mysql数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- mysql数据库名称 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/ssh?useSSL=true</property>
<!-- 数据库的登陆用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库的登陆密码 -->
<property name="hibernate.connection.password">admin</property>
<!-- 方言:为每一种数据库提供适配器,方便转换 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 映射文件 -->
<mapping resource="student.hbm.xml"/>
</session-factory>
</hibernate-configuration>
映射文件
student.hbm.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.Student" table="stu">
<id name="id">
<generator class="assigned"></generator>
</id>
<property name="name" type="string"></property>
<property name="score" type="float"></property>
</class>
</hibernate-mapping>
持久化类
Student.java
package hibernate;
public class Student {
private int id;
private String name;
private float score;
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
执行事务
package hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class StoreData {
public static void main(String[] args) {
//creating configuration object
Configuration cfg=new Configuration();
cfg.configure("hibernate.cfg.xml");//populates the data of the configuration file
//creating seession factory object
SessionFactory factory=cfg.buildSessionFactory();
//creating session object
Session session=factory.openSession();
//creating transaction object
Transaction t=session.beginTransaction();
Student e1=new Student();
e1.setId(9);
e1.setName("李四");
e1.setScore(87.5f);
session.save(e1);//persisting the object
t.commit();//transaction is committed
session.close();
factory.close();
System.out.println("successfully saved");
}
}
基于Annotation注解实现数据的CRUD
在数据类里面通过注解的方式来实现和数据库表以及字段的映射,就可以免写具体类的XML配置文件了。
UserInfo.java
package com.hibernate.entity;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
//使用@Entity注解,表示当前类为实体Bean,需要进行持久化
@Entity
// 使用@Table注解实现数据表user_info与持久化类UserInfo之间的映射,catalog指定数据库名,name指定表名
@Table(name = "user_info", catalog = "digital")
public class UserInfo {
private int id;
private String userName;
private String password;
private Date regDate;
// 使用@Id注解指定当前持久化类的ID标识属性
@Id
// 使用@GeneratedValue注解指定主键生成策略为IDENTITY
@GeneratedValue(strategy = GenerationType.IDENTITY)
// 使用@Column注解指定当前属性所对应的数据表中的字段,name指定字段名,
// unique指定是否为唯一,nullable指定是否可为null
@Column(name = "id", unique = true, nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
// 使用@Column注解指定当前属性所对应的数据表的字段,name指定字段名,length指定字段长度
@Column(name = "userName", length = 16)
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Column(name = "password", length = 16)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Column(name = "regDate")
public Date getRegDate() {
return regDate;
}
public void setRegDate(Date regDate) {
this.regDate = regDate;
}
/** 无参构造方法 */
public UserInfo() {
}
/** 全部属性的构造方法 */
public UserInfo(String userName, String password, Date regDate) {
super();
this.userName = userName;
this.password = password;
this.regDate = regDate;
}
@Override
public String toString() {
return "UserInfo [id=" + id + ", userName=" + userName + ", password="
+ password + ", regDate="
+ new SimpleDateFormat("yyyy-MM-dd").format(regDate) + "]";
}
}
采用JUnit进行测试:
package com.hibernate.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.hibernate.entity.UserInfo;
public class HibernateTest {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init() {
// 加载 hibernate.cfg.xml
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure().build();
try {
// 根据 hibernate.cfg.xml 配置 ,初始化 SessionFactory
sessionFactory = new MetadataSources(registry).buildMetadata()
.buildSessionFactory();
// 创建 session
session = sessionFactory.openSession();
// 通过session开始事务
transaction = session.beginTransaction();
} catch (Exception e) {
StandardServiceRegistryBuilder.destroy(registry);
}
}
/**
* 添加数据
*/
@Test
public void testSaveUserInfo() {
// 初始化UserInfo类
UserInfo ui = new UserInfo("hibUser1", "123456", new Date());
// 保存
session.save(ui);
}
/**
* 使用get方法加载数据
*/
@Test
public void testGetUserInfo() {
// 从数据表user_info中加载编号id为1的用户对象
UserInfo ui = (UserInfo) session.get(UserInfo.class, 1);
// 在控制台输出用户对象信息
System.out.println(ui.toString());
}
/**
* 使用load方法加载数据
*/
@Test
public void testLoadUserInfo() {
// 从数据表user_info中加载编号id为1的用户对象
UserInfo ui = (UserInfo) session.load(UserInfo.class, 1);
// 在控制台输出用户对象信息
System.out.println(ui.toString());
}
/**
* 使用delete方法删除数据
*/
@Test
public void testDeleteUserInfo() {
// 从数据表user_info中加载编号id为7的用户对象
UserInfo ui = (UserInfo) session.get(UserInfo.class, 7);
// 删除对象
session.delete(ui);
}
/**
* 使用update方法更新数据
*/
@Test
public void testUpdateUserInfo() {
// 从数据表user_info中加载编号id为3的用户对象
UserInfo ui = (UserInfo) session.get(UserInfo.class, 3);
// 修改数据
ui.setUserName("miaoyong");
// 更新对象
session.update(ui);
}
@After
public void destroy() {
// 提交事务
transaction.commit();
// 关闭session
session.close();
// 关闭sessionFactory
sessionFactory.close();
}
}
hiberbate.cfg.xml
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Hiberante 连接的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">admin</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///digital</property>
<!-- Hiberante 方言 -->
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<!-- 是否打印SQL -->
<property name="show_sql">true</property>
<!-- 关联 Hibernate 的持久化类 -->
<mapping class="com.hibernate.entity.UserInfo"/>
</session-factory>
</hibernate-configuration>
选中一个@test方法,run as JUnit运行前,必须要将hibernate.cfg.xml放到build/classes下,不然程序会提示:could not locate cfg.xml[hibernate.cfg.xml]
,切记!!!
如果最后显示绿条,那么恭喜你,成功了!
PO/VO
Hibernate的对象有三种状态:
- 瞬时态:new出来的对象;持久态对象用了delete方法,同时删除数据库记录。
- 持久态:用save()或者saveOrUpdate()方法,将瞬时态对象变成持久态,放入session缓存中,当session清理缓存时会同步更新到数据库。
- 托管态:session执行
- close
- clear(将所有对象从session的一级缓存中清除)
- evict(将某个对象从session的一级缓存中清除)
方法后,持久态变成托管态,此后对象的变化不再同步变化到数据库。
处于持久态的对象也称为PO(Persistence Object);
瞬时对象和脱管对象也称为VO(Value Object);
Hibernate的缓存
上面说到了clear和evict方法,涉及到了缓存的问题,这里再说明一下。
一级缓存
Hibernate的一级缓存由Session提供,只存在于Session的生命周期中。当调用:
- session接口的save/update/saveOrUpdate/get/load
- Query和Criteria实例的list/iterate
等方法时,如果session里面没有相应对象,hibernate就会把对象加入一级缓存中,下次操作就不直接访问数据库了。当session关闭时,该session所管理的一级缓存也会被立即清除。
二级缓存
Hibernate的二级缓存由SessionFactory负责管理,是进程范围或者集群范围的缓存,其功能是通过配置二级缓存插件来实现的,常用的有:EHCache、OSCache、SwarmCache、JBossCache。使用一般包括以下几步:
- 要下载相应的jar包以
- 使用xml配置文件
- 在Hibernate.cfg.xml中启用
Hibernate优点
- 有HQL语言,可以不去管与数据库有关的底层的SQL语言,可移植性好,可以专注于对象处理上。
- 基本的sql语句已经被封装好,对于简单的增删改查,效率就很快。
Hibernate缺点
由于对持久层封装过于完整,导致开发人员无法对SQL进行优化,无法灵活使用JDBC的原生SQL,Hibernate封装了JDBC,所以没有JDBC直接访问数据库效率高。要使用数据库的特定优化机制的时候,不适合用Hibernate。
框架中使用ORM原则,导致配置过于复杂,一旦遇到大型项目,配置文件和内容是非常庞大的,另外DTO满天飞,性能和维护问题随之而来。
如果项目中各个表中关系复杂,表之间的关系很多,在很多地方把lazy都设置false,会导致数据查询和加载很慢,尤其是级联查询的时候。
Hibernate在批量数据处理时有弱势,对于批量的修改,删除,不适合用Hibernate,这也是ORM框架的弱点。
MyBatis简介
MyBatis也封装了JDBC,但没有Hibernate那么深,通过在配置文件中编写SQL语句,可以根据需求定制SQL语句,数据优化起来比Hibernate容易得多。需要程序员有较好的SQL编写能力,比较适用于大数据系统。
Hibernate优势
- Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
- Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
- Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
- Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
Mybatis优势
- MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
- MyBatis容易掌握,而Hibernate门槛较高。
一句话总结
- Mybatis:小巧、方便、高效、简单、直接、半自动化
- Hibernate:强大、方便、高效、复杂、间接、全自动化
(引用自https://blog.youkuaiyun.com/jiuqiyuliang/article/details/45378065)