Hibernate入门及知识点使用

Hibernate的介绍及使用

一、什么是hibernate

  • hibernate是一个轻量级javaEE持久层框架,是一个ORM框架(对象关系映射,所以这类框架都有个对象关系映射文件xxx.hbm.xml)
    在web项目中对数据库的操作流程是–application–>hibernate–>database,hibernate在里面就是连接请求与数据库的桥梁,核心配置文件xxx.hbm.xml用于连接application,hibernate.cfg.xml用于连接database
  • ORM 表示 Object-Relational Mapping (ORM)
    O:object:对象
    R:Relational:关系
    M:mapping:映射

二、hibernate的属性

a、configuration

  • 读取hibernate.cfg.xml
  • 管理对象关系映射文件xxx.hbm.xml
  • 加载hibernate的配置信息 创建对象Configuration config=new Configuration().configure();

b、SessionFactory

  • 缓存sql语句,数据(一级缓存,session级缓存)
  • 在应用程序初始化的时候创建,重量级类,一个数据库只要有一个就可以了(为什么叫重量级的类呢,因为sessionFactory管理着连接数据库的会话,网站运行时连接时很重要的,而且存储了大量sql语句或数据,占用了大量内存)
  • SessionFactory负责创建Session实例,可以通过Configuration实例构建SessionFactory
    sessionFactory= new Configuration().configure().buildSessionFactory();

Session作用

  • Session时hibernate数据持久化的基础,可以看作持久化管理工具,提供了很多持久化方法 ,通过这些方法,完成curd操作(save/delete/get/load/update)
  • 通常一个数据库事物和一个Session事例绑定,每执行一个事物都要创建一个Session,使用后需要手动关闭
  • Session时线程不同步的(不安全),所以要保证在同一线程中使用,可以 用getCurrentSession
  • Session实例由SessionFactory构建–Session session=sessionFactory.openSession();)

c、openSession和getCurrentSession区别

  • openSession是一个全新的Session getCurrentSession时获取一个和事务绑定的Session
  • getCurrentSession在commit后自动关闭,openSession不会 getCurrentSession在hibernatecfg.xml还要配置

三、hibernate的全局配置文件

在这里插入图片描述

  • 配置方言
<property
name="hibernate.dialect">org.hibernate.dialect.MySQL5Diale
ct</property>

在这里插入图片描述

四、hibernate的简单案例编写

  • 编写一个员工实体类
package com.cn.lin;

import java.util.Date;

/**
 * @Author Lin_Home
 * @Date 2020/10/10 18:31
 * @Version 1.0
 */
public class Employee {
    private Integer id;
    private String name;
    private String email;
    private Date hiredate;

    public Employee() {
    }

    public Employee(Integer id, String name, String email, Date hiredate) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.hiredate = hiredate;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", hiredate=" + hiredate +
                '}';
    }
}

  • 编写一个工具类
package com.cn.lin;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * @Author Lin_Home
 * @Date 2020/10/10 18:56
 * @Version 1.0
 */
public class HibernateUtils {
    //编写hibernate的工具类
    private static SessionFactory sessionFactory;

    static {
        //创建配置对象
        Configuration configuration = new Configuration().configure();
        //建立sessionFactory对象
        sessionFactory = configuration.buildSessionFactory();
    }

    public static Session openSession(){
        //建立会话
        return sessionFactory.openSession();
    }



}
  • 编写一个测试类
package com.cn.lin;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import org.junit.jupiter.api.Test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @Author Lin_Home
 * @Date 2020/10/10 18:38
 * @Version 1.0
 */
public class MainTest {
    /**
     * 实现添加数据
     * */
    public static void main(String[] args) {
        //创建配置对象,他会读取hibernate.cfg.xml文件
        Configuration configuration = new Configuration().configure();
        //创建一个会话 SessionFactory对象
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //连接会话
        Session session =sessionFactory.openSession();
        //开启事务
        Transaction transaction = session.beginTransaction();
        Employee employee = new Employee();
        employee.setEmail("1415318251@qq.com");
        employee.setName("Yee");
        long timeMillis = System.currentTimeMillis();
        Date date = new Date(timeMillis);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        simpleDateFormat.format(date);

        employee.setHiredate(date);
        session.save(employee);
        transaction.commit();
        //关闭会话
        session.close();
    }


