关于后端:一文快速入门体验-Hibernate

43次阅读

共计 11912 个字符,预计需要花费 30 分钟才能阅读完成。

前言

Hibernate 是一个优良的长久层的框架,当然,尽管当初说用得比拟多的是 MyBaits,然而我工作中也不得不接触 Hibernate,特地是一些老我的项目须要你保护的时候。所以,在此写下这篇文章,不便本人回顾,也不便新手入门体验 Hibernate。

注:应用的版本是 Hibernate 5.x 的

什么是 ORM?

ORM(Object Relational Mapping,对象关系映射)能够说是一种实践,或者说是一种设计思维,次要是让「关系型数据库」和「面向对象编程语言」之间建设映射关系。目标是将数据库中的数据转换为对象,以便开发人员更不便地进行数据库操作。

那为什么会呈现 ORM 呢?

在咱们学习 JDBC 的时候,咱们须要编写大量的 SQL 语句来执行数据库的 CRUD 操作,而且还须要手动将查问后果转换为对象。这样的操作是比拟繁琐的,还容易出错,而且对于大型项目来说,数据库操作的代码量通常很大,保护起来也是十分艰难的。所以,ORM 呈现了,帮忙咱们简化数据库操作,进步开发效率。

市面上有很多不同的 ORM 框架可供选择,在 Java 后端开发的学习路线上,咱们须要晓得的就有 Hibernate 和 MyBatis。

简略来说,ORM 就是将数据库操作封装成对象操作,通过对象的形式来进行数据库的增删改查。

了解 JPA 和 ORM 的关系

JPA(Java Persistence API)是 Java EE(当初称为 Jakarta EE)标准中定义的一套 API,用于实现对象和关系数据库之间的映射。JPA 提供了一种规范的形式来进行对象长久化操作。而 ORM 是一个通用的概念,不局限于特定的编程语言或框架。比方 Python 也有对应的实现 ORM 的框架。

换句话说,JPA 它定义了一系列的接口和注解,开发者能够应用这些接口和注解来形容对象和数据库表之间的映射关系,并进行数据库操作。而 ORM 是一个更宽泛的概念,它能够实用于其余编程语言和框架,并不局限于 Java 和 JPA。

注:JPA 就只定义,没有具体实现,就是所谓的标准、规范,我 JPA 规定了这些 API 能进行相干操作,具体的实现是交给软件厂商去实现的,比方 Hibernate 就是 JPA 规范的一种实现。

了解 JPA 和 Hibernate 的关系

Hibernate 是 JPA 的一种具体实现,它应用了 JPA 标准定义的接口和注解,提供了 ORM 性能。

从工夫线上来看:JPA(Java Persistence API)是在 Hibernate 之后呈现的。

最早由 Gavin King 在 2001 年创立 Hibernate,指标是简化开发人员进行数据库的操作,以面向对象的形式去操作数据库。

JPA 的第一个版本是在 2006 年公布的,其中蕴含了一系列的接口和注解,用于形容对象和数据库表之间的映射关系,以及进行数据库操作。Hibernate 的创始人 Gavin King 是 JPA 标准的次要参与者之一。

JPA 标准的呈现是为了标准化 ORM 框架的行为和性能,使开发人员能够在不同的 ORM 实现之间进行切换,而不须要批改大量的代码。

总结来说,Hibernate 是在 JPA 标准之前呈现的 ORM 框架,而 JPA 是在 Hibernate 的根底上产生的一套标准化的 ORM API。Hibernate 作为 JPA 的一种实现,为开发人员提供了弱小的 ORM 性能,并成为了 JPA 标准的次要影响者之一。

正题:Hibernate 简介

Hibernate 是全自动的对象关系映射的长久层框架,次要通过长久化类(.Java,当然,也习惯说的实体类)、映射文件(.hbm.xml)和配置文件(.cfg.xml)来操作关系型数据库。

Hibernate 封装了数据库的拜访细节,通过配置的属性文件,来关联上关系型数据库和实体类的。

