使用Hibernate进行对象数据持久化储存

1、简介

ORM(Object Relationship Mapping,对象关系映射)是通过使用描述对象和数据库之间映射的元数据,将对象持久化存储到关系数据库中。不同数据库的SQL语法不同,相同的功能在不同的数据库中有不同的实现方式,而且如果直接在应用中编写底层数据库相关的SQL语句会使程序过分依赖特定数据库,不利于程序的移植与扩展,因此需要ORM框架实现面向对象与数据存储的分离。

Hibernate是Java领域在对JDBC进行轻量级封装的开源ORM框架。如下图所示,hibernate作为持久化层,将业务逻辑层生成的数据对象持久化地储存在数据库中

Hibernate执行过程如下,首先读取数据库配置文件hibernate.cfg.xml生成Configuration对象,之后读取对象的映射文件Entity.hbm.xml生成工厂对象,最后创建Session对象来进行数据库具体操作。Session类似于JDBC的Connection,通过session来进行数据库的增删改查操作,不同的是一个connection可以提供多个session对象。在进行具体操作时,必须以事务Transaction的方式来执行,而hibernate默认不会自动提交事务,所以在session操作完成之后需要手动提交事务才能保存数据库的操作。

可以通过sessionFactory.getCurrentSession()或者openSession()两种方法获取session对象,第一种会自动结束session,但是需要在cfg.xml文件中配置<property name="current_session_context_class">thread</property>。第二种不需要其他配置,但是需要手动结束session,否则每次SessionFactory都会分配一个新的session对象,造成溢出。

2、创建一个Hibernate应用

1、首先需要导入jar包:除了引入hibernate所需的jar包外,还需要引入jdbc的jar包

2、创建配置文件:在src/hibernate.cfg.xml中配置数据库的url、驱动、对应的映射实体、用户名、密码和其他数据库的配置。

3、创建对应的实体类,例如为student表在mypackage目录下创建StudentEntity类,该类要满足JavaBean要求(类公有,属性私有并有对应的get/set方法)

4、创建表和类的映射,创建Students.hbm.xml文件来描述对应的映射关系,也可以在StudentEntity类中通过注解来声明映射关系

5、通过Junit来测试映射对象插入数据库

以上为手动创建过程,在IDEA中通过Hibernate逆向工程可以十分方便的创建一个Hibernate应用并自动生成hibernate.cfg.xml、Students.hbm.xml、StudentEntity.java文件:

项目根目录右击,选择new->Module弹出如下,选择Hibernate框架,然后勾选创建默认配置文件和引入数据库,并且第一次需要下载hibernate依赖包(或者也可以使用Use library来指定本地),之后弹出界面选择文件名和保存位置,完成工程创建。

之后弹出界面配置数据库与对应的映射。也可以在IDEA的View->Tool Windows->Persistence调出Hibernate窗口在界面的左下角,然后右击当前的HibernateXML项目,选择Generate Persistence Mapping生成映射界面

以XML配置映射

Choose Data Source选择要映射的数据库,Package选择生成的Java对象类保存的包名,Entity prefix/suffix设置对象类名前后缀,例如这里生成的是entity包下的StudentEntity类。Database Schema Mapping选择要映射的数据库中的表名,最后选择Generate Separate XML per Entity以XML文件的方式来为每张表生成映射关系文件。

之后自动生成了hibernate.cfg.xml文件如下。通过<property>标签对数据库进行设置,其中url为数据库的地址,driver_class为数据库的驱动,dialect为数据库的方言,设置方言可以针对不同数据库进行优化,username、password分别为数据库的用户名和密码。show_sql、format_sql设置格式化输出数据库操作语句。hbm2ddl.auto设置操作数据库的方式,update代表更新数据表,create会新建一个表,如果原来存在则先删除之后再新建。<mapping>标签指定数据表和对象的映射文件。

<?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</property>
        <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="connection.username">root</property>
        <property name="connection.password">password</property>
        <property name="current_session_context_class">thread</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <mapping resource="StudentEntity.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

随之生成的StudentEntity.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="entity.StudentEntity" table="student" schema="test">
        <id name="id" column="id"/>
        <property name="name" column="Name"/>
        <property name="age" column="Age"/>
    </class>
</hibernate-mapping>

并且Hibernate的反向工程会在entity文件夹下自动生成Java的StudentEntity类 ,包含字段对应的变量及其get/set方法以及equals与hashCode方法,注意如果其中没有默认无参构造方法,则需要手动添加,否则之后执行会报错

package entity;

import java.util.Objects;