    //删除
    @Test
    public void deleteByIdTest() {
        Session session = HibernateUtils.openSession();
        // 4.开启事务
        Transaction transaction = session.beginTransaction();
        // 5.执行持久化操作
        Employee user = session.get(Employee.class, 1);
        session.delete(user);
        // 6.提交事务
        transaction.commit();
        // 7.关闭资源
        session.close();
    }

    //修改
    @Test
    public void UpdateTest(){
        Session session = HibernateUtils.openSession();
        //开启事务
        Transaction transaction = session.beginTransaction();
        Employee employee = new Employee();
        employee.setId(2);
        employee.setEmail("141551@qq.com");
        employee.setName("Woo");
        long timeMillis = System.currentTimeMillis();
        Date date = new Date(timeMillis);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        simpleDateFormat.format(date);

        employee.setHiredate(date);
        session.update(employee);
        transaction.commit();
        //关闭会话
        session.close();
    }

    /**
     * 单查询根据id
     * */
    @Test
    public void QueryById(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        Employee user = session.get(Employee.class, 2);
        System.out.println(user);
        transaction.commit();
        session.close();
    }

    //全查询 from 对应的是实体类命名
    @Test
    public void QueryTest(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        Query query = session.createQuery("from Employee ");
        //2、使用Query对象的list方法得到数据集合
        List<Employee> list = query.list();
        for(Employee employee:list){
            System.out.println(employee.getId()+" "+ employee.getName()+" "+employee.getEmail()+" "+employee.getHiredate());
        }
        transaction.commit();
        session.close();
    }

    //条件查询
    @Test
    public void QueryByCondition(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        Query query = session.createQuery("from Employee where name = :name");
        query.setParameter("name","Yee");
        //2、使用Query对象的list方法得到数据集合
        List<Employee> list = query.list();
        for(Employee employee:list){
            System.out.println(employee.getId()+" "+ employee.getName()+" "+employee.getEmail()+" "+employee.getHiredate());
        }
        transaction.commit();
        session.close();
    }
}

  • 实体类的配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


<hibernate-mapping package="com.cn.lin">
    <class name="com.cn.lin.Employee" table="employee">
        <id name="id">
            <!--            数据库的主键交给数据库本地管理-->
            <generator class="native"></generator>

<!--            主键实现自增长-->
<!--            <generator class="identity"></generator>-->

<!--            自增主键,由Hibernate维护,插入数据前,先从数据库中读取主键最大值+1作为本次主键-->
<!--            <generator class="increment"></generator>-->

<!--            使用的是String 类型,并且是32位的,自动生成id-->
<!--            <generator class="uuid"></generator>-->

<!--            Oracle数据库中主键生成策略-->
<!--            <generator class="sequence"></generator>-->
        </id>

        <property name="name" column="name"/>
        <property name="email" column="email"></property>
        <property name="hiredate" column="hiredate"></property>
    </class>


</hibernate-mapping>
  • hibernate的生成文件配置
<?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/hello</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.username">账号</property>
    <property name="connection.password">密码</property>
    <!--  导入配置文件的路径  -->
    <mapping resource="Employee.hbm.xml"></mapping>
  </session-factory>

</hibernate-configuration>

五、Hibernate的主键生成策略

  • 开发中尽量使用代理主键,这样可以在主键发生变化的时候不用修改源代码,也满足OCP原则。
  • ocp原则介绍:https://blog.csdn.net/benbenxiongyuan/article/details/24021039
    在这里插入图片描述

a、increment

  • hibernate中提供的自动增长机制,适用于short、int、long类型的主键。仅单线程程序中使用。原理:首先发送一条语句:select MAX(id) from 表;然后将id+1作为下一条记录的主键。

b、identity

  • 使用数据库底层的自动增长机制,适用于short、long、int。适用于有自动增长机制的数据库(MySQL、MSSQL)。 注意:Oracle是没有自动增长的。

c、 sequence

  • 采用序列机制,适用于short、int、long。适用于序列机制的数据库(Oracle)

d、uuid

  • uuid 适用于字符串类型主键。使用hibernate中随机方式生成字符串主键。 它会生成唯一的32位的16进制的字符串

e、native

  • 本地策略。可以在identity和sequence间进行自动切换。

f、assigned

  • hibernate放弃外键管理。需要通过手动编写程序或用户自己设置。

