Hibernate不如Mybatis? 一文讲清Hibernate特点和基本使用方法

Hibernate概述

Hibernate框架是当今主流的Java持久层框架之一,是一个开源的ORM(Object Relational Mapping,对象惯性映射)框架,它对JDBC进行了轻量级的对象封装,使得Java开发人员可以使用面向对象的编程思维来操作数据库。 Hibernate

与其他操作数据库的技术相比,Hibernate具有以下几点优势:

  1. Hibernate对JDBC访问数据库的代码做了轻量级封装,大大简化了数据访问层的繁琐的重复性代码,并且减少了内存消耗,加快了运行效率。
  2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现,它很大程度上简化了DAO(Data Access Object)层的编码。
  3. Hibernate性能非常好,映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系。
  4. 可扩展性强。

Mybatis与Hibernate对比:

MybatisMybatis
针对高级查询映射机制手动编写SQL
开发难度开发难度相对较大开发难度相对简单
日志统计有日志统计没有日志统计
数据库扩展性XML关联扩展性、迁移性较差
缓存机制工厂生产配置文件映射中配置

Mytais:小巧、方便、高效、简单、直接、半自动

Hibernate:强大、方便、高效、复杂、绕弯、全自动


Hibernate快速开始

引入依赖

在官网(https://hibernate.org/orm/releases/)有详细说明,注意如果使用JDK1.8则最高只能下载Hibernate5,从Hibernate6开始至少需要JDK11,最新的Hibernate7则是要求JDK17起步,这里使用Hibernate5进行演示。鉴于日常的Java项目几乎都是基于Maven/Gradle开发,展示他们的坐标引入方法。当然如果你的项目没有使用这些框架进行构建,你也可以在官网中下载压缩包进行解压安装,最后手动配置。

  • Gradle:

    dependencies {
    	implementation platform "org.hibernate.orm:hibernate-platform:5.6.15.Final"
    
    // use the versions from the platform
    implementation "org.hibernate.orm:hibernate-core"
    implementation "jakarta.transaction:jakarta.transaction-api"
    }
    
  • Maven:

    <dependencies>
            <!--Hibernate5最后版本,此后Hibernate都不再兼容jdk1.8-->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <version>5.6.15.Final</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.infinispan</groupId>
                <artifactId>infinispan-directory-provider</artifactId>
                <version>9.0.1.Final</version>
            </dependency>
    
            <!--注意这个依赖的版本必须与自己数据库的版本一致-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.28</version>
            </dependency>
    
            <dependency>
                <groupId>jakarta.xml.bind</groupId>
                <artifactId>jakarta.xml.bind-api</artifactId>
                <version>2.3.2</version>
            </dependency>
    
            <dependency>
                <groupId>org.glassfish.jaxb</groupId>
                <artifactId>jaxb-runtime</artifactId>
                <version>2.3.5</version>
            </dependency>
        </dependencies>
    
    

创建实体

在src目录下创建一个包,并且在包中创建一个Customer类进行演示,Customer类包含了cst_customer数据表字段对应的属性,以及get、set方法。

public class Customer{
    private Long cust_id;
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;
    
    //因为篇幅省略get、set方法
}

创建数据库和表

create database hibernate;
user hibernate;
CREATE TABLE 'cst_customer'{
	'cust_id' bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)'
	'cust_name' varchar(32) NOT NULL COMMENT '客户名称'
	'cust_source' varchar(32) DEFAULT NULL COMMENT '客户信息来源'
	'cust_industry' varchar(32) DEFAULT NULL COMMENT '客户所属行业'
	'cust_level' varchar(32) DEFAULT NULL COMMENT '客户级别'
	'cust_phone' varchar(64) DEFAULT NULL COMMENT '固定电话'
	'cust_mobile' varchar(16) DEFAULT NULL COMMENT '移动电话'
	PRIVATE KEY('cust_id')
}ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=UTF8

创建映射文件

实体类Customer目前还不具备持久化操作的能力,而Hibernate需要知道实体类Customer映射到数据库中的哪个表,以及类中的哪个属性对应数据库表中的哪个字段,这些都需要在映射文件中配置。