public class StudentEntity {
    private int id;
    private String name;
    private Integer age;

    public StudentEntity() {    //手动添加无参构造方法
    }

    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;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        StudentEntity that = (StudentEntity) o;
        return id == that.id &&
                Objects.equals(name, that.name) &&
                Objects.equals(age, that.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}

以注解方式表示映射

除了使用.hbm.xml文件之外,也可以通过注解的方式来表示Java类和数据表之间的映射关系,在import database schema的步骤中选择Generate JPA Annotations

随之生成了StudentEntity类文件如下,可见不仅生成了字段对应的变量与get/set方法,而且为类和方法添加了注解表明映射关系

@Entity
@Table(name = "student", schema = "test", catalog = "")
public class StudentEntity {
    private int id;
    private String name;
    private Integer age;

    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Basic
    @Column(name = "Name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Basic
    @Column(name = "Age")
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        StudentEntity that = (StudentEntity) o;
        return id == that.id &&
                Objects.equals(name, that.name) &&
                Objects.equals(age, that.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}

3、使用Hibernate

这样就生成了一个简单的hibernate架构,我们通过JUnit对生成的Student映射进行测试,在StudentEntity.class文件内点击alt+insert,选择generate Test,生成类的测试方法,选择自动生成setUp与tearDown方法,用于在测试之前和之后执行的操作

如下所示为生成的StudentEntityTest文件,在setUp中创建hibernate服务并开启事务,在tearDown中关闭资源。在@test注解中创建一个方法用于测试,创建一个对象并保存到数据库的对应的student表中。之后查看数据库,发现插入了学生“赵六”的数据。

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.junit.jupiter.api.Test;

class StudentEntityTest {
    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @org.junit.jupiter.api.BeforeEach
    void setUp() {
        //创建服务注册对象
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
        //创建会话工厂对象
        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
        //会话对象
        session = sessionFactory.openSession();
        //开启事物
        transaction = session.beginTransaction();
    }

    @org.junit.jupiter.api.AfterEach
    void tearDown() {
        //提交事物
        transaction.commit();
        //关闭会话
        session.close();
        //关闭会话工厂
        sessionFactory.close();
    }

    @Test
    void testStudent(){
        StudentEntity student = new StudentEntity();        //创建一个对象
        student.setId(1007);
        student.setName("赵六");
        student.setAge(12);
        session.save(student);        //将对象保存到数据库中对应的表
    }
}

CRUD操作

hibernate的增删改查通过session的save()、delete()、update()、get()/load()方法来实现,其中get()会在调用后立即查询并返回一个对象,load()只保存对象id,当之后用到对象其他属性时才会执行查询。而且在查询不到对象信息时,get()返回null,而load()会抛出一个hibernate.ObjectNotFoundException,例如测试文件如下

@Test
    void testStudent(){
        StudentEntity student = new StudentEntity();
        student.setId(1007);
        student.setName("赵六");
        student.setAge(12);
        session.save(student);              //向数据库中持久化保存对象
        StudentEntity s2=session.get(StudentEntity.class,1007);     //通过主键id取出对象
        System.out.println(s2.getName());
        s2.setAge(22);
        session.update(s2);             //修改对象
        session.delete(s2);             //删除对象
    }

组件属性

有时需要将一张表的多个属性组合成一个对象作为映射,而不是直接映射。例如students表有city和street两个字段,需要首相将其映射为一个Address对象,然后再作为Student的一个属性,这就是组件。

首先声明一个Adress类

public class Address {
    private String city;
    private String street;

    public Address() {
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }
}

接着修改Student类,添加address属性并设置对应的get/set方法

public class StudentEntity {
    private int id;
    private String name;
    private Integer age;
    private Address address;        //添加address对象属性

    ......

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

接着修改student.hbm.xml映射文件,增加address组件

    <class name="entity.StudentEntity" table="students" schema="test">
        <id name="id" column="id"/>
        <property name="name" column="Name"/>
        <property name="age" column="Age"/>
        <component name="address" class="entity.Address">
            <property name="city" column="city"/>
            <property name="street" column="street"/>
        </component>
    </class>

 接下来在测试方法中首先获取id为1006的学生,然后为其添加address对象属性后保存

    void testStudent(){
        StudentEntity s2=session.get(StudentEntity.class,1006);     //通过主键id取出对象
        Address address=new Address();
        address.setCity("北京");
        address.setStreet("新直门");
        s2.setAddress(address);            //为学生添加address对象
        session.save(s2);
    }

查看数据库结果如下,可见已经保存了address对应的city和street字段

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值