Hibernate 中有 3 个咱们须要晓得的类,别离是配置类(Configuration)、会话工厂类(SessionFactory)和会话类(Session),留神,此处的 Session 可不是 HttpSession 啊!

  • 配置类

次要负责管理 Hibernate 的配置信息以及 Hibernate 的启动,在运行的时候,配置类会读取一些底层的根本信息,比方数据库的 URL、数据库的用户名、明码、驱动类、方言(适配器,Dialect)等信息。

  • 会话工厂类

次要负责生成 Session,这个工厂类会保留以后数据库中所有的映射关系。

  • 会话类

长久化操作的外围,通过它实现 CRUD,它不是线程平安的,须要留神不要多个线程共享一个 Session 对象。

了解会话二字:顾名思义,实际上就是交换,通信。在网络中,一次会话能够是一次 HTTP 申请到 HTTP 响应的过程,在数据库操作中,一次会话,能够是一次新增操作的申请到数据库中,而后数据库做出响应。

应用 Maven 构建 Hibernate 我的项目

最原始引入 Jar 包的形式来创立 Hibernate 我的项目,能够参考这里:

http://m.biancheng.net/hibernate/first-example.html

因为我比拟懒,所以应用 Maven 来构建一个具备 Hibernate 的 Web 我的项目。

引入依赖项

别离引入 Hibernate、MySQL 数据库驱动、单元测试 Junit4(创立 Maven 时自带的)。

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.6.14.Final</version>
</dependency>

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

Hibernate 配置文件

在 resource 目录下创立一个 hibernate.cfg.xml 配置文件:

<?xml version="1.0" encoding="UTF-8"?>
        <!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>
        <!-- 配置数据源、连接池等相干信息 -->
        <property name="connection.url">jdbc:mysql://localhost:3306/demo_hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- Hibernate 方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 打印 SQL 语句 -->
        <property name="show_sql">true</property>
        <!-- 格式化 SQL 语句 -->
        <property name="format_sql">true</property>
        <!-- 映射文件所在位置 -->
        <mapping resource="cn/god23bin/demo/domain/mapping/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>

以上的配置只是一小部分,还能够配置数据库连接池、是否主动生成数据库表等等。

长久化类(实体类)

咱们是通过长久化类来操作数据库表的,也就是 ORM 的体现,即对象映射到数据库表,数据库表也映射对象,操作对象就相当于操作数据库表。所以咱们须要编写长久化类来形容数据库表,类中的属性须要与数据库表中的字段相匹配。

创立一个 User 类,作为一个 JavaBean(只有 getter 和 setter 办法,没有其余业务办法的对象)

package cn.god23bin.demo.domain.entity;

/**
 * @author god23bin
 */
public class User {
    private Integer id;
    private String name;
    private String password;

    // 省略 getter 和 setter 办法
}

这品种(JavaBean)在日常开发中是无处不在的,百分之百会用到,也称它为 POJO(Plain Old Java Object),咱们晓得这种概念就行,反正这品种就只有属性和对应的 getter 和 setter 办法。

须要留神的几点:

  • 必须有无参构造方法,便于 Hibernate 通过 Constructor.newInstance() 实例化长久类。
  • 提供一个标识属性,个别这个标识属性映射的是数据库表中的主键字段,就下面 User 中的 id 属性。
  • 设计实体类,属性都是申明为 private 的。

Hibernate 映射

咱们独自写了一个长久化类,目前是还没有做映射的,也就是说还不能通过这个类去操作数据库,那如何去做映射呢?

这就波及到一个映射文件了,映射文件是 xml 文件,命名规定个别是 长久化类名.hbm.xml,以 User 为例,它的映射文件就是 User.hbm.xml

咱们能够在我的项目某个包下创立映射文件,我抉择在 cn.god23bin.demo.domain.mapping 包下创立:

<?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>
    <!-- name 属性:长久化类的全门路 -->
    <!-- table 属性:表的名称 -->
    <class name="cn.god23bin.demo.domain.entity.User" table="user">
        <!-- 主键 -->
        <id name="id" column="id" type="java.lang.Integer">
            <!-- 主键生成策略 -->
            <generator class="native"/>
        </id>
        <!-- type 属性 的三种写法 -->
        <!-- 1. Java 类型 :java.lang.String -->
        <!-- 2. Hibernate 类型:string -->
        <!-- 3. SQL 类型 : 不能间接应用 type 属性, 须要子标签 <column> -->
        <!--    <column name="name" sql-type="varchar(20)"/> -->
        <property name="name" column="name" type="string" not-null="true" length="50"/>
        <property name="password" column="password" not-null="true" length="50"/>
    </class>
</hibernate-mapping>

留神:映射文件的编写须要依照长久化类来编写,而不是数据库表。

cn.god23bin.demo.domain.entity.User 称为全门路 | 全限定类名 | 全限定名 | 全包名,反正我是见过多种叫法的,指的都是同个货色。

如果映射文件中没有配置 column 和 type 属性,那么 Hibernate 会默认应用长久化类中的属性名和属性类型去匹配数据库表中的字段。

创立完这个映射文件后,咱们须要在配置文件中 <session-factory> 里指定该映射文件所在的地位,这样 Hibernate 才晓得映射文件在哪里。

<mapping resource="cn/god23bin/demo/domain/mapping/User.hbm.xml" />

残缺的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
        <!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>
        <property name="connection.url">jdbc:mysql://localhost:3306/demo_hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <!-- 映射文件所在位置 -->
        <mapping resource="cn/god23bin/demo/domain/mapping/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>

配置 pom.xml

因为我是 Maven 来构建我的项目的,所以须要新增一个配置,便于让 Hibernate 可能找到 Maven 工程编译后的 *.hbm.xml 映射文件。

在 pom.xml 中,找到 build 标签,在外面加上如下的配置:

<build>
    ...
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
    </resources>
</build>

Hibernate 工具类

Hibernate 有 3 个须要晓得的类,不晓得当初你还记不记得,不记得就翻到下面简介那里看看。

其中,Session 是长久化操作的外围类,通过它能够实现 CRUD 操作。那么如何获取 Session 对象呢?不言而喻,就是通过 Session 工厂,即 SessionFactory 对象,来获取 Session 对象,那问题又来了,Session 工厂如何获取?

这里就得说到 Configuration 配置类了,通过它创立 SessionFactory 对象,进而获取 Session 对象。

外围代码是这样的:

// 读取 hibernate.cfg.xml 配置文件并创立 SessionFactory
Configuration configure = new Configuration().configure(); // 加载配置文件,configure() 办法能够指定配置文件所在位置,没有指定的话,默认为我的项目的 classpath 根目录下的 hibernate.cfg.xml
SessionFactory sessionFactory = configure.buildSessionFactory();  // 创立 SessionFactory 对象

个别状况下,咱们会写一个工具类来获取 Session 对象,如下:

package cn.god23bin.demo.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * @author god23bin
 */
public class HibernateUtil {

    /**
     * 一个 ThreadLocal 变量,用于存储线程局部变量 Session。* ThreadLocal 提供了线程局部变量的机制,保障每个线程都有本人的 Session 实例。*/
    private static final ThreadLocal<Session> THREAD_LOCAL = new ThreadLocal<>();

    private static SessionFactory sessionFactory;

    static {
        try{
            // 读取 hibernate.cfg.xml 配置文件并创立 SessionFactory
            Configuration configure = new Configuration().configure();
            sessionFactory = configure.buildSessionFactory();} catch (Exception e) {System.err.println("Hibernate 创立会话工厂失败!");
            e.printStackTrace();}
    }

    /**
     * 获取 Session 对象
     */
    public static Session getSession() {Session session = THREAD_LOCAL.get();
        if (session == null || session.isOpen()) {if (sessionFactory == null) {rebuildSessionFactory();
            }
            session = (sessionFactory != null) ? sessionFactory.openSession() : null;
            THREAD_LOCAL.set(session);
        }
        return session;
    }

