美文网首页
Hibernate笔记

Hibernate笔记

作者: 0c9e81b07e5a | 来源:发表于2017-12-26 13:53 被阅读0次

    JavaEE的三层结构

    1. web层:struts2框架
    2. service层:spring框架
    3. dao层:hibernate框架
      MVC思想
    4. m:模型
    5. v:视图
    6. c:控制器

    1 Hibernate概述

    1.1 框架

    1.1.1 通俗理解

    就是少写部分代码实现功能

    1.2 Hibernate框架

    1. hibernate框架应用在JavaEE三层结构中的dao层
    2. 在dao层hibernate实现CRUD操作,hibernate底层就是JDBC,对JDBC进行封装,好处是不需要写复杂的
      JDBC代码了,不需要写SQL语句实现
    3. hibernate开源轻量级框架
    4. hibernate 版本
      Hibernate3.x
      Hibernate4.x
      Hibernate5.x(2017最新)

    1.3 底层实现

    1.3.1 ORM思想
    1. hibernate使用ORM思想对数据库进行CRUD操作
    2. 在web阶段学习Javabean更正确的叫法交:实体类
    3. ORM:Object Relational Mapping 对象关系映射
      实体类数据库 表进行一一对应关系
      实体类数据库 表进行对应
      实体类 属性 里面 字段 对应
      不需要操作数据库而是直接操作对应的实体类对象

    2 Hibernate使用

    2.1 入门

    2.1.1 hibernate开发环境搭建
    1)导入jar包

    下载hibernate-release-5.2.10.Final
    ①压缩包中的lib中的required文件夹内的jar包
    ②jpa的jar包也在required内
    ③日志jar包.hibernate本身没有日志输出jar包,需导入其他日志输出jar包 log4j,slf4j-log4j,slf4j-api
    ④mysqk驱动jar包mysql-connector-java

    2)创建实体Bean类

    hibernate 要求有个实体类有一个属性唯一
    (可以手动在mysql中创建表与bean类属性对应,也可以由hibernate自己创建)

    package cn.wanxp.entity;
    
    public class User {
        public int getUid() {
            return uid;
        }
        public void setUid(int uid) {
            this.uid = uid;
        }
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }
        /*hibernate 要求有个实体类有一个属性唯一*/
        private int uid;
        private String username;
        private String password;
        private String address;
    }
    
    
    3) 配置实体类和数据库表一一对应关系(映射关系)

    实用配置文件实现映射关系
    (1) 创建xml格式的配置文件
    映射文件的名称和位置没有固定要求
    -- 建议在实体类的所在包内 实体类名称.hbm.xml
    (2) 配置文件是xml格式,在配置文件中引入xml约束
    -- hibernate里面引入的约束是dtd格式
    (3)在包内创建映射文件User.hbm.xml
    约束可以是本地文件在hibernate-release-5.2.10.Final内可搜索到,复制与User放一起然后写

    <!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >  
    

    也可以是网上公用的DTD文件,如果是使用网上的dtd约束则

    <!DOCTYPE hibernate-mapping PUBLIC   
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
    <!-- 上面这段约束可在hibernate-mapping-3.0.dtd中开头部分找到 -->      
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
    <hibernate-mapping>
        <!-- 1配置类和表对应
            class标签
                name 属性: 实体类全路径
                table 属性:数据库名称(随意名称)
         -->
         <class name="cn.wanxp.entity.User" table="t_user">
            <!-- 2配置实体类id和表id一一对应
                要求两id在各自位置具有唯一性
             -->
             <!-- 
                id标签
                    name属性: 实体类里面id属性名称
                    column属性:生成表字段名称(名称随意)
              -->
             <id name="uid" column="uid">
                <!--设置数据表id增长策略  
                    native 生成表id是主键和自增长
                -->
                <generator class="native"></generator>
             </id>
             <!-- 配置其他属性与字段对应 
                name属性:实体类属性名称  
                column属性:数据表字段名称
             -->
             <property name="username" column="username"></property>
             <property name="password" column="password"></property>
             <property name="address" column="address"></property>
         </class>
        
    </hibernate-mapping>
    
    4)创建hibernate的核心配置文件

    (1)核心配置文件格式xml,配置文件名称和位置固定
    -位置: 必须src下面
    -名称: 必须hibernate.cfg.xml
    (2)引入约束

    <!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    

    (3)hibernate 操作过程中只会加载核心配置文件,其它配置文件不会加载
    第一部分:配置数据库信息
    第二部分:配置hibernate信息
    第三部分:映射文件放在核心配置文件中
    注意
    ①方言
    注意下面的这句:是MySQL5Dialect,不是properties文件中的MySQLDialect因为版本不一样了,
    不然无法创建表。原因就是使用没有5的会用创建命令type=,而不是engine=

      <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    

    ②字符集
    -1- 如要使用字符集utf8,想要支持中文时:
    先创建数据库database加上字符集:create database hibernate_day01 charset utf8 ;
    然后在hibernate.cfg.xml加上下面标签属性,表示和数据库传递数据采用utf8编码

    <property name="connection.useUnicode">true</property>
    <property name="connection.characterEncoding">UTF-8</property>
    

    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>
        <!-- 第一部分:配置数据库信息 
            在下载的hibernate-release压缩包文件夹内搜索hibernate.properties打开后可看到对应的数据库需要配置的属性
        -->
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_day01</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">root</property>
            <property name="connection.useUnicode">true</property>
        <property name="connection.characterEncoding">UTF-8</property>
        <!-- 第二部分:配置hibernate信息,可选的,可以配置也可以不用配置
            同样能在hibernate.properties搜索到相应的值
         -->
            <!-- 如:输出底层sql语句 -->
            <property name="hibernate.show_sql">true</property>
            <!-- 如:格式化底层sql语句 -->
            <property name="hibernate.format_sql">true</property>
            <!-- 如:hibernate创建表,需要配置后
                update:如果已经存在表则更新,若不存在则创建
             -->
            <property name="hibernate.hbm2ddl.auto">update</property>
            <!-- 配置数据库方言
                mysql里实现分页关键字 limit 只能在mysql里面
                Oracle数据库,实现分页rownum
                在hibernate框架识别不同数据库自己特有的语句
             -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
            
        <!-- 第三部分:配置映射文件 -->
            <!-- resource引入路径根目录是src -->
            <mapping resource="/cn/wanxp/entity/User.hbm.xml" />
        </session-factory>
    </hibernate-configuration>
    
    5)测试 添加操作 1-4,6,7写法基本都是固定的,变化的只有第5步

    (1)加载hibernate核心配置文件
    (2)创建SessionFactory对象
    (3)使用SessionFactory创建session对象
    (4)开启事务
    (5)写具体逻辑
    (6)提交事务
    (7)关闭资源
    示例如下

    package cn.wanxp.hibernatetest;
    
    
    import java.io.UnsupportedEncodingException;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    
    import cn.wanxp.entity.User;
    
    public class HibernateDemo {
        @Test
        public void testAdd() {
    //      (1)加载hibernate核心配置文件  
                //在hibernate里面封装对象  
                //将会到src下找到hibernate.cfg.xml的文件
            Configuration cfg = new Configuration();
            cfg.configure();
    //      (2)创建SessionFactory对象 
                //读取hibernate核心配置文件,创建SessionFactory
                //过程中根据配置文件中的属性以及映射关系xml文件创建表
            SessionFactory sessionFactory=cfg.buildSessionFactory();
    //      (3)使用SessionFactory创建session对象
                //类似于JDBC连接
            Session session = sessionFactory.openSession();
    //      (4)开启事务  
            Transaction tx = session.beginTransaction();
    //      (5)写具体逻辑编写CRUD操作  
             User user = new User();
             String username="张三";
             user.setUsername(username);
             user.setPassword("password1");
             user.setAddress("上海");
             session.save(user);
    //      (6)提交事务  
            tx.commit();
    //      (7)关闭资源 
            session.close();
            sessionFactory.close();
        }
    }
    
    

    效果如下:

    hibernate-first-test

    2 hibernate详解

    2.1 hibernate配置文件

    2.1.1 hibernate映射配置文件
    • 映射文件没有固定位置
      映射配置文件中,标签name属性写实体类中的属性名;column可以不用写,字段名就会命名为实体类属性同一名字。
      property标签type属性可以设置数据表的字段属性。
    2.1.2 核心配置文件

    标签位置要求:

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

    配置的三部分要求

    • 数据库部分--必须
    • hibernate部分--可选
    • 映射文件--必须

    2.2 hibernate核心api

    2.2.1 Configuration
    Configuration cfg = new Configuration();
    cfg.configure();
    

    上面代码的过程:从src下找到hibernate.cfg.xml文件并根据里面的配置,创建对象并加载

    2.2.2 SessionFactory
    1. 根据配置文件中的属性创建表
    <!-- 如:hibernate创建表,需要配置后
      update:如果已经存在表则更新,若不存在则创建  
     -->
    <property name="hibernate.hbm2ddl.auto">update</property>
    
    1. 创建SessionFactory过程,特别耗费资源,所以一般一个项目只创建一次
    2. 具体实现
      (1)写工具类,写静态代码块
    package cn.wanxp.utils;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    public class HibernateUtils {
        private static Configuration cfg = null;
        private static SessionFactory sessionFactory = null;
        static {
            cfg = new Configuration();
            cfg.configure();
            sessionFactory = cfg.buildSessionFactory();
            
        }
        public static SessionFactory getSessionFactory() {
            return sessionFactory;
        }
    }
    
    2.2.3 Session
    1. Sesssion不同方法实现CRUD操作
      (1) 添加:save
      (2) 修改:update
      (3) 删除:delete
      (4) 根据id查询:get
    2. session对象单线程对象
      (1) session对象不能共用,只能自己使用
    2.2.4 Transaction
    1. 事务对象
    Transaction tx =  session.beginTransaction();
    
    1. 事物提交和回滚方法
    tx.commit();
    tx.rollback();
    
    1. 事物
      (1) 事物四个特性
      原子性、一致性、隔离性、持久性
    2.3 配置文件没有提示

    复制下面的uri

    http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
    

    Eclipse->Preferences->XML Catalog->Add->

    location---找到hibernate-configuration-3.0.dtd    
    uri----http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
    

    这样就能不用联网就能使用http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd

    3 hibernate

    3.1 实体类编写

    3.1.1 编写规则

    1) 私有域
    2) set-get方法
    3) 实体类有属性有唯一值
    4) 实体类建议不使用基本类型,使用基本数据类型的包装类
    (1) int--Integer,char--Character
    (2) 比如表示学生分数用int就只能表示分数大小,不能使用null表示没参加,而是用Integer就能解决这个问题了

    3.2 Hibernate主键生成策略

    1) hibernate要求实体类厘米吗必须有一个属性作为唯一值,对应表主键,主键可以不同生成策略
    2) hibernate主键生成策略有很多值
    3) 在class里面的值
    主要: native,uuid
    UUID生成策略的实体类属性表id的类型是String类型

    private String uid;
    
    <generator>
    

    3.3 Hibernate CRUD

    3.3.1 增
    User user = new User();
    user.setUsername("李四");
    user.setPassword("123456");
    user.setAddress("上海");
    session.save(user);
    
    3.3.2 删

    方法1 查询-删除

    User user =session.get(User.class , 3);
    session.delete(user);
    

    方法2 设置-删除

    User user = new User();
    user.setId(3);
    session.delete(user);
    
    3.3.3 改

    方法1

    方法2 查询-修改

    //李四换成王五
    package cn.wanxp.hibernatetest;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.junit.Test;
    
    import cn.wanxp.entity.User;
    import cn.wanxp.utils.HibernateUtils;
    
    public class HibernateDemoDay02 {
        @Test
        public void testAdd() {
    //      直接调用SessionFactory调用静态调用方法   
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
    //      (3)使用SessionFactory创建session对象
                //类似于JDBC连接
            Session session = sessionFactory.openSession();
    //      (4)开启事务  
            Transaction tx = session.beginTransaction();
    //      (5)写具体逻辑编写CRUD操作  
             User user = new User();
             String username="李四";
             user.setUsername(username);
             user.setPassword("password1");
             user.setAddress("上海");
             session.save(user);   
             
             System.out.println(user);
             
             user = session.get(User.class , 3);
             user.setUsername("王五");
             session.update(user);  
             user = session.get(User.class , 3);
             System.out.println(user);
    //      (6)提交事务  
            tx.commit();
    //      (7)关闭资源 
            session.close();
            sessionFactory.close();
        }
    }
    
    
    3.3.4 查
    User user = session.get(User.class,2);//查询并返回id=2的user
    

    3.3.5 save,update,saveOrUpdate

    save:id没有效果 ,只会直接添加
    update:id的对应记录更新所有内容

    3.4 实体类对象状态

    3.4.1实体类状态三种状态

    1)瞬时态,对象里面没有id值,对象与session没有关联

    User user = new User();
    user.setUsername("Jack");
    user.setPassword("password");
    user.setAddress("上海");
    

    2)持久态,对象里有id值,与session相关联

    User user = session.get(User.class , 3);
    
    1. 托管态,对象里有id值,与session没有关联
    user.setId(3);
    
    3.4.2演示操作实体类对象的方法
    1. saveOrUpdate方法:
    • 实体类状态瞬时态,这个方法做的是添加操作
    • 实体类状态托管态,这个方法做的是修改操作
    • 实体类状态持久态,这个方法做的是修改操作

    4 hibernate的优化

    4.1 缓存

    hibernate有两级缓存:一级缓存,二级缓存

    4.1.1 一级缓存

    1)第一类 hibernate一级缓存特点
    (1)hibernate的一级缓存默认打开的
    (2)hibernate的一级缓存适用范围,是session范围,从session创建到session关闭范围
    (3)hibernate的一级缓存中,存储数据必须持久态数据
    2)第二类hibernate的二级缓存
    (1)目前 已经不适用了,替代技术redis
    (2)二级缓存默认不是打开的,需要配置
    (3)二级缓存使用范围,是SessionFactory范围

    4.1.2 验证一级缓存的存在

    1)验证方式
    (1)首先根据uid=1查询,返回对象
    (2)再次根据uid=1查询,返回对象
    第二次查询将不会查询数据库而是直接拿出数据

    4.1.3 一级缓存过程

    session.get(),会先去一级缓存中查询,若没有则去数据库,若有直接拿出。
    session范围是指从创建到close();

    4.1.4 一级缓存的特点

    持久态会自动执行

    User user = session.get(User.class , 3);//将对象保存至一级缓存和快照区
    user.setUsername("赵武");   //会同时修改:修改user对象里的值,修改持久态对象的值,修改一级缓存中的内容,不会修改快照区内容
    tx.commit();//执行到这里即使没有update,也会修改数据库
    //commit做的内容:提交事务,做的事情,比较一级缓存和快照区内容是否相同,若不同则将一级缓存内容写入数据库,若相同则不修改    
    

    效果图如下

    效果图

    4.2 事务详解

    4.2.1 什么是事务
    4.2.2 事务的特性

    原子性,一致性,隔离性,持久性

    4.2.3 不考虑隔离性产生的问题
    1. 脏读
      2)不可重复读
      3)虚读
    4.2.4 设置事务隔离级别

    1)mysql默认隔离级别 repeateable read
    2)级别设置 在hibernate.cfg.xml中

    <!--
      1-Read uncommited isolation
      2-Read commited isolation
      4-Repeatable read isolation
      8-Serializable isolation
    -->
    <property name="hibernate.connection.isolation">4</property>
    
    4.2.5 hibernate规范的事务写法
    try{
      //开启事务
      //提交事务
    }catch(){
      //回滚事务
    }final{
      //关闭操作
    }
    
    @Test
    public void testRollback() {
      SessionFactory sessionFactory = null;
      Session session = null;
      Transaction tx = null;
      try {
        sessionFactory = HibernateUtils.getSessionFactory();
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        User user = session.get(User.class , 3); 
        user.setUsername("毛毛");
        tx.commit();
      }catch(Exception e) {
        e.printStackTrace();
        tx.rollback();
      }finally{
        session.close();
        sessionFactory.close();
      }
    }
    

    4.3 hibernate绑定session线程

    4.3.2 介绍

    为了保证session是单线程的,而不会被其它人使用。
    注意 由于与本地线程绑定,所以不需要关闭session了,因为本地线程一完成,session自动关闭

    4.3.2 配置
    1. hibernate.cfg.xml中配置
    <property name="hibernate.current_session_context_class">thread</property>
    
    1. 调用SessionFactory对象里的的方法得到
    public static Session getSessionObject(){
      return sessionFactory.getCurrentSession();
    }
    

    5 hibernate的api使用

    5.1 查询

    Query对象,Criteria对象 SQLQuery对象

    5.1.1 Query对象

    1)使用Query对象不需要写sql语句,但是写hql语句
    (1)hql:hibernate query language,hibernate提供查询语句
    这个hql语句和普通sql很相似
    (2) hql和sql语句区别
    sql操作表和字段
    hql操作实体类和属性
    2)查询所有hql语句:
    (1)from实体类名称
    3) Query对象使用
    (1)创建 Query对象
    (2)调用Query对象里的方法得到结果

    Query query = session.createQuery("from User");
    List<User> list = query.list();
    
    5.1.2 Criteria对象

    1) Query对象使用
    (1)创建 Query对象
    (2)调用Query对象里的方法得到结果

    Criteria criteria = session.createCriteria(User.class);
    List<User> list = query.list();
    
    5.1.3 SQLQuery对象
    1. 使用SQL底层语句
      2) SQLQuery对象使用
      (1)创建 Query对象
      (2)调用Query对象里的方法得到结果(默认是数组)
    SQLQuer sqlQuery = session.createSQLQuery("select * from t_user where username='张三'");
    //默认返回的数组
    List list = query.list();
    

    (3)调用Query对象里的方法得到结果为对象的做法

    SQLQuer sqlQuery = session.createSQLQuery("select * from t_user where username='张三'");
    sqlQuery.addEntity(User.class);
    List<User> list = query.list();
    

    6 hibernate的表关系操作

    6.1 表的关系

    1)一对多
    一个分类有多个商品
    2)多对多
    订单与商品,一个订单多个商品,一个商品多个订单
    3)一对一
    丈夫与妻子

    6.2 一对多

    6.2.1 一对多表创建

    1)创建“一”实体类并在里面创建“多”的Set(集合)如HashSet
    2)创建“多”实体类并在里面创建“一”的实体的对象作为私有域
    3)创建“一”实体类映射表,将基本的私有域建立好映射
    4)创建“多”实体类映射表,将基本的私有域建立好映射
    5)在配置文件中配置一对多关系
    6)创建核心配置文件hibernate.cfg.xml
    下面是一个例子,客户(企业)类,每个(客户)企业都有很多员工的联系方式,客户表-员工联系方式表就是一对多的关系

    ①----客户实体类 Customer.java

    package cn.wanxp.entity;
    
    import java.util.HashSet;
    import java.util.Set;
    
    
    public class Customer {
    
        public Integer getCid() {
            return cid;
        }
        public void setCid(Integer cid) {
            this.cid = cid;
        }
        public String getCustomerName() {
            return customerName;
        }
        public void setCustomerName(String customerName) {
            this.customerName = customerName;
        }
        public String getCustomerLevel() {
            return customerLevel;
        }
        public void setCustomerLevel(String customerLevel) {
            this.customerLevel = customerLevel;
        }
        public String getCustomerSource() {
            return customerSource;
        }
        public void setCustomerSource(String customerSource) {
            this.customerSource = customerSource;
        }
        public String getCustomerPhone() {
            return customerPhone;
        }
        public void setCustomerPhone(String customerPhone) {
            this.customerPhone = customerPhone;
        }
        public String getCustomerMobile() {
            return customerMobile;
        }
        public void setCustomerMobile(String customerMobile) {
            this.customerMobile = customerMobile;
        }
        
        //在客户实体类中表示多个联系人,一个客户对应多个联系人   
        //hibernate要求使用集合表示多的数据,使用Set集合
        private Set<Linkman> setLinkman = new HashSet<Linkman>();
        
        
        public Set<Linkman> getSetLinkman() {
            return setLinkman;
        }
        public void setSetLinkman(Set<Linkman> setLinkman) {
            this.setLinkman = setLinkman;
        }
    
        private Integer cid;
        private String customerName;
        private String customerLevel;
        private String customerSource;
        private String customerPhone;
        private String customerMobile;
    }
    

    ②----”多“的表实体类Linkman.java

    package cn.wanxp.entity;
    
    public class Linkman {
        public Integer getLid() {
            return lid;
        }
        public void setLid(Integer lid) {
            this.lid = lid;
        }
        public String getLinkmanName() {
            return linkmanName;
        }
        public void setLinkmanName(String linkmanName) {
            this.linkmanName = linkmanName;
        }
        public String getLinkmanGender() {
            return linkmanGender;
        }
        public void setLinkmanGender(String linkmanGender) {
            this.linkmanGender = linkmanGender;
        }
        public String getLinkmanPhone() {
            return linkmanPhone;
        }
        public void setLinkmanPhone(String linkmanPhone) {
            this.linkmanPhone = linkmanPhone;
        }
        
        //在联系人实体类里表示所属客户,一个联系人属于一个客户
        private Customer customer = new Customer();
        
        
        public Customer getCustomer() {
            return customer;
        }
        public void setCustomer(Customer customer) {
            this.customer = customer;
        }
    
        private Integer lid;
        private String linkmanName;
        private String linkmanGender;
        private String linkmanPhone;
    }
    

    ③----Customer实体配置文件Customer.hbm.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
    <hibernate-mapping>
         <class name="cn.wanxp.entity.Customer" table="t_customer">
             <id name="cid" column="cid">
                <generator class="native"></generator>
             </id>
             <property name="customerName" column="customerName"></property>
             <property name="customerLevel" column="customerLevel"></property>
             <property name="customerSource" column="customerSource"></property>
             <property name="customerPhone" column="customerPhone"></property>
             <property name="customerMobile" column="customerMobile"></property>
             <!-- 在客户映射文件中,表示所有联系人,使用set标签表示所有联系人 
                    set标签里面有name属性:属性值写在客户实体类里面表示联系恶人的set集合名称
             -->
             <set name="setLinkman">
                <!-- 一对多建表,有外键。hibernate机制:双向维护外键,在一和多都有配置外键 
                    column属性值:外键名称
                -->
                <key column="cid"></key>
                <one-to-many class="cn.wanxp.entity.Linkman"/>
             </set>
         </class>
    </hibernate-mapping>
    

    ④----Linkman配置文件 Linkman.hbm.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
    <hibernate-mapping>
         <class name="cn.wanxp.entity.Linkman" table="t_linkman">
            <id name="lid" column="lid">
                <generator class="native"></generator>
             </id>
             <property name="linkmanName" column="linkmanName"></property>
             <property name="linkmanGender" column="linkmanGender"></property>
             <property name="linkmanPhone" column="linkmanPhone"></property>
             <!-- 在联系人中配置所属客户 
                name属性:因为在联系人实体类使用Customer对象表示。写customer名称
                class属性:Customer全路径
                column属性是生成的表格存储Customer的id的列名称要与Customer.hbm.xml中key一致
             -->
             <many-to-one name="customer" class="cn.wanxp.entity.Customer" column="cid"></many-to-one>
         </class>
    </hibernate-mapping>
    

    ⑤----同样需要将配置文件加入到hibernate核心配置文件中

    <mapping resource="/cn/wanxp/entity/Customer.hbm.xml" />
    <mapping resource="/cn/wanxp/entity/Linkman.hbm.xml" />
    

    ⑥----测试效果

    package cn.wanxp.hibernatetest;
    import java.io.UnsupportedEncodingException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    import cn.wanxp.entity.User;
    public class HibernateDemoDay03 {
        @Test
        public void testOneToMany() {
            Configuration cfg = new Configuration();
            cfg.configure();
            SessionFactory sessionFactory=cfg.buildSessionFactory();
            Session session = sessionFactory.openSession();
            Transaction tx = session.beginTransaction();
            tx.commit();
            session.close();
            sessionFactory.close();
        }
    }
    
    

    ⑦----输出结果

    Hibernate: 
        
        create table t_customer (
           cid integer not null auto_increment,
            customerName varchar(255),
            customerLevel varchar(255),
            customerSource varchar(255),
            customerPhone varchar(255),
            customerMobile varchar(255),
            primary key (cid)
        ) engine=MyISAM
    Hibernate: 
        
        create table t_linkman (
           lid integer not null auto_increment,
            linkmanName varchar(255),
            linkmanGender varchar(255),
            linkmanPhone varchar(255),
            cid integer,
            primary key (lid)
        ) engine=MyISAM
    Hibernate: 
        
        alter table t_linkman 
           add constraint FKn4dw5i2knad5dl95xit4v1b0p 
           foreign key (cid) 
           references t_customer (cid)
    
    6.2.1 一对多表操作

    1)一对多级联保存 -- 复杂写法
    直接在session中设置并保存

    package cn.wanxp.hibernatetest;
    import java.io.UnsupportedEncodingException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    
    import cn.wanxp.entity.Customer;
    import cn.wanxp.entity.Linkman;
    import cn.wanxp.entity.User;
    import cn.wanxp.utils.HibernateUtils;
    public class HibernateDemoDay03 {
        @Test
        public void testOneToManyAdd() {
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            Customer customer = new Customer();
            Linkman linkman = new Linkman();
            try {
                sessionFactory = HibernateUtils.getSessionFactory();
                session = sessionFactory.openSession();
                tx = session.beginTransaction();
                //1创建客户和联系人对象并设置基本域值
                linkman.setLinkmanName("李四");
                linkman.setLinkmanGender("男");
                linkman.setLinkmanPhone("131313");
                
                customer.setCustomerName("联想");
                customer.setCustomerSource("web");
                customer.setCustomerLevel("vip");
                customer.setCustomerPhone("3333");
                customer.setCustomerMobile("1111");
                
                //2在客户表中和联系人表中连接部分分别添加对方
                linkman.setCustomer(customer);
                customer.getSetLinkman().add(linkman);
                //3使用save存储进数据表中
                session.save(customer);
                session.save(linkman);
                
                tx.commit();
            }catch(Exception e) {
                e.printStackTrace();
                tx.rollback();
            }finally {
                session.close();
                sessionFactory.close();
            }
        }
    }
    

    2)一对多级联保存 -- 简单写法
    第一步在客户映射文件中进行配置
    修改Customer.hbm.xml配置文件中的set标签,在set标签中添加 cascade="save-update"属性

    <set name="setLinkman" cascade="save-update">
    

    上面的HibernateDemoDay03.java就可以修改为

    package cn.wanxp.hibernatetest;
    import java.io.UnsupportedEncodingException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.junit.Test;
    
    import cn.wanxp.entity.Customer;
    import cn.wanxp.entity.Linkman;
    import cn.wanxp.entity.User;
    import cn.wanxp.utils.HibernateUtils;
    public class HibernateDemoDay03 {
       @Test
       public void testOneToManyAdd() {
           SessionFactory sessionFactory = null;
           Session session = null;
           Transaction tx = null;
           Customer customer = new Customer();
           Linkman linkman = new Linkman();
           try {
               sessionFactory = HibernateUtils.getSessionFactory();
               session = sessionFactory.openSession();
               tx = session.beginTransaction();
               //1创建客户和联系人对象并设置基本域值
               linkman.setLinkmanName("李四");
               linkman.setLinkmanGender("男");
               linkman.setLinkmanPhone("131313");
               
               customer.setCustomerName("联想");
               customer.setCustomerSource("web");
               customer.setCustomerLevel("vip");
               customer.setCustomerPhone("3333");
               customer.setCustomerMobile("1111");
               
               //2在客户表中添加联系人实体类对象,相互
         linkman.setCustomer(customer);
               customer.getSetLinkman().add(linkman);
               //3使用save存储进数据表中
               session.save(customer);
               
               tx.commit();
           }catch(Exception e) {
               e.printStackTrace();
               tx.rollback();
           }finally {
               session.close();
               sessionFactory.close();
           }
       }
    }
    

    效果如下

    hibernate-one-to-many-add

    3)一对多删除
    如,删除某个客户,把客户里面所有的联系人删除

    ① 在客户映射文件中进行配置(多个值用逗号隔开)
    修改Customer.hbm.xml配置文件中的set标签,在set标签中添加 cascade="save-update,delete"属性

    <set name="setLinkman" cascade="save-update,delete">
    

    ② 在代码中直接删除
    先根据id查找客户然后删除

    @Test
    public void testOneToManyDelete() {
      SessionFactory sessionFactory = null;
      Session session = null;
      Transaction tx = null;
      Customer customer = new Customer();
      Linkman linkman = new Linkman();
      try {
        sessionFactory = HibernateUtils.getSessionFactory();
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        
        customer = session.get(Customer.class, 1);
        session.delete(customer);
        
        tx.commit();
      }catch(Exception e) {
        e.printStackTrace();
        tx.rollback();
      }finally {
        session.close();
        sessionFactory.close();
      }
    }
    

    效果如下

    效果
    3)一对多修改
    (1)如将多方的ABC三个记录中的C的外键Y修改为一方的XY中的X
    Customer X=session.get(Customer.class,1);
    Linkman C=session.get(Linkman.class,3);
    X.getSetLinkman().add(C);
    

    (2)一对多的里面,可以让其中一方放弃维护,用以提高效率。一般让一放弃维护,多的维护
    (3)具体实现放弃维护
    set标签中的inverse属性:放弃true,不放弃false(默认)

    <set name="setLinkman" inverse="true" cascade="save-update,delete">
    
    6.2.2 多对多表
    1. 多对多映射配置
      (1)创建实体类,用户和角色
      Person.java
    package cn.wanxp.entity;
    import java.util.HashSet;
    import java.util.Set;
    public class Person {
        public Integer getPid() {
            return pid;
        }
        public void setPid(Integer pid) {
            this.pid = pid;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Set<Role> getSetRole() {
            return setRole;
        }
        public void setSetRole(Set<Role> setRole) {
            this.setRole = setRole;
        }
        private Integer pid;
        private String name;
        private Set<Role> setRole = new HashSet<Role>();
    }
    

    Role.java

    package cn.wanxp.entity;
    import java.util.HashSet;
    import java.util.Set;
    public class Role {
        public Integer getRid() {
            return rid;
        }
        public void setRid(Integer rid) {
            this.rid = rid;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Set<Person> getSetPerson() {
            return setPerson;
        }
        public void setSetPerson(Set<Person> setPerson) {
            this.setPerson = setPerson;
        }
        private Integer rid;
        private String name;
        private Set<Person> setPerson = new HashSet<Person>();
    }
    
    

    (2)让两个实体类之间相互表示
    ①用户里表示所有角色,使用set集合
    ②一个角色有多个用户,使用set集合
    (3)配置映射
    ①基本配置
    ②配置多对多关系
    person.hbm.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
    <hibernate-mapping>
         <class name="cn.wanxp.entity.Person" table="t_person">
             <id name="pid" column="pid">
                <generator class="native"></generator>
             </id>
             <property name="name" column="name"></property>
             <!-- 在客户映射文件中,表示所有联系人,使用set标签表示所有联系人 
                    set标签里面有name属性:属性值写在客户实体类里面表示联系恶人的set集合名称
                    table:第三张表名
             -->
             <set name="setRole" table="t_person_role" cascade="all">
                <!-- 一对多建表,有外键。hibernate机制:双向维护外键,在一和多都有配置外键 
                    key属性 column当前映射文件在第三张表的外键名称
                -->
                <key column="person_id"></key>
                <!-- 一对多建表,有外键。hibernate机制:双向维护外键,在一和多都有配置外键 
                    many-to-many属性 column值Role在第三张表的外键名称
                -->         
                <many-to-many class="cn.wanxp.entity.Role" column="role_id" />
             </set>
         </class>
    </hibernate-mapping>
    

    role.hbm.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping SYSTEM "hibernate-mapping-3.0.dtd" >
    <hibernate-mapping>
         <class name="cn.wanxp.entity.Role" table="t_role">
             <id name="rid" column="rid">
                <generator class="native"></generator>
             </id>
             <property name="name"  column="name"></property>
             <!-- 在客户映射文件中,表示所有联系人,使用set标签表示所有联系人 
                    set标签里面有name属性:属性值写在客户实体类里面表示联系恶人的set集合名称
             -->
             <set name="setPerson" table="t_person_role" cascade="all">
                <!-- 
                key属性 column当前映射文件在第三张表的外键名称
                -->
                <key column="role_id"></key>
                <!-- 一对多建表,有外键。hibernate机制:双向维护外键,在一和多都有配置外键 
                    many-to-many属性 column值Person在第三张表的外键名称
                -->  
                <many-to-many class="cn.wanxp.entity.Person" column="person_id"/>
             </set>
         </class>
    </hibernate-mapping>
    

    --在用户里表示所有角色,使用set标签
    --在角色里表示所有用户,使用set标签
    (4)核心配置中引入配置文件
    2)多对多级联保存

    public void testManyToManyAdd() {
      SessionFactory sessionFactory = null;
      Session session = null;
      Transaction tx = null;
      try {
        sessionFactory = HibernateUtils.getSessionFactory();
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        //创建对象
        Person p1 = new Person();
        Person p2 = new Person();           
        p1.setName("张三");
        p2.setName("李四");
        
        Role r1 = new Role();
        Role r2 = new Role();
        Role r3 = new Role();
        r1.setName("肉坦");
        r2.setName("输出");
        r3.setName("辅助");
        
        //关联对象
        p1.getSetRole().add(r1);
        p2.getSetRole().add(r2);
        p1.getSetRole().add(r3);
    
        //保存对象
        session.save(p1);
        session.save(p2);
          
        tx.commit();
      }catch(Exception e) {
        e.printStackTrace();
        tx.rollback();
      }finally {
        session.close();
        sessionFactory.close();
      }
    }
    

    效果如下

    hibernate-many-to-many-add
    3)多对多级联删除
    删除方式同一对多删除
    4)维护第三张表关系
    用户表添加角色 搜索用户表,搜索角色表,在用户表中添加角色,如p1.getSetRole().add(r5);
    用户表删除角色 搜索用户表,搜索角色表,在用户表中删除角色,如p1.getSetRole().remove(r2);

    7 hibernate 查询方式

    7.1 对象导航查询

    如一对多表格 客户与联系人,根据某个id查询 客户以及下面的联系人
    先按照id搜索客户,然后获取set集合即可

    Customer customer = session.get(Customer.class , 1);
    Set<Linkman> setLinkman = customer.getSetlinkman();
    

    7.2 OID查询

    根据id查询某一条记录
    按照id搜索客户

    Customer customer = session.get(Customer.class , 1); 
    

    7.3 hql查询

    Query对象,写hql语句查询
    hql与sql类似
    区别:hql操作实体类和属性,sql操作数据库表和字段
    过程:创建Query对象,写hql语句 ,调用Query对象的方法获得结果

    7.3.1 查询所有
    //from 实体类名称
    Query query = session.createQuery("from Customer");
    //调用方法得到结果  
    List<Customer> list = query.list();
    
    7.3.2 条件查询
    //from 实体类名称 where 实体类属性名称=? [and 实体类属性名称=? ...] 或者 from 实体类名称  实体类属性名称 like ?
    Query query = session.createQuery("from Customer c where c.cid=? and c.customerName=?"); 
    //问好问号位置从0开始
    query.setParameter(0,1);
    query.setParameter(1,"百度");
    //调用方法得到结果  
    List<Customer> list = query.list();
    
    7.3.3 排序查询
    //在上面基础上 加入 order by 实体类属性名称 desc|asc   (desc 降序,asc 升序) 
    Query query = session.createQuery("from Customer c where c.cid=? and c.customerName=?" order by c.cid desc); 
    
    7.3.4 分页查询
    Query query = session.createQuery("from Customer");
    //设置起始位置
    query.setFirstResult(0);
    //设置每页记录数量
    query.setMaxResult(3);
    //调用方法得到结果  
    List<Customer> list = query.list();
    
    
    7.3.5 投影查询

    sql:select customerName from Customer; --查询部分字段而不是所有字段

    Query query = session.createQuery("select customerName from Customer");
    list<Object> list = query.list();//注意这里的区别
    
    7.3.6 聚集函数使用

    常用count sum avg max min

    //hql:select count(*) from 实体类名   
    Query query = session.createQuery(" select count(*) from Customer"); 
    Object obj = query.uniqueResult();
    
    

    7.4 QBC查询

    1)使用hql需要写hql语句,但使用qbc是不需要写语句,只需要方法就行
    2)使用qbc操作实体类和属性
    3)使用Criteria对象进行操作

    7.4.1 查询所有
    //创建Criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    //调用Criteria对象的方法
    List<Customer> list = criteria.list();
    
    7.4.2 条件查询
    //创建Criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    //调用Criteria对象的方法设置条件  
    //add方法添加条件,参数Restrictions对象的方法,方法里传入实体类属性和值
    criteria.add(Restrictions.eq("cid",1));
    List<Customer> list = criteria.list();
    
    7.4.3 排序查询
    //创建Criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    //调用Criteria对象的方法设置条件  
    //addOrder方法添加条件,参数Order对象的方法,方法里传入实体类属性asc升序desc降序
    criteria.addOrder(Order.asc("cid"));
    List<Customer> list = criteria.list();
    
    7.4.4 分页查询
    //创建Criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    //调用Criteria对象的方法设置条件  
    //setFirstResult(0)起始位置0,setMaxResult(3)获得3条记录
    criteria.setFirstResult(0);
    criteria.setMaxResult(3);
    List<Customer> list = criteria.list();
    
    7.4.5 统计查询
    //创建Criteria对象
    Criteria criteria = session.createCriteria(Customer.class);
    //调用Criteria对象的方法设置条件  
    criteria.setProjection(Projections.rowCount());
    Object obj = criteria.uniqueResult();
    Long lobj = (Long) obj
    int count = lobj.intValue();
    System.out.println(count);
    
    7.4.5 离线查询
    //创建DetachedCriteria对象
    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
    Criteria criteria = detachedCriteria.getExecutableCriteria(session);
    List<Customer> list = criteria.list();
    
    

    7.5 本地sql查询

    SQLQuery对象,使用普通sql实现

    8 多表查询

    8.1 内连接

    8.1.1 内连接

    sql语句:select * from t_customer as c inner join t_linkman as l on c.cid=l.lid;

    Query query = session.createQuery("from Customer c inner join c.setLinkman");
    //list()返回的Object对象的数字
    List list = query.list();
    
    8.1.2 迫切内连接

    1)与内连接底层是一样的
    2)区别:使用内连接返回list中每部分是数组,迫切内连接返回的是对象
    用法:加入关键字fetch

    Query query = session.createQuery("from Customer c inner join fetch c.setLinkman");
    //list()返回的Object对象的数字
    List list = query.list();
    

    8.2 左外连接

    8.2.1 左外连接

    sql语句:select * from t_customer as c left outer join t_linkman as l on c.cid=l.lid;

    Query query = session.createQuery("from Customer c left outer join c.setLinkman");
    //list()返回的Object对象的数字
    List list = query.list();
    
    8.2.2 迫切左外连接

    效果用法区别与内连接类似

    8.3 右外连接

    8.3.1 右外连接

    sql语句:select * from t_customer as c right outer join t_linkman as l on c.cid=l.lid;

    Query query = session.createQuery("from Customer c right outer join c.setLinkman");
    //list()返回的Object对象的数字
    List list = query.list();
    
    8.3.2 迫切右外连接

    效果用法区别与内连接类似

    9 hibernate检索策略

    9.1 立即查询

    如根据id查询,调用get方法时,一调用get方法立即发送查询语句给数据库

    9.2 延迟查询

    如根据id查询,调用load方法时,调用load方法,不会立即发送查询语句给数据库,只有得到对象里面的值时才会发送查询语句
    分类:类级别延迟,关联级别延迟

    9.2.1 类级别延迟

    就是上面那种

    9.2.2 关联类级别延迟

    如查询Customer时,是否延迟查询关联的Linkman

    默认状态

    Customer customer = session.get(Customer.class , 1);
    //执行到这里时,只发送了查询表t_customer
    Set<Linkman> setLinkman = customer.getSetlinkman();
    //执行到这里时,只发送了查询表t_customer
    System.out.println(list.size());//执行到这里将会发送查询t_linkman表命令
    

    修改延迟
    在set标签上修改属性
    fetch :值select
    lazy:值
    ----true:延迟,默认
    ----false:不延迟
    ----extra:极其延迟,要什么值就去查什么值

    10 批量查询

    如获取所有客户的联系人
    方式1 普通方式,效率较低

    //下面这种方式经过测试效率不高,因为每次查询一条客户再查询联系人都要发送查询命令
    Criteria criteria =session.createCriteria(Customer.class);   
    List<Customer> list = criteria.list();
    for(Customer customer:list){
      Systerm.out.println(customer.getId());
      Set setLinkman =customer.getSetLinkman();
      for(Linkman linkman : setLinkman){
        System.out.println(linkman.getId());
      }
    }
    

    方式2 修改配置Customer文件 ,在set标签中加入属性batch-size,batch-size的值只要是整数即可,其值越大,发送的语句命令越少,效率越高

    <set name = "setLinkman" batch-size="2">  
    

    相关文章

      网友评论

          本文标题:Hibernate笔记

          本文链接:https://www.haomeiwen.com/subject/uuadgxtx.html