在实体类Customer所在的包中,创建一个名为Customer.hbm.xml的映射文件。在该文件中定义了实体类和Customer的属性是如何映射到cst_customer表的列上的。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTO 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-mapping-3,0.dtd"
<hibernate-mappping>
	<!-- 建立类和表的一个映射关系-->
	<!-- 
		class标签:用来建立类和表的映射
			* name属性:类中的全路径
			* table属性:表明(如果类名和表名一致,那么table属性可省略)
			* catalog属性:数据库名字,可省略
	-->
	<class name="cn.itcast.domain.Customer" table="cst_customer">
		<!-- 建立类中的属性与表中的主键的映射 -->
		<!-- 
			id标签:用来建立类中的属性和表中字段对应
				* name属性:类中的属性名
				* column属性:表中的字段名(如果类中的属性名和表中的字段名一致,那么column属性可省略)
				* length属性:字段的长度
				* type属性:类型。写Java数据类型,Hibernate数据类型(默认),SQL类型
		-->
		<id name="cust_id" column="cust_id">
			<!-- 主键生成策略 -->
			<generator class="native"/>
  		</id>

		<!-- 建立类中的属性与表中的普通的映射 -->
		<!-- 
			property标签:用来建立类中的属性和表中字段对应
				* name属性:类中的属性名
				* column属性:表中的字段名(如果类中的属性名和表中的字段名一致,那么column属性可省略)
				* length属性:字段的长度
				* type属性:类型。写Java数据类型,Hibernate数据类型(默认),SQL类型
		-->
		<property name="cust_name" column="cust_name"/>
		<property name="cust_source" column="cust_source"/>
		<property name="cust_industry column="cust_property"/>
		<property name="cust_level" column="cust_level"/>
		<property name="cust_phone column="cust_phone"/>
		<property name="cust_mobile" column="cust_mobile"/>
 	</class>
</hibernate-mapping>	

创建核心配置文件

Hibernate的映射文件反应了持久化和数据库的表的映射信息,而Hibernate的配置文件则主要是用来配置数据库连接以及Hibernate运行时所需的各个属性的值。在项目中的src下创建一个名称为hibernate.cfg.xml的文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTO 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-mapping-3,0.dtd"
<hibernate-configuration>
	<session-factory>
  		<property name="hibernate.connection.driver_class"com,mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url"jdbc:mysql://hibernate_day01</property>
  		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">root</property>
		<!-- Hibernate的属性 -->
		<!-- Hibernate的方言:作用,根据配置的方言生成相应的SQL语句-->
  		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<!-- Hibernate显示SQL语句 -->
  		<property name="hibernate.show_sql">true</property>
		<!-- Hibernate格式化SQL语句 -->
		<property name="hibernate.format_sql">true</property>
		<!-- Hibernate加载映射 -->
		<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
	</session-factory>
</hibernate-configuration>

该配置文件设置了数据库连接的相关属性以及其他的一些常用属性,并且通过mapping的resorce属性将对象的映射信息加入到了Hibernate的配置文件中。

编写测试代码

在项目中新建一个test包,然后在包中建立一个名为HibernateDemo1.java文件,该文件是用来测试的。

public class HibernateDemo1{
    @Test
    public void demo1(){
        //1.加载配置文件
        Configuration cfg = new Configuration().configure();
        //2.创建一个SessionFactory
        SessionFactory sessionFactroy = cfg.buildSessionFactory();
        //3.创建Session对象
        Session session = sessionFactory.openSession();
        //4.开启事务
        Transaction tx = session.beginTransaction();
        //5.执行业务逻辑
        Customer customer = new Customer();
        customer.setCust_name("张三");
        customer.setCust_source("网络推广");
        
        session.save(customer);
        //6.事务提交
        tx.commit();
        //7.释放资源
        session.close();
    }
}

Hibernate的常见配置

Hibernate的配置文件,包含了连接持久层的映射文件所需要的基本信息,其配置文件有两种格式,具体如下:

  1. properties类型:properties属性文件格式的配置文件,它使用键值对的形式存放信息,默认文件名称是hibernate.properties。
  2. XML类型:XML配置文件的默认名称为hibernate.cfg.xml。

上述两种格式的配置文件效果想同。**XML配置文件更易修改,配置能力更强。**当改变底层配置时不需要重新编译代码,只需要修改配置文件的对应属性即可,而properties格式的文件则不具备此优势。

Hibernate常用配置属性:

名称用途
hibernate.dialect操作数据库方言
hibernate.connection.driver_class连接数据库驱动程序
hibernate.connection.url连接数据库URL
hibernate.connection.username数据库用户名
hibernate.connection.password数据库密码
hibernate.show_sql在控制台上输出SQL语句
hibernate.format_sql格式化控制台输出的SQL语句
hibernate.connection.autocommit事务是否自动提交

Hibernate常见API

Configuration:配置对象

Configuration类的作用是对Hibernate进行配置,以及对它进行启动。在Hibernate的启动过程中,Configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。虽然Configuration类在整个项目中只扮演一个小角色,但是它是启动Hibernate时遇到的第一个对象。它会加载核心配置文件和映射文件。

Configuration config = new Configuration().configure("核心配置文件位置");
config,addResource("映射配置文件位置");

SessionFactory:Seesion工厂对象

SessionFactory接口负责Hibernate的初始化和建立Session对象。它充当数据存储源的代理,并且负责创建Session对象。这里用到了工厂模式。它在Hibernate中起到一个缓冲区的作用,Hibernate可以将自动生成的SQL语句,映射数据以及某些可重复利用的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存

SessionFactory sessionFactory = config.buildSessionFactory();

SessionFactory具有以下特点:

  1. 线程安全:它的同一个实例能提供多个线程共享。
  2. 重量级:不能随意的创建和销毁它的实例。

由于SessionFactory的这些特点,一般情况下,一个项目只需要一个SessionFactory,只有当应用中存在多个数据源时,才能为每个数据源建立一个SessionFactory实例。因此在实际项目中,我们通常会抽离出一个HibernateUtils工具类,用来提供Session对象。代码具体如下:

public class HibernateUtils{
    private static final Configuration configuration;
    private static final SessionFactory sessionFactory;
    
    static{
        configuration = new Configuration().configure();
       	sessionFactory = configuration.buildSessionFactory();
    }
    //提供获得session的方法
    public static Session openSession(){
        return sessionFactory.opensession();
    }
}

SessionFactory内部还维护着一个连接池,如果我们还需要动刀第三方连接池如C3P0等可以手动配置,但在这儿不过多赘述。

Session:

Session是应用程序与数据库之间交互操作的一个单线程对象,是Hibernate运作的中心,它的主要功能是持久化创建对象提供创建、读取和删除的能力,所有的持久化对象必须在session的管理下才能进行持久化操作。

获取Session实例的方法有两种方式,如下:

//采取openSession方法创建session
Session session = sessionFactory().openSession();
//采取getCurrentSession()方法创建session
Session session = sessionFactory().getCurrentSession();

以上两种获取session实例方式的主要区别是:

  • 采用openSession获取Session实例时,SessionFactory直接创立一个新的Session实例。并且在使用完成后需要调用close方法手动关闭。
  • 而getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或者回滚操作时会自动关闭。

在这里插入代码片Session是线程不安全的。**多个并发线程同时操作一个Session实例时,就可能导致Session数据存取的混乱。因此在设计软件架构时,应避免多个线程共享一个Session实例。它还有一个缓存,即Hibernate的一级缓存

在Session中还提供了大量常用方法,具体如下:

  • save()、update()和saveOrUpdate()方法:用于增加和修改对象。
  • delete()方法:用于删除对象。
  • get()和load()方法:根据主键查询。
  • createQuery()和createSQLQuery()方法:用于数据库操作对象。
  • createCriteria()方法:条件查询。

Transaction:

Transction接口是一个可选的API。Transction接口是对实际事务的一个抽象,主要用于管理事务、它是Hibernate的数据库事务接口,且对底层的事务接口进行了封装。Transaction接口的事务对象是通过Session对象开启的,代码如下:

Transaction transaction = session.beginTransaction(); 

在Transaction接口中,提供了事务管理的实用方法,具体如下:

  • commit()方法:提交相关联的session实例。
  • rollback()方法:撤销事务操作。

Session执行完数据库操作后,要使用Transction接口的commit()方法进行事务提交,才能真正将数据操作同步到数据库中。发生异常时,要使用rollback()方法进行事务回滚,以免数据发生错误。因此在持久化操作后,必须调用这两个方法。如果没有开启事务,那么 每一个Session的操作,都相当于一个独立的操作。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值