    /**
     * 从新创立会话工厂
     */
    private static void rebuildSessionFactory() {
        try{
            // 读取 hibernate.cfg.xml 配置文件并创立 SessionFactory
            Configuration configure = new Configuration().configure();
            sessionFactory = configure.buildSessionFactory();} catch (Exception e) {System.err.println("Hibernate 创立会话工厂失败!");
            e.printStackTrace();}
    }

    /**
     * 返回惟一的会话工厂对象
     */
    public static SessionFactory getSessionFactory() {return sessionFactory;}

    /**
     * 敞开 Session 对象
     */
    public static void closeSession() {Session session = THREAD_LOCAL.get();
        THREAD_LOCAL.remove();
        if (session != null) {session.close();
        }
    }

}

测试

创立一张 user 表:

CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(50) NOT NULL COMMENT '名称',
  `password` varchar(50) NOT NULL COMMENT '明码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

编写一个测试类,因为我这里是 Maven 我的项目,依照约定,测试类放在 /src/test/java/ 目录下,我这里就把这个测试类 HibernateTest 放在 java 目录下的 cn.god23bin.demo 包中:

package cn.god23bin.demo;

import cn.god23bin.demo.domain.entity.User;
import cn.god23bin.demo.util.HibernateUtil;
import org.hibernate.Session;
import org.junit.Test;

/**
 * @author god23bin
 */
public class HibernateTest {

    @Test
    public void test() {
        // 获取 Session 对象
        Session session = HibernateUtil.getSession();
        User user = new User();
        user.setName("god23bin");
        user.setPassword("123456");
        try {
            // 开启事务,即便是执行一次数据库操作,也是事务
            session.beginTransaction();
            // 执行插入操作
            session.save(user);
            // 提交事务
            session.getTransaction().commit();
        } catch (Exception e) {
            // 产生异样,则回滚事务
            session.getTransaction().rollback();
            System.out.println("插入 User 数据失败!");
            e.printStackTrace();} finally{
            // 敞开 Session 对象
            HibernateUtil.closeSession();}
    }
}

控制台输入:

五月 07, 2023 11:52:13 下午 org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 5.6.14.Final
五月 07, 2023 11:52:15 下午 org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
五月 07, 2023 11:52:17 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
五月 07, 2023 11:52:17 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/demo_hibernate]
五月 07, 2023 11:52:17 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=root, password=****}
五月 07, 2023 11:52:17 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
五月 07, 2023 11:52:17 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
Sun May 07 23:52:17 CST 2023 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
五月 07, 2023 11:52:18 下午 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
五月 07, 2023 11:52:20 下午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: 
    insert 
    into
        user
        (name, password) 
    values
        (?, ?)

Process finished with exit code 0

咱们能够查看数据库中 User 表中是否存在咱们刚刚插入的数据,能够发现是存在的:

总结

咱们顺次阐明了什么是 ORM,并且梳理了 JPA 和 ORM 的关系以及 JPA 和 Hibernate 的关系。

我置信还是有很多人没有搞清楚它们之间的分割的,就只是学了而已,或者说学过而已,当然,也有的人说,晓得了它们的关系又能怎么呢?我不晓得我也能用 Hibernate 去操作数据库。话虽如此,然而我认为明确它们之间的分割,是有利于咱们后续其余常识的学习的,也能跟其余常识建设起分割,而不是独自的一个常识孤岛。

接着介绍了 Hibernate,以及如何应用 Maven 我的项目去构建一个具备 Hibernate 的 Web 利用,毕竟咱们开发,根本都是 Web 应用程序。

应用 Maven 去构建,就须要引入相干的依赖,Hibernate 的外围依赖以及数据库驱动的依赖,接着须要编写配置文件、长久化类、长久化类的映射文件,最初写一个获取 Session 对象的工具类,便于咱们获取 Session 对象执行数据库操作。

以上,就是本篇文章的内容,当初祝贺你曾经入门 Hibernate 了!是不是很快上手了!哈哈哈

最初的最初

心愿各位屏幕前的 靓仔靓女们 给个三连!你轻轻地点了个赞,那将在我的心里世界削减一颗亮堂而夺目的星!

咱们下期再见!

正文完
 0