g、foreign

  • 外部的。会在一对一的关联映射下使用。

六、hibernate一对多关系用法

在这里插入图片描述

-- 客户表
CREATE TABLE t_customer(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
gender CHAR(1)
);
-- 订单表
CREATE TABLE t_order(
id INT PRIMARY KEY AUTO_INCREMENT,
orderno VARCHAR(20),
product_name VARCHAR(20),
cust_id INT,
CONSTRAINT order_customer_fk FOREIGN KEY(cust_id) REFERENCES
t_customer(id)
);
  • 编写一的实体类
package com.lin.cn;

import java.util.Set;

/**
 * @Author Lin_Home
 * @Date 2020/10/11 14:38
 * @Version 1.0
 */
public class Customer {
    //id
    private Integer id;
    //用户名
    private String name;
    //性别
    private String gender;
    //客户对应的多个订单号

    private Set<Order> order;

    public Customer() {
    }

    public Customer(Integer id, String name, String gender, Set<Order> order) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.order = order;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Set<Order> getOrder() {
        return order;
    }

    public void setOrder(Set<Order> order) {
        this.order = order;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", order=" + order +
                '}';
    }
}

  • 编写多的实体类
package com.lin.cn;

/**
 * @Author Lin_Home
 * @Date 2020/10/11 14:41
 * @Version 1.0
 */
public class Order {
    //订单id
    private Integer id;
    //订单编号
    private String orderno;
    //产品名
    private String productName;
    //体现一个订单所属一个客户(one)
    private Customer customer;

    public Order() {
    }

    public Order(Integer id, String orderno, String productName, Customer customer) {
        this.id = id;
        this.orderno = orderno;
        this.productName = productName;
        this.customer = customer;
    }

    public Integer getId() {
        return id;
    }

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

    public String getOrderno() {
        return orderno;
    }

    public void setOrderno(String orderno) {
        this.orderno = orderno;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", orderno='" + orderno + '\'' +
                ", productName='" + productName + '\'' +
                ", customer=" + customer +
                '}';
    }
}
  • 测试类
package com.lin.cn;

import com.sun.org.apache.xpath.internal.operations.Or;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.jupiter.api.Test;

import java.util.HashSet;
import java.util.Set;

/**
 * @Author Lin_Home
 * @Date 2020/10/11 14:56
 * @Version 1.0
 */
public class MainTest {
    @Test
    public void insertTest(){
        //建立会话
        Session session = HibernateUtils.openSession();
        //建立事务
        Transaction transaction = session.beginTransaction();
        //开始实体类的赋值
        Customer customer = new Customer();
        customer.setName("苍井空");
        customer.setGender("女");

        Order order = new Order();
        order.setOrderno("订单一号");
        order.setProductName("剧情片场");

        Order order2  = new Order();
        order2.setOrderno("订单二号");
        order2.setProductName("上门片场");

        Set<Order> orderSet = new HashSet<>();
        orderSet.add(order);
        orderSet.add(order2);

        order.setCustomer(customer);
        order2.setCustomer(customer);
        customer.setOrder(orderSet);

        //建立持久会话
        session.save(customer);
//        session.save(order);
//        session.save(order2);

        transaction.commit();
    }


    //全部查询
    @Test
    public void queryAllTest(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

    }

    //查询客户
    @Test
    public  void queryCustomer() {
        Session session=HibernateUtils.openSession();
        Customer customer=session.get(Customer.class,1);
        System.out.println("客户名="+customer.getName());
        for (Order order : customer.getOrder()) {
            System.out.println("订单名 ="+order.getProductName() +"-----订单编号"+order.getOrderno());
        }
    }


    //查询订单
    @Test
    public  void queryOrder() {
        Session session=HibernateUtils.openSession();
        Order order=session.get(Order.class,1);
        System.out.println("订单名="+order.getProductName());
        System.out.println("订单所属的客户 ="+order.getCustomer().getName() +"-------订单编号"+order.getOrderno());
    }

    //数据修改
    @Test
    public void delete(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        Customer customer = session.get(Customer.class, 1);
        session.delete(customer);
        transaction.commit();
        session.close();
    }

}

  • 配置文件

customer 的配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


