Hibernate基础

本文介绍了Hibernate的基础知识,包括其运行过程、配置文件、映射文件、持久化类和事务处理。通过Annotation实现数据的CRUD操作,并讨论了Hibernate的一级和二级缓存机制。此外,还对比了Hibernate与MyBatis的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hibernate原理介绍

hibernate是一个开放源代码的对象关系映射框架(ORM),它的作用就是在关系型数据库和对象之间做了一个映射。从对象(Object)映射到关系(Relation),再从关系映射到对象。这样,我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了(把关系数据库的字段在内存中映射成对象的属性)。
hibernate可以应用在任何使用JDBC的场合,既可以在java的客户端程序使用,也可以在Servlet/jsp中的Web应用中使用。最具革命意义的是,hibernate可以在应用的EJB的j2ee架构中取代cmp,完成数据持久化的重任。

运行过程

  1. 通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件
  2. 由hibernate.cfg.xml中的<mapping resource="xxx.hbm.xml"/>读取并解析映射信息
  3. 通过config.buildSessionFactory();//创建SessionFactory
  4. sessionFactory.openSession();//打开Sesssion
  5. session.beginTransaction();//创建事务Transation
  6. persistent operate持久化操作 //一般指Save这个方法
  7. session.getTransaction().commit();//提交事务
  8. 关闭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。使用一般包括以下几步:

  1. 要下载相应的jar包以
  2. 使用xml配置文件
  3. 在Hibernate.cfg.xml中启用

Hibernate优点

  1. 有HQL语言,可以不去管与数据库有关的底层的SQL语言,可移植性好,可以专注于对象处理上。
  2. 基本的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值