<hibernate-mapping package="com.lin.cn">
    <class name="com.lin.cn.Customer" table="t_customer">
        <id name="id">
            <!--            数据库的主键交给数据库本地管理-->
            <generator class="native"></generator>
        </id>

        <property name="name" column="name"/>
        <property name="gender" column="gender"></property>

<!--        对应的是集合    name对应的是集合的变量名  key对应的是数据库中关联表的外键名  class值的是对表中的那个类名-->
<!--        cascade实现级联操作 这个是 实现 添加修改-->
        <set name="order" cascade="save-update,delete">
            <key column="cust_id"/>
            <one-to-many class="Order" />
        </set>

    </class>

</hibernate-mapping>
  • order的配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


<hibernate-mapping package="com.lin.cn">
    <class name="com.lin.cn.Order" table="t_order">
        <id name="id">
            <!--            数据库的主键交给数据库本地管理-->
            <generator class="native"></generator>
        </id>

        <property name="orderno" column="orderno"/>
        <property name="productName" column="product_name"></property>

        <!--对应的是集合    name对应的是集合的变量名的主键  column对应的是数据库中关联表的外键名 这边的class指的是映射one表 -->
        <many-to-one name="customer" column="cust_id" class="Customer"/>

    </class>


</hibernate-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/hello</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.username">root</property>
    <property name="connection.password">123456</property>

    <property name="hibernate.show_sql">true</property><!-- 配置显示sql语句 -->
<!--    <property name="format_sql">true</property>&lt;!&ndash; 让输出的sql语句格式化 &ndash;&gt;-->

    <mapping resource="Customer.hbm.xml"></mapping>
    <mapping resource="Order.hbm.xml"/>

  </session-factory>
</hibernate-configuration>

a、级联操作

  • 只要与此添加的对象相关的对象,它会连同持久化处理(添加或者修改)
                  <set name="orderSet" cascade="save-update">
                 <key column="cust_id" />
                <one-to-many class="Order"/>
  • 删除此对象,连同此对象的相关对象也删除( 要小心配置 )删除
          <set name="orderSet" cascade="save-update,delete">
          <key column="cust_id" />
          <one-to-many class="Order"/>
 </set>

b、inverse用法

1、作用
如果inverse为true,则放弃外键控制
如果inverse为false,则不放弃外键关系控制
2、用法
针对一方配置,多方inverse配置不起作用,不管inverse如何配置,多方它都会维护外键处理
用法
在一方配置inverse属性
输出sql语句,发现update语句不见了

          <set name="orderSet" inverse="true">
          <key column="cust_id" />
        <one-to-many class="Order"/>

七、多对多关联问题

1、什么是多对多

  • 举例以用户表与角色表为例
    • 一个用户可以所属多个角色
    • 一个角色里面可以有多个用户

2、多对多表关系实现

在这里插入图片描述

  • 多对多的关联表的实现要依赖于中间表
    • 中间表的user_id的字段其实就是用户表的主键
    • 中间表的role_id的字段其实就是角色表的主键

3、编写实体对象

  • 编写用户对象

    • 注意定义一个Set集合属性,存储一个用户对应多个角色
    package com.gec.domain;
    
    import java.util.Set;
    
    /*
    * 定义用户类
    * */
    public class User {
    
        private Integer id;
        private String name;
    
        public User() {
    
        }
    
        public User(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    
        //体现多角色,使用Set集合存储
        private Set<Role> roleSet;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Set<Role> getRoleSet() {
            return roleSet;
        }
    
        public void setRoleSet(Set<Role> roleSet) {
            this.roleSet = roleSet;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
  • 编写角色对象

    • 注意一个角色可以配置多个用户,因此定义Set集合userSet属性
    package com.gec.domain;
    
    import java.util.Set;
    
    /*
    * 角色类
    * */
    public class Role {
    
        private Integer roleId;
        private String roleName;
    
        //一个角色可以有多个用户
        private Set<User> userSet;
    
        public Role() {
    
        }
    
        public Role(Integer roleId, String roleName) {
            this.roleId = roleId;
            this.roleName = roleName;
        }
    
        public Integer getRoleId() {
            return roleId;
        }
    
        public void setRoleId(Integer roleId) {
            this.roleId = roleId;
        }
    
        public String getRoleName() {
            return roleName;
        }
    
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
    
        public Set<User> getUserSet() {
            return userSet;
        }
    
        public void setUserSet(Set<User> userSet) {
            this.userSet = userSet;
        }
    }
    
    

4、编写映射文件

  • 用户的映射文件(User.hbm.xml)

    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.gec.domain">
    
        <class name="User" table="t_user">
            <id name="id" column="id">
                <generator class="identity" />
            </id>
    
            <property name="name" column="name">
    
            </property>
    
            <!--Set集合映射,映射(一个用户所属多个角色)
                table:描述多对多所依赖的中间表表名
            -->
            <set name="roleSet" table="t_user_role">
                <!---此key的字段就是配置中间表的外键,它指向用户表的主键-->
                <key column="fk_user_id"></key>
                <!---此column的字段就是配置中间表的外键,它指向角色表的主键-->
                <many-to-many class="Role" column="fk_role_id"/>
            </set>
    
    
        </class>
    
    </hibernate-mapping>
    
  • 角色的映射文件(Role.hbm.xml)

    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.gec.domain">
    
        <class name="Role" table="t_role">
            <id name="roleId" column="roleId">
                <generator class="identity" />
            </id>
    
            <property name="roleName" column="roleName">
    
            </property>
    
            <!--Set集合映射,映射(一个用户所属多个角色)
                table:描述多对多所依赖的中间表表名
            -->
            <set name="userSet" table="t_user_role">
                <!---此key的字段就是配置中间表的外键,它指向角色表的主键-->
                <key column="fk_role_id"></key>
                <!---此column的字段就是配置中间表的外键,它指向用户表的主键-->
                <many-to-many class="User" column="fk_user_id"/>
            </set>
    
    
        </class>
    
    </hibernate-mapping>
    

5、编写全局配置文件

  • 编写hibernate.cfg.xml

    <?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>
        <!--jdbc驱动类名-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">1111</property>
        <!--配置数据库的方言-->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!--是否显示sql语句-->
        <property name="hibernate.show_sql">true</property>
        <!--hibernate自构建数据库表-->
        <property name="hibernate.hbm2ddl.auto">create</property>
    
        <!--指明映射文件的路径-->
        <mapping resource="com/gec/domain/User.hbm.xml"/>
        <mapping resource="com/gec/domain/Role.hbm.xml"/>
    
    
      </session-factory>
    </hibernate-configuration>
    

6、操作数据的主类

package com.gec.test;

import com.gec.dbtuils.HibernateUtils;
import com.gec.domain.Role;
import com.gec.domain.User;
import org.hibernate.Session;
import org.hibernate.Transaction;

import java.util.HashSet;
import java.util.Set;

public class MainTest {

    public static void main(String[] args) {
       // insert();
        queryUser();
    }

    public static void insert(){
        //创建用户对象
        User user01=new User();
        user01.setName("小苍");

        User user02=new User();
        user02.setName("小罗");

        //创建角色对象
        Role role01=new Role();
        role01.setRoleName("超级管理员");

        Role role02=new Role();
        role02.setRoleName("普通管理员");

        //创建一个角色集合,将此角色添加到小苍用户
        Set<Role> roleSet=new HashSet<>();
        roleSet.add(role01);
        roleSet.add(role02);
        user01.setRoleSet(roleSet);

        Set<Role> roleSet2=new HashSet<>();
        roleSet2.add(role02);
        user02.setRoleSet(roleSet2);

        //相互关联操作
        //定义集合,存储用户对象
        Set<User> userSet=new HashSet<>();
        userSet.add(user01);

        //role01.setUserSet(userSet);

        Set<User> userSet2=new HashSet<>();
        userSet2.add(user01);
        userSet2.add(user02);

        //role02.setUserSet(userSet2);

        Session session= HibernateUtils.openSession();
        Transaction tr=session.beginTransaction();

        //针对对象作持久化处理
        session.save(user01);
        session.save(user02);
        session.save(role01);
        session.save(role02);

        tr.commit();

        session.close();

    }
    
    //实现查询
    public static void queryUser(){
        Session session=HibernateUtils.openSession();
        User user=session.get(User.class,1);

        System.out.println("此用户名="+user.getName());

        for (Role role : user.getRoleSet()) {

            System.out.println("此用户所属的角色="+role.getRoleName());

        }
    }
}

八、实现一对一关系

1、什么是一对一关系?

  • 两个元素之间它们是唯一匹配的关系

    • 举例

      • 公民都有唯一的身份证

        公民------->身份证
        身份证------>公民
        

2、如何设计一对一的数据表关系

  • 如何设计数据表

    • 方案一:

      • 唯一外键关联

        • 特点
          • 针对外键作唯一的约束

        在这里插入图片描述

    • 方案二:

      • 主键关联

        • 特点
          • 此字段既是主键,也是外键

      在这里插入图片描述

3、如何实现唯一的外键关联

a、对象的设计

  • 公民的实体类对象

    package com.gec.domain;
    
    public class Person {
    
        private Integer id;
        private String personName;
    
        //以对象方式描述用户所分配的身份证
        private Card card;
    
        public Person() {
        }
    
        public Person(Integer id, String personName) {
            this.id = id;
            this.personName = personName;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getPersonName() {
            return personName;
        }
    
        public void setPersonName(String personName) {
            this.personName = personName;
        }
    
        public Card getCard() {
            return card;
        }
    
        public void setCard(Card card) {
            this.card = card;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "id=" + id +
                    ", personName='" + personName + '\'' +
                    '}';
        }
    }
    
    
  • 身份证的实体类对象

    package com.gec.domain;
    
    public class Card {
    
        private Integer id;
        private String cardNo;
    
        //以对象方式描述身份证所属唯一的公民
        private Person person;
    
        public Card() {
        }
    
        public Card(Integer id, String cardNo) {
            this.id = id;
            this.cardNo = cardNo;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getCardNo() {
            return cardNo;
        }
    
        public void setCardNo(String cardNo) {
            this.cardNo = cardNo;
        }
    
        public Person getPerson() {
            return person;
        }
    
        public void setPerson(Person person) {
            this.person = person;
        }
    
        @Override
        public String toString() {
            return "Card{" +
                    "id=" + id +
                    ", cardNo='" + cardNo + '\'' +
                    '}';
        }
    }
    
    

b、映射文件的配置

  • 针对Person实体类的映射配置文件

    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.gec.domain">
    
        <class name="Person" table="t_person">
    
            <id name="id" column="id">
                <generator class="identity" />
            </id>
    
            <property name="personName" column="person_name">
            </property>
    
            <!--针对身份证对象属性映射处理-->
            <!--
                一对一的配置
             -->
            <one-to-one name="card" class="Card"/>
    
    
        </class>
    
    </hibernate-mapping>
    
  • 针对身份证的实体类映射文件

    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.gec.domain">
    
        <class name="Card" table="t_card">
            <id name="id" column="id">
                <generator class="identity" />
            </id>
    
            <property name="cardNo" column="cardNo">
    
            </property>
    
            <!--
                配置多对一,但外键受唯一约束,其实就是一对一
            -->
            <many-to-one name="person" column="person_id" unique="true"/>
    
        </class>
    
    </hibernate-mapping>
    

c、全局配置文件

<?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>
    <!--jdbc驱动类名-->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">1111</property>
    <!--配置数据库的方言-->
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    <!--是否显示sql语句-->
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>

    <mapping resource="com/gec/domain/Person.hbm.xml" />
    <mapping resource="com/gec/domain/Card.hbm.xml" />

  </session-factory>
</hibernate-configuration>

d、实现主类

package com.gec.test;

import com.gec.dbutils.HibernateUtils;
import com.gec.domain.Card;
import com.gec.domain.Person;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class MainTest {

    public static void main(String[] args) {

        //insert();
        findPerson();
    }

    public static void insert(){
        //创建Person对象
        Person p=new Person();
        p.setPersonName("小苍");

        //创建身份证对象
        Card c=new Card();
        c.setCardNo("sn001");

        //相互关联
        p.setCard(c);
        c.setPerson(p);

        Session session=HibernateUtils.openSession();
        Transaction tr=session.beginTransaction();

        //针对公民及身份证作对象的持久化处理
        session.save(p);
        session.save(c);

        tr.commit();

        session.close();

    }

    public static void findPerson(){
        Session session=HibernateUtils.openSession();
        Transaction transaction=session.beginTransaction();

        Person p=session.get(Person.class,1);
        System.out.println("用户名="+p.getPersonName());
        System.out.println("对应的身份证="+p.getCard().getCardNo());

        transaction.commit();

        session.close();
    }
}

4、主键关联

a、简介

  • 表的字段既是主键,又是外键

b、对象实现

  • 对象实现如上述一致

c、映射配置文件实现

  • 主要修改card.hbm.xml文件

    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.gec.domain">
    
        <class name="Card" table="t_card">
            <id name="id" column="id">
                <generator class="identity" />
            </id>
    
            <property name="cardNo" column="cardNo">
    
            </property>
    
            <!--
                主键关联
                constrained属性:使用主键作为外键关联
            -->
            <!--<many-to-one name="person" column="person_id" unique="true"/>-->
            <one-to-one name="person" class="Person" constrained="true"/>
    
        </class>
    
    </hibernate-mapping>
    

九、查询功能

  • HQL 查询

  • QBC查询

  • 支持sql查询

    https://www.cnblogs.com/yizhichenfen/p/11319681.html对应的使用方式

十、对象状态问题

1、状态类别

  • 临时态
    • 此对象没有OID值,并且不受session对象所管理
      • OID:object的ID值,
  • 持久态
    • 此对象有 OID值,并且受session所管理
  • 游离态
    • 此对象有OID值,已经脱离了session所管理

2、举例

  • 临时态----》持久态----》游离态

    package com.gec.test;
    
    import com.gec.domain.Employee;
    import com.gec.utils.HibernateUtils;
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    
    public class MainTest {
    
        public static void main(String[] args) {
    
            objectstatus();
        }
    
        public static void objectstatus()
        {
            //创建一个Employee对象,此对象处于临时状态
            Employee employee=new Employee();
            employee.setEmpName("周杰伦");
            employee.setJob("C++开发");
            employee.setSalary(100000.00);
            employee.setHiredate(new java.util.Date());
    
    
    
    
    
            Session session= HibernateUtils.openSession();
    
            Transaction transaction=session.beginTransaction();
    
            //从临时态----->持久态
            /*
            *   持久态的特点:
            *   1、OID有值
            *   2、受session所管理
            * */
            session.save(employee);
    
            System.out.println("处于持久态的id值="+employee.getId());
    
            transaction.commit();
    
            session.close();
    
            //employe它就会处于游离态
            System.out.println("处于游离态的id值="+employee.getId());
    
        }
    }
    
    
  • 状态转换

img

十一、缓存详解

  • 减少访问数据库的次数,提高访问数据的效率

在这里插入图片描述

2、验证一级缓存是否存在

  • 举例

    //测试缓存是否启作用
        public static void testCache()
        {
            Session session= HibernateUtils.openSession();
    
            Transaction transaction=session.beginTransaction();
    
            //获取id=5的对象
            //employee此对象处于持久态
            Employee employee=session.get(Employee.class,5);
    
            System.out.println(employee.getEmpName());
    
            //此处是使用缓存获取对象数据
            Employee employee2=session.get(Employee.class,5);
    
            System.out.println(employee2.getEmpName());
            transaction.commit();
            session.close();
        }
    

3、如何清除一级缓存对象

  • 只需要调用以下方法即可

     session.evict(employee);
    session.clear();
    
  • 一级缓存其实它的作用域就是session对象,一级缓存hibernate是默认启动

  • 二级缓存它的作用域就是SessionFactory,二级缓存默认是不启动

在这里插入图片描述

4、如何配置二级缓存

a、导入encache库

  • 导入第三方缓存工具:EhCache

在这里插入图片描述

b、配置hibernate.cfg.xml

  • 启动二级缓存

  • 配置encache

  • 需要哪个类使用二级缓存

    <!-- 开启 Hibernate 的二级缓存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!-- 引入 EhCache 的工具 -->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    
    <class-cache class="实体类路径" usage="read-only" />
    

c、编写主类,测试二级缓存

Session session= HibernateUtils.openSession();

        Transaction transaction=session.beginTransaction();

        //获取id=5的对象
        //employee此对象处于持久态
        Employee employee=session.get(Employee.class,5);

        System.out.println(employee.getEmpName());


        transaction.commit();
        session.close();

        Session session2=HibernateUtils.openSession();

        //此处是使用缓存获取对象数据
        Employee employee2=session2.get(Employee.class,5);

        System.out.println(employee2.getEmpName());

        session2.close();

十二、延时加载

  • get 和 load的区别

  • load :是存在延时加载(当调用到load 返回来的数据时,才显示sql语句,当是没有执行的时候是存在延时加载)[QueryById]方法

  • get:不存在延时加载,只要调用了get这个方法,直接执行hql 语句**【QueryById2】**

    @Test
    public void QueryById(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        Employee user = session.load(Employee.class, 2);
//        System.out.println(user);
        transaction.commit();
        session.close();
    }

    @Test
    public void QueryById2(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();
        Employee user = session.get(Employee.class, 2);
//        System.out.println(user);
        transaction.commit();
        session.close();
    }
  • 配置文件下 设置:lazy=“false”:放弃延时加载 true 是开启延时

1、类延时加载

在这里插入图片描述

<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.gec.domain">

    <class name="Employee" table="t_employee" lazy="false">

        <id name="id" column="id">
            <generator class="native" />
        </id>

        <property name="empName" column="emp_name">
            
        </property>
        
        <property name="salary" column="salary" type="java.lang.Double">

        </property>

        <property name="job" column="job" type="java.lang.String">

        </property>

        <property name="hiredate" column="hiredate" type="java.util.Date">

        </property>
    </class>

</hibernate-mapping>

2、类属性延时

  • 与表关联的延时加载问题,以一对多为例讲解

  • 可以针对一方,设置lazy=true,则支持延时加载,否则放弃延时加载

    • 配置一方的延时加载实现

       <set name="orderSet" lazy="true">
                  <!--设置外键字段-->
                  <key column="cust_id" />
                  <!--指明多方的类名-->
                  <one-to-many class="Order"/>
              </set>
      
      • 配置lazy=true(默认),则支持延时加载 ,当查询客户对象,只要没有用于order属性对象,,是不会生成sql语句,查询order表内容
      • 配置layz=false,不管客户是否使用order属性,都会生成查询订单的sql语句,执行sql
    • 配置多方的延时加载实现

      <!--映射one的对象-->
              <many-to-one name="customer" column="cust_id" class="Customer" lazy="false"/>
      
      • 配置lazy=true(默认),则支持延时加载 ,当查询订单对象,只要没有用到客户对象属性,则不会生成查询客户对象的sql语句

十三、抓包策略

  • hibernate有如下四种原生态的Hibernate抓取策略,分别是:select fetching ,join fetching,subselect fetching,Batch fetching。
  • 配置fetch属性

    • select(默认)

      生成n条sql
      		第一条sql:select * from customer where c.id=1;
               第二条sql: select * from order where o.cust_id=1;
      
    • join

      • 生成多表关联查询

         它只会生成一条sqlselect c.*,o.* from customer c left join order o on c.id=o.cust_id where c.id=1
        
    • subselect(针对createQuery起作用)

      • 生成子查询

        select * from order o where o.cust_id in (select c.id from customer c)
        

十四、Threadlocal管理session

1、为什么要使用ThreadLocal管理session

  • session是线程不安全的,因此在多线程环境下,session对象不能为共享对象
  • 每次运行都要打开及关闭session对象,导致性能受影响
  • 如果直接调用sessionfactory.openSession方法,获取session对象,则无法在业务层获取实现事务管理

2、如何配置session受threadlocal管理

a、写法一:

  • 自定义session受Threadlocal管理的实现

    /*
    * 定义hibernate的工具类
    * 受ThreadLocal管理session
    * */
    public class HibernateUtils {
    
        private static SessionFactory sf=null;
        // 使用线程局部模式
        //它其实就是一个map集合
        /*
        *   key:就是线程id
        *   value:Session对象
        * */
        private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    
        //静态初始化块只加载一次
        static {
            //创建配置对象,它会默认读取hibernate.cfg.xml文件
            Configuration configuration=new Configuration().configure();
    
            //创建一个SessionFactory对象
            sf=configuration.buildSessionFactory();
    
        }
    
    
        public static Session getCurrentSession()
        {
            //先判断threadlocal是否已经存在当前线程的session,如果不存在,才创建session对象
            Session session = threadLocal.get();
            if(session==null)
            {
                session=sf.openSession();
                threadLocal.set(session);
            }
    
            return session;
        }
    }
    

b、写法二:

  • 通过配置实现

    • 配置hibernate.cfg.xml文件

      <property name="hibernate.current_session_context_class">thread</property>
      
    • 修改Hibernate工具类代码

          public static Session openSession()
          {
              return sf.getCurrentSession();
          }
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值