Hibernate笔记

本文深入探讨Hibernate框架的基础知识,包括配置、实体类操作、缓存机制、事务管理等内容,并讲解了一对多、多对多关系的配置及级联操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重点内容jdbc
JDBC 的优点
干净整洁的 SQL 处理
大数据下有良好的性能
对于小应用非常好
易学的简易语法

JDBC 的缺点
大项目中使用很复杂
很大的编程成本
没有封装
难以实现 MVC 的概念

查询需要指定 DBMS

第一个问题,如果我们开发了几页代码或应用程序后,
需要修改数据库的设计怎么办?
第二个问题,在关系型数据库中加载和存储对象时我们要面临以
下五个不匹配的问题。
不匹配 描述
粒度 有时你将会有一个对象模型,该模型类的数量比数据库中关联的表的数量更多
继承 RDBMSs 不会定义任何在面向对象编程语言中本来就有的继承
身份 RDBMS 明确定义一个 ‘sameness’ 的概念:主键。然而,Java 同时定义了对象判等(a==b)和 对象值判等(a.equals(b))
关联 面向对象的编程语言使用对象引用来表示关联,而一个 RDBMS 使用外键来表示对象关联
导航 在 Java 中和在 RDBMS 中访问对象的方式完全不相同

Object-Relational Mapping (ORM) 是解决以上所有不匹配问题的方案。

orm:在关系型数据库和java,C#中转换数据的技术

Hibernate 优势

Hibernate 使用 XML 文件来处理映射 Java 类别到数据库表格中,并且不用编写任何代码。
为在数据库中直接储存和检索 Java 对象提供简单的 APIs。
如果在数据库中或任何其它表格中出现变化,那么仅需要改变 XML 文件属性。
抽象不熟悉的 SQL 类型,并为我们提供工作中所熟悉的 Java 对象。
Hibernate 不需要应用程序服务器来操作。
操控你数据库中对象复杂的关联。
最小化与访问数据库的智能提取策略。
提供简单的数据询问。

配置对象

配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。配置对象提供了两种基础组件。

数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.properties 和 hibernate.cfg.xml。
类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

SessionFactory 对象
配置对象被用于创造一个 SessionFactory 对象,使用提供的配置文件为应用程序依次配置 Hibernate,并允许实例化一个会话对象。SessionFactory 是一个线程安全对象并由应用程序所有的线程所使用。
SessionFactory 是一个重量级对象所以通常它都是在应用程序启动时创造然后留存为以后使用。每个数据库需要一个 SessionFactory 对象使用一个单独的配置文件。所以如果你使用多种数据库那么你要创造多种 SessionFactory 对象。
Session 对象
一个会话被用于与数据库的物理连接。Session 对象是轻量级的,并被设计为每次实例化都需要与数据库的交互。持久对象通过 Session 对象保存和检索。
Session 对象不应该长时间保持开启状态因为它们通常情况下并非线程安全,并且它们应该按照所需创造和销毁。
Transaction 对象
一个事务代表了与数据库工作的一个单元并且大部分 RDBMS 支持事务功能。在 Hibernate 中事务由底层事务管理器和事务(来自 JDBC 或者 JTA)处理。
这是一个选择性对象,Hibernate 应用程序可能不选择使用这个接口,而是在自己应用程序代码中管理事务。
Query 对象
Query 对象使用 SQL 或者 Hibernate 查询语言(HQL)字符串在数据库中来检索数据并创造对象。一个查询的实例被用于连结查询参数,限制由查询返回的结果数量,并最终执行查询。
Criteria 对象

Criteria 对象被用于创造和执行面向规则查询的对象来检索对象。

hibernate
一、入门和基本操作
1.web内容回顾
(1)javaee三层架构
dao层 hibernate
service层(业务逻辑层) spring
web层 struts2
(2)mvc思想(不是java独有的,)
model(模型)
view(视图)
control(控制器)
2.hibernate概述
什么是框架?
使用框架之后,帮我i们实现部分代码,
什么是hibernate框架(重点)
(1)应用于dao层的框架
(2)使用hibernate实现crud操作,hibernate底层代码是jdbc,对jdbc进行封装,
不需要写复杂的jdbc代码,不需要写sql语句。
(3)开源的,轻量级的框架
(4)hibernate版本:
hibernate3.X
hibernate4.X
hibernate5.X(学习)
orm思想:
(1)hibernate使用orm思想对数据库进行crud操作。
(2)在web学习阶段,javabean,正确叫法 实体类。
Object relation mapping对象关系映射
(1)让实体类和数据库表一一对应
实体类和数据库表
类中的属性和表中的列
(2)不需要直接操作数据库,而操作表对应的实体类

例如:
    jdbc:
    //加载驱动  
    Class.forname("com.mysql.jdbc.Driver");
        //建立连接
                    Connection conn = 
                        DriverManager.getConnection(url,username,password);
                    //对sql进行预编译
                        PrepareStatement pstmt = conn.prepareStatement(sql);
                    //执行sql
                        ResultSet rs = pstmt.executeQuery();
                    //遍历结果集
                    //释放资源

                orm:
                    (1):实体类创建
                        public class User{
                            private int uid;
                            private String username;
                            private String password;
                            //set get;
                        }
                    (2):建表:
                        create table user(
                            uid int,
                            username varchar2(10),
                            password varchar2(10)
                        );
                    (3)让实体类和表一一对应
                            使用配置文件完成

                        不需要操作表,而表对应的实体类对象就可以了
                        hibernate封装的对象,Session
                        //创建实体类对象,
                        User user = new User();
                        user.setUsername("张三");
                        session.save(user);
    3.hibernate入门
        搭建hibernate环境
            创建项目(java/web)
            (1)导入hibernate的jar包
                lib下边的required
                entity-manager的jar包
                hibernate本身没有支持的日志信息jar包,需要导入
                mysql驱动jar包
            (2)创建实体类:User
                hibernate中要求属性有一个唯一值,
                private int uid;
                private String username;
                private String password;
                //set get;

                使用hibernate时,不用创建表,他可以自动创建表
            *(3)建表:
                create table user(
                    uid int,
                    username varchar2(10),
                    password varchar2(10)
                );
            (4)配置实体类和数据库表一一对应关系
                配置文件:
                    <1>创建xml格式的配置文件
                        映射配置文件名称和位置没有固定要求,
                        建议在实体类包中创建 实体类.hbm.xml文件
                        User.hbm.xml
                    <2>在xml中引入约束
                        dtd
                        shema
                        在hibernate中引入dtd的约束
                            hibernate-mapping.dtd中找到约束,复制
                    <3>配置:
                        创建核心配置文件
                        核心配置文件格式也是xml,位置是固定的,
                            1.src下面创建hibernate.cfg.xml
                            2.导入dtd约束
                            3.hibernate在操作过程中只会加载核心配置文件,其他配置文件不会加载。
                        <hibernate-configuration>
                            <session-factory>
                                <!--配置数据库信息(必须)-->
                                    //hibernate.property文件
                                    <property name="driver">com.mysql.jdbc.Driver</>
                                    <property name="uri">jdbc:mysql://hibernate_day01</>
                                    <property name="username">mclhn</>
                                    <property name="password">199526</>

                                <!--配置hibernate信息(可选)-->
                                    <!--输出底层sql语句-->
                                    <property name="hibernate.show_sql">true</>
                                    <!--输出底层sql语句格式-->
                                    <property name="hibernate.format_sql">true</>
                                    <!---hibernate帮助创建表,需要配置之后
                                        update:如果已经有表,更新,如过没有,创建
                                    ->
                                    <property name="hibernate.hbm2ddl.auto">update</>
                                    <!--配置数据库方言
                                        例如:在mysql里面实现分页,关键字limit,只能用在mysql中
                                        在oracle中,实现分页rownum
                                        让hibernate识别不同数据库里边自己特有的语句
                                    -->
                                    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</>

                                <!--配置映射文件信息到核心文件-->
                                <mapping resource="com/mc/entity/User.hbm.xml"></>
                            </session-factory>
                        </hibernate-configuration>
                        创建映射配置文件
                        <hibernate-mapping>
                            <!--配置类和表对应
                                name中写实体类的全路径
                                table数据库表名
                                -->
                            <class name="com.mc.test.User" table="t_user">
                                <!--配置实体类属性和表中的列对应
                                hibernate要求实体类有一个唯一值
                                并要求数据库中的表有一个唯一值-->
                                <id name="uid" column="uid">
                                    <!--设置数据库id增长策略(比如主键自增)-->
                                    <generator class="native"></generator>
                                </id>
                                <!--配置其他属性
                                    name表示实体类中的属性
                                    column表示表中的列-->
                                <property name="username" column="username"></property>
                                <property name="password" column="password"></property>
                            </class>
                        </hibernate-mapping>
                测试:
                    创建类:HibernateDemo{
                        @Test
                        public void testAdd(){
                            //实现添加操作:
                        //第一步:加载hibernate核心配置文件
                            //到src下面找hibernate.cfg.xml,在hibernate中封装对象
                            Configuration cfg = new Configuration();
                            cfg.configure();
                        //第二步:创建SessionFactory对象
                            //读取hibernate核心配置文件内容,创建sessionFactory
                            //在创建过程中,根据映射关系,在配置数据库里边创建表
                            SessionFactory sessionFactory = cfg.buildSessionFactory
                        //第三步:使用SessionFactory对象创建session对象
                            //类似于链接(封装)
                            Session session = sessionFactory.openSession();
                        //第四步:开启事务
                            Transaction tx = session.beginTransaction();
                        //第五步:写具体逻辑crud
                            //添加功能
                            User user = new User();
                            user.setUsername("zhansgan");
                            user.setPassword("12344");
                            session.save(user);
                        //第六步:提交事务
                            tx.commit();
                        //第七步:关闭资源
                            session.close();
                            sessionFactory.close();
                        }
                    }
                    结果:1.是否创建表
                           2.是否插入数据
    4.配置文件(详解)
        映射配置文件:
            1.配置文件名和文件位置没有固定要求
            2.映射配置文件中,标签name属性写的是实体类属性
                (1)Class标签name属性值写实体类全路径
                (2)id标签property标签name属性值写实体类属性名称
            3.id标签和property标签,column属性可以不写,不写以后默认值和name一样
            4.在property标签中,type属性,设置生成表字段的类型,但hibernate会自动生成
        核心配置文件:
            1.根标签(hibernate-configuration)下边还有一个标签(session-factory)
            2.配置三部分要求:
                (1)数据库部分必须
                (2)hibernate部分可选
                (3)映射文件必须
            3.核心配置文件名和位置固定
                (1)位置src下边
                (2)名称:hibernate.cfg.xml
    5.api使用(hibernate核心api使用)
        1.Configuration
            Configuration cfg = new Configuration();
            cfg.configure();
            (1)到src下面找到hibernate.cfg.xml配置文件,创建对象,把配置文件放到对象里面(加载核心配置文件)
        2.SessionFactory(重点)
            1.使用configuration对象创建sessionFactory对象
                (1)创建sessionFactory对象过程中做事情(创建表。。。)
                    根据核心配置文件中,有数据库配置,有映射文件部分,到数据库里面根据映射关系创建表
            2.创建sessionfactory对象的时候,过程特别消耗资源
                在hibernate操作中,建议一个项目一般创建一个sessionfactory对象
            3.具体实现
                (1)写工具类,写静态代码块实现
                    静态代码块在类加载的时候执行,并且只执行一次
                    HibernateUtils{
                        static Configrucation cfg = null;
                        static SessionFactory sessionFactory = null;
                        //静态代码块实现
                        static{
                            //加载核心配置文件
                            cfg = new Configuration();
                            cfg.configure();
                            sessionFactory = cfg.buildSessionFactory();
                        }
                        //提供方法返回sessionFactory
                        public static SessionFactory getSessionFactory(){
                            return sessionFactory;  
                        }
                    }
        3.Session(重点)
            特点:
                1.session类似于jdbc中的connection,
                2.通过调用session中的不同方法来实现crud操作
                    (1)添加save()方法
                    (2)修改update()方法
                    (3)删除delete()方法
                    (4)查询
                3.session对象是一个单线程对象
                    (1)session对象不能共用,只能自己使用
        4.Transaction
            1.事务对象
            Transaction tx = session.beginTransaction();
            2.事务提交和回滚
            tx.commit();
            tx.rollback();
            原则性,一致性,隔离性,持久性

二、概念,api
    1.实体类的编写规则
        (javaBean)规范:
        (1)属性是private
        (2)属性都有public修饰的get/set方法
        (entity)特有规范:
        *(3)要求有一个唯一值属性,例如uid
        *(4)实体类中的属性建议不使用基本数据类型,而是使用对应的包装类类型
            <1>八个基本数据类型对应的包装类
                int-------integer
                char------Character
                其他的都是首字母大写
            <2>比如表示学生的分数   int score;
                假如学生考了零分,,int score=0;
                但是如果没有参加考试上述不能表示
                    解决:使用包装类可以,Integer score = 0;
                        没有参加考试:Integer score = null;
    2.hibernate主键生成策略
        (1)主键生成策略:hibernate要求实体类中有一个属性作为唯一值,对应表主键,主键可以有不同的生成策略
        (2)hibernate主键生成策略有很多值
            <!--设置数据库id增长策略(比如主键自增)-->
            <generator class="native"></generator>
        (3)在class属性里边有值
            主要记住native和uuid
            increment:每次增量为一
            identity:条件是数据库支持自动增长(oracle不支持自动增长,mysql支持)
            sequence:序列生成标识符,要求数据库1支持序列(oracle支持,mysql不支持)
            native:根据使用的数据库自动帮你选择合适的产生自增长的值,
            uuid:之前需要手写uuid,hibernate可以自动生成
                演示生成策略uuid:
                    <1>使用uuid生成策略,实体类属性不能是int,因为uuid可能是字符串等。
                        private String uid;
                        生成get/set
                        <generator class="uuid"></generator>
                        生成的uid是一个非空主键,不是自动增长,但会添加值
    3.实体类操作
        (1)对实体类的crud操作
            添加操作:
                User user = new User();
                user.setUsername("zhansgan");
                user.setPassword("12344");
                session.save(user);
            根据id进行查询:
                public void testGet(){
                    //1.调用工具类得到sessionFactory
                    SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                    //2.获取session
                    Session session = sessionFactory.OpenSession();
                    //3.开启事务
                    Transaction tx = session.beginTransaction();
                    //4.根据id查询
                    //调用session里边的get方法
                    //第一个参数:实体类的class
                    //第二个参数:id值
                    User user = session.get(User.class,1);
                    System.out.println(user);
                    //5.提交事务:
                    tx.commit();
                    //6.关闭资源
                    session.close();
                    sessionFactory.close();
                }
            修改:先查再改
                (1)先根据id查询
                (2)修改
                public void updateTest(){
                    //1.调用工具类得到sessionFactory
                    SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                    //2.获取session
                    Session session = sessionFactory.OpenSession();
                    //3.开启事务
                    Transaction tx = session.beginTransaction();
                    //4.修改(uid=2)
                        //调用session里边的get方法
                        //第一个参数:实体类的class
                        //第二个参数:id值
                        User user = session.get(User.class,2);
                        //向user对象中修改
                        user.setUsername("mmm");
                        //调用session的方法进行修改
                        //到user对象中找到id,对user对象进行修改
                        session.update(user);

                    //5.提交事务:
                    tx.commit();
                    //6.关闭资源
                    session.close();
                    sessionFactory.close();
                }
                删除:
                    调用session中的delete方法
                    public void deleteTest(){
                        //1.调用工具类得到sessionFactory
                        SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                        //2.获取session
                        Session session = sessionFactory.OpenSession();
                        //3.开启事务
                        Transaction tx = session.beginTransaction();
                        //4.删除
                            //调用session里边的get方法
                            //第一个参数:实体类的class
                            //第二个参数:id值
                            User user = session.get(User.class,2);
                            //向user对象中修改
                            user.setUsername("mmm");
                            //调用session的方法进行修改
                            //方法一:到user对象中找到id,对user对象进行删除
                            session.delete(user);
                            //方法二:User user = new User();
                            user.setUid(3);
                            session.delete(user);
                        //5.提交事务:
                        tx.commit();
                        //6.关闭资源
                        session.close();
                        sessionFactory.close();
                    }
        (2)实体类对象状态(概念)
            <1>实体类有三种状态
                1.瞬时态
                User u = new User();
                u.setUsername("jack");
                u.setAddress("dsadsa");
                在做处理之前没有id,对象和session没有关联
                2.持久态
                做了处理,有id值,和session有关联
                User user = session.get(User.class,1);
                3.托管态
                对象有id值,但是没有和session关联
            <2>演示操作实体类的方法
                //既能实现添加,也能实现修改
                saveOrUpdate(){
                    //1.添加
                    User u = new User();
                    u.setUsername("test");
                    u.setPassword("222");
                    //查找表中是否有这一列数据
                    //如果实体类状态是瞬时态,做添加操作,如果是托管态,做修改操作
                    //如果是持久态,做修改操作
                    session.saveOrUpdate(u);
                }
    4.hibernate一级缓存
        (1)什么是缓存?
            数据存到数据库中,数据库本身就是文件系统,使用流操作文件效率不是很高
            *将数据存到内存中,不需要使用流方式,就可以直接读取内存中的数据,
            *把数据放到内存中,提高读取效率。
        (2)hibernate缓存
            *hibernate框架中提供很多优化方法,缓存就是一个优化方法
            *hibernate缓存特点:
                1.hibernate一级缓存:
                    hibernate一级缓存默认打开的
                    hibernate一级缓存使用范围:
                        session的范围(开始创建到关闭)就是一级缓存范围
                    hibernate一级缓存中,存储数据必须是持久态数据
                2.hibernate二级缓存:
                    目前已经不适用了,替代技术:redis
                    二级缓存默认不是打开的,需要配置打开
                    二级缓存使用范围,是sessionFactory范围
        (3)验证一级缓存的存在
            *1首先根据uid=1查询,返回对象
            *2再根据uid=1查询,返回对象(不会查数据库,而是去一级缓存查询)
            testCash(){
                //根据uid=6查询
                //执行第一个get方法是否查询数据库,是否发送sql语句
                User user1 = session.get(User.class,6);
                System.out.println(user1);
                //再根据uid=6查询
                //是否发送语句
                User user2 = session.get(User.class,6);
                System.out.println(user2);
            }
            结论:一级缓存,首次查询时,会查询数据库,发送sql语句,之后不会发送语句
        (4)一级缓存的执行过程
            首先查询一级缓存,发现没数据,返回user1对象(持久态),
            其次,把user1持久态对象反放到一级缓存中
            下次执行get操作时,发现一级缓存有相同的数据,直接返回。
        (5)一级缓存,持久态会自动更新数据库
            在执行时可以不写update方法,就可以执行update操作
        day02——11
    5.hibernate事务操作
        (1)事务代码规范写法(重点掌握)
        事务相关概念:
            事务:一组操作,要么都成功,要么都失败
            特性:原子性,一致性,隔离性,持久性
            产生的度的问题:read committed(oracle默认)
                            repeatable read(mysql默认隔离级别)
                            serializable(oracle默认)
        (2)在hibernate核心配置文件第二部分也可以自主设置事务的隔离级别
            <!--
                1
                2
                4
                8
            -->
            <property name="hibernate.connection.isolation">4</>
        (3)代码规范:
            try(){
                开启事务
                提交事务
            }catch(){
                回滚事务
            }finally{
                关闭连接
            }
            public void testTest(){
                SessionFactory sessionFactory = null;
                Session session =null;
                Transaction tx = null;
                try{
                    sessionFactory = HibernateUtils.getSessionFactory();
                    session = sessionFactory.openSession();

                    tx = session.beginTransaction();
                    //业务处理
                    tx.commit();
                }catch(){
                    tx.rollback();
                }finally{
                    session.close();
                    sessionFactory.close();
                }
            }
        *(4)hibernate绑定session
            因为session是单线程的,但是有时候我们需要多个session,
            1.session类似于jdbc中的connection,之前web阶段学过的ThreadLocal(和本地线程进行链接)
            2.hibernate帮我们实现了与本地线程绑定session(底层就是ThreadLocal)
            3获取与本地线程链接:、
                (1)在hibernate核心配置文件中配置
                    在核心配置文件第二部分:
                        <!--配置与本地连接的session-->
                        <property nmae="hibernate.current_session_context_class">thread</>
                (2)调用sessionFactory里边的方法得到
                    在hibernateUtils工具类中写方法,调用getCurrentSession()方法
                    public static Session getSessionObject(){
                        return sessionFactory.getCurrentSession();
                    }
                *(3)注意,获取与本地绑定session时,关闭session报错,不需要手动关闭了。

    6.hibernate其他的api(查询)
        MYSQL查询:
            全部查询    select * from table;                        
            条件查询    select * from table where username= =?;
            模糊查询    select * from table where username like ?;
            分页查询    select * from table limit ?,?;
        hibernate中的api对象:(查询)
            *query对象
                (1)使用query对象,里边不需要写SQL语句,但是写hql语句
                    *hql:hibernate query language,hibernate提供的一种查询语言
                        和SQL很相似
                        sql:操作的是数据库中的表和字段
                        hql:操作的是实体类和实体类中的属性
                (2)查询所有
                    from后面加实体类的名字:
                (3)query对象的使用
                    1.创建query对象
                    2.调用query对象里的方法得到结果
                类HibernateQueryDate{
                    try{
                        //session中有创建query的方法,括号中的参数写hql语句
                        Query query = session.createQuery("from User");
                        //query中的list方法可以查询出数据库中所有的数据,返回list集合
                        List<User> list = query.list();
                    } 
                }
            *Criteria对象
                也能实现上述功能,但是使用时不需要写hql语句,只需要调用方法。
                    try{
                    (1)创建Criteria对象
                        Criteria criteria = session.createCriteria(User.class);
                    (2)调用方法得到结果
                        List<User> list = criteria.list();
                    }
            *SQLQuery对象
                (1)使用hibernate时候,调用底层SQL实现
                (2)实现过程
                    try{
                        1.创建对象
                        SQLQuery sqlquery = session.createSQLQuery("select * from t_user");
                        2.调用方法得到结果(默认返回的list中的每部分是一个数组)
                        /*
                        List<Object[]> list = sqlquery.list();
                        for(Object[] obj:list){
                            System.out.println(Arrays.toString(obj));
                        }
                        */
                        可以设置SQLquery将数据放入那种类型,然后调用list方法
                        sqlquery.addEntity(User.class);
                        List<User> list = sqlquery.list();
                    }
三、配置(一对多,多对多)
    1.表和表之间的关系:
        一对多
            (1)分类和商品的关系,一个分类中有多个商品,一个商品只属于一个分类
            (2)客户和联系人是一对多的关系(一个客户有多个联系人,一个联系人只能属于一个客户)
                客户:和公司有业务往来的·
                联系人:公司里边的员工,比如百度里边可以有很多员工,联系员工就可以联系到百度
                外键建立关系:在多的一方创建,指向一的一方的主键
        多对多、
            (1)订单和商品关系,一个订单有多个商品,一个商品可以对应多个订单。
            (2)用户和角色:
                用户:小王,小马,小宋
                角色:总经理,秘书,司机,保安
                比如:小王可以是总经理,也可以是司机。
                        小马可以是秘书,可以是总经理
                一个用户可以有多个角色,一个角色可以有多个用户
                建表:
                    创建第三张表来维护关系,至少要有两个字段作为外键,来表示两个表的主键
        一对一
            (1)在中国,一夫一妻制
    2.hibernate一对多:
        一对多配置映射
            以客户和联系人为例(客户是一,联系人是多):
            1.创建实体类,客户和联系人
            2.让两个实体类之间互相表示
                //一个客户多个联系人
                //但是hibernate中要求使用集合表示多的时候,
                //使用set而不是list(set无序并且不重复)
                private Set<LinkMan> setLinkman = new HashSet<LinkMan>();
                public Set<LinkMan> getSetLinkman() {
                    return setLinkman;
                }
                public void setSetLinkman(Set<LinkMan> setLinkman) {
                    this.setLinkman = setLinkman;
                }
                //一个联系人只对应一个客户:
                private Customer customer;

                public Customer getCustomer() {
                    return customer;
                }
                public void setCustomer(Customer customer) {
                    this.customer = customer;
            3.配置映射文件
                将最基本的配置完
                在映射文件中,配置一对多
                    hibernate有种机制,默认双方都要配置外键
                    (1)在客户映射文件中表示所有联系人
                        <set name="setLinkman">
                            <key column="clid"></key>
                            <!-- 表示客户所有联系人的全路径 -->
                            <one-to-many class="com.mc.test.entity.LinkMan"/>
                        </set>
                    (2)在联系人中表示所属客户
                        <!-- name属性,customer用户名
                            class customer全路径
                            column外键名称 -->
                        <many-to-one name="customer" 
                            class="com.mc.test.entity.Customer" 
                            column="clid">
                        </many-to-one>
            4.创建核心配置文件
                <!--配置映射文件信息到核心文件-->
                <mapping resource="dtd/Custom.hbm.xml"></mapping>
                <mapping resource="dtd/LinkMan.hbm.xml"></mapping>
        一对多级联操作
            级联删除:
                删除客户,客户连接的联系人也要删除
                1.删除某个客户,把客户里边的联系人也删除
                2.具体实现:在客户配置文件的set标签中添加
                    cascade="delete"
                3.在代码中直接删除客户:
                    (1)根据id查询对象,调用session里边的delete方法删除,
                        //根据id查询客户对象
                        Customer customer = session.get(Customer.class, 1);
                        //2.调用方法删除、
                        session.delete(customer);
                4.具体过程
                    (1)根据id查询客户
                    (2)根据外键的id值查询联系人
                    (3)把联系人的外键设置成null;
                    (4)删除联系人和客户
            级联保存:
                1.添加一个客户,为这个客户添加多个·联系人
                //添加一个客户,为这个客户添加多个·联系人
                //创建对象
                Customer cus = new Customer();
                cus.setCustName("ma");
                cus.setCustLevel("vip");
                cus.setCustMobile("111");
                cus.setCustRhone("999");
                cus.setCustSource("wangluo");

                LinkMan man = new LinkMan();
                man.setLkm_name("lisi");
                man.setLkm_phone("222");
                man.setLkm_gender("男");

                2.//在客户表示联系人,在联系人表示客户。
                //建立关系
                //把联系人添加到客户中
                Set<LinkMan> linkman = cus.getSetLinkman();
                linkman.add(man);
                //把客户添加到联系人中
                man.setCustomer(cus);
                //保存到数据库
                session.save(cus);
                session.save(man);
            简化写法:
                一般根据客户加联系人,
                (1)在客户的映射文件中添加属性:cascade="save-update
                    <set name="setLinkman" cascade="save-update">
                        <key column="clid"></key>
                        <!-- 表示客户所有联系人的全路径 -->
                        <one-to-many class="com.mc.test.entity.LinkMan"/>
                    </set>
                (2)创建对象,只需要把联系人放入对象中就可以了,最终只需要保存客户就可以了
                    Set<LinkMan> linkman = cus.getSetLinkman();
                    linkman.add(man);
                    //把客户添加到联系人中
                    man.setCustomer(cus);
                    //保存到数据库
                    session.save(cus);
        一对多修改操作(inverse属性):
            eg:修改联系人对应的客户,修改成其他客户
                //根据id查询出lucy,在查处客户id,查出联系人
                Customer customer = session.get(Customer.class, 1);
                LinkMan linkMan = session.get(LinkMan.class, 2);
                //2.设置持久态对象的值
                //把联系人放到客户里边
                customer.getSetLinkman().add(linkMan);
                linkMan.setCustomer(customer);
            *在hibernate执行上述代码时,update会执行两次,
                因为修改了两次外键(hibernate双向维护外键)
                就会造成性能重复浪费
                解决:让其中一方放弃维护外键
                    思想:一对多的数据库操作中,让一的一方放弃外键维护。
                具体实现:
                    在放弃关系维护的映射文件中进行配置:在set标签上添加inverse属性(true表示放弃)。
                <set name="setLinkman" cascade="save-update,delete" inverse="true">
                    <key column="clid"></key>
                    <!-- 表示客户所有联系人的全路径 -->
                    <one-to-many class="com.mc.test.entity.LinkMan"/>
                </set>
    3.hibernate多对多:
        多对多映射配置
            用户和角色为例:
            1.创建用户和角色实体类
            2.实体类间互相表示
                一个用户里有多个角色,使用set集合
                一个角色有多个用户,使用set集合
            3.配置映射关系
                (1)基本配置
                (2)配置多对多关系
                在用户里边显示所有角色,使用set标签(User.hbm.xml)
                <!-- name属性写的是set集合,
                    table属性写的是第三张表的名字 -->
                <set name="setRole" table="user_role">
                    <!-- key标签
                        column:配置当前映射文件在第三张表的外键名字 -->
                    <key column="userid"></key>
                    <!-- many:多对多
                        class: 角色实体类全路径
                        column:角色在第三张表外键名称-->
                    <many-to-many class="com.mc.test.entity.Role" column="roleid"></many-to-many>
                </set>
                在角色里边也使用set标签(Role.hbm.xml)
                <!-- name属性写的是set集合,
                    table属性写的是第三张表的名字 -->
                <set name="setUser" table="user_role">
                    <!-- key标签
                        column:配置当前映射文件在第三张表的外键名字 -->
                    <key column="roleid"></key>
                    <!-- many:多对多
                        class:用户实体类全路径
                        column:角色在第三张表外键名称-->
                    <many-to-many class="com.mc.test.entity.User" column="userid"></many-to-many>
                </set>
            4.在核心配置文件中引入映射文件
                <mapping resource="com/mc/test/mapping/User.hbm.xml"></mapping>
                <mapping resource="com/mc/test/mapping/Role.hbm.xml"></mapping>
        多对多级联操作:
            级联保存
                根据用户保存角色
                1.(简化操作)在用户文件中set标签上进行配置
                    cascade="save-update"
                2.(复杂操作)写代码实现
                    创建对象,把角色放到用户中,把用户放到角色中
                //建立关系
                user1.getSetRole().add(r1);
                user1.getSetRole().add(r2);

                user2.getSetRole().add(r2);
                user2.getSetRole().add(r3);

                session.save(user1);
                session.save(user2);
            级联删除(一般不用,因为删除时会将需要的部分也删除)
                1.在set标签上进行配置,
                    cascade="save-update,delete"
                2.删除用户
                    User user = session.get(User.class, 1);
                    session.delete(user);
        *用户和角色使用第三张表维护
            1用户和角色多对多关系,维护关系通过第三张表。
            2.让某个用户有某个角色

            3.让某个用户没有某个角色
四、hibernate查询操作
    hibernate中的查询方式:
        1.对象导航查询
            (1)(需求)根据id查询出某个客户,再查询出该客户下边的联系人。
            (2)实现代码:
                //查询cid==1的客户
                Customer customer = session.get(Customer.class, 1);
                //在查询客户中的联系人集合
                Set<LinkMan> linkman = customer.getSetLinkman();
                System.out.println(linkman.size()); 
        2.OID查询
            (1)根据id查询某一条记录,并以对象的方式返回
            (2)可以调用session里边的get方法进行查询
            //查询cid==1的客户
            Customer customer = session.get(Customer.class, 1);
        3.hql查询(hibernate query language)
            *在hibernate的api那一章有学习过。
            hql也支持给字段起别名
            (1)Query对象,写hql语句实现查询
                <1>查询所有:查询所有客户记录:from 实体类名称
                    //查询所有
                    Query query = session.createQuery("from Customer");
                    List<Customer> list = query.list();
                    for (Customer customer : list) {
                        System.out.println(customer);
                    }
                <2>条件查询:where and ,like
                    语句写法:
                        from 实体类名称 where 实体类属性名称=? and 实体类属性名称=?
                        from 实体类名称 where 实体类属性名称  like ?

                        query.setParameter(0, 1);
                        //第一个参数: ?的位置,第一个是0,第二个是1
                        //第二个参数:具体的查询条件值
                    模板一:
                        Query query = 
                            session.createQuery("from Customer where cid=? and custName=?");
                        //设置?里边的值、
                        //第一个参数: ?的位置,第一个是0,第二个是1
                        //第二个参数:具体的查询条件值
                        query.setParameter(0, 1);
                        query.setParameter(1, "mc");
                        //调用方法
                        List<Customer> list = query.list();
                        for (Customer customer : list) {
                            System.out.println(customer);
                        }
                    模板二(模糊查询):
                        Query query = 
                            session.createQuery("from Customer where custName like ?");
                        query.setParameter(0, "%m%");

                        //调用方法
                        List<Customer> list = query.list();
                        for (Customer customer : list) {
                            System.out.println(customer);
                        }
                <3>排序查询:order by
                    排序语句写法:from 实体类名称 order by 实体类属性名称 (asc/desc)
                    Query query = 
                        session.createQuery("from Customer order by cid asc");
                    应用场景:根据时间排序时,
                <4>分页查询:limit
                    MYSQL中实现分页用limit关键字 (第一个数是开始位置,第二个是每页的数据数)
                        select * from t_customer limit 0,3; 
                    在hql中,不能写limit,query对象中封装了两个方法进行分页
                    //查询所有
                    Query query = session.createQuery("from Customer");
                    //设置分页数据
                    //设置开始位置
                    query.setFirstResult(0);
                    //设置每页最大页数
                    query.setMaxResults(3);
                <5>投影查询:
                    sql:select custName from t_customer;
                    查找的是部分字段而不是所有字段
                    投影查询的hql查询语句
                        select 实体类中的属性名称1,实体类中的属性名称2 from 实体类名
                    Query query =
                            session.createQuery("select custName,cid from Customer");
                    //调用方法
                    List<Object[]> list = query.list();
                    for (Object[] obj : list) {
                        System.out.println(obj);
                    }

                <6>聚集函数使用:
                    常用的聚合函数:count sum avg max min
                    需求:知道表中记录数:
                        hql:select count(*) from 实体类名称
                        //查询所有
                        Query query =
                            session.createQuery("select count(*) from Customer");
                        //调用方法
                        Object result = query.uniqueResult();
                    *Object如果直接转换成int会报错,先转换long类型,再转换成int类型
                        Long a = (Long)result;
                        int count = a.intValue();
                        System.out.println(result);
            (2)常用的hql语句
        4.QBC查询(hibernate的API章节有介绍)
            (1)Criteria对象,不需要写语句。
                <1>查询所有:查询所有客户记录:
                    //创建对象
                    Criteria criteria = session.createCriteria(Customer.class);
                    //调用方法
                    List<Customer> list = criteria.list();
                    for (Customer customer : list) {
                        System.out.println(customer);
                    }
                <2>条件查询:
                    1.没有语句的书写
                    模式一:条件查询
                        Criteria criteria = 
                            session.createCriteria(Customer.class);
                        //2.使用方法设置条件值
                        //使用add方法设置条件值
                        //在add方法里使用Restrictions类的方法实现添加
                            //方法中的第一个参数是类里边的属性,第二个填的是查询值
                        criteria.add(Restrictions.eq("cid", 1));
                        criteria.add(Restrictions.eq("custName", "mc"));
                        //调用方法
                    模式二:模糊查询
                        criteria.add(Restrictions.like("custName", "%c"));
                <3>排序查询:
                    1.创建对象
                    2.设置排序规则
                        Order是hibernate中的一个类
                        criteria.addOrder(Order.asc("cid"));
                <4>分页查询:
                    1.创建对象
                    2.设置分页数据,开始位置,每页记录数
                    criteria.setFirstResult(0);
                    criteria.setMaxResults(3);
                    *开始位置计算公式:
                        (当前页-1)*每页记录数
                <5>统计查询
                    用方法得到表中记录数
                    1.创建对象
                    2.调用方法查询数据
                        criteria.setProjection(Projections.rowCount());
                        //可以使用下面的方法得到
                        Object result = criteria.uniqueResult();
                        同样可以使用hql的转换方式进行转换类型
                <6>离线查询
                    不需要session也可以进行操作
                    使用对象
                    DetachedCriteria detachedcriteria = 
                            DetachedCriteria.forClass(Customer.class);
                    Criteria criteria = 
                            detachedcriteria.getExecutableCriteria(session);
                    List<Customer> list = criteria.list();
                    for (Customer customer : list) {
                        System.out.println(customer);
                    }
                    使用情况:
                        在servlet调用service方法,service调用dao层的方法,
                        在dao层进行crud操作,
                        在dao层使用hibernate框架,调用session
                        想要在service层进行离线拼接QBC时
        5.本地SQL查询
            (1)SQLQuery对象,使用普通SQL实现查询
        6.HQL多表查询:
            Mysql多表查询
                1.内连接
                    select * from t_customer c,t_linkman l
                    where c.cid=l.cLid;
                    或者:
                    select * from t_customer c inner join t_linkman l
                    on c.cid=l.cLid;
                2.外连接
                    左外连接:左边表中包含的所有数据,右边表的部分数据
                        select * from t_customer c left outer join t_linkman l 
                        on c.cid = l.cLid;
                    右外连接:左边表中部分,右边表的数据包含的所有数据
                        select * from t_customer c right outer join t_linkman l 
                        on c.cid = l.clid;
            HQL实现多表查询
                (1)内连接(inner join)
                    内连接查询的hql语句写法(客户-联系人):
                        from Customer c inner join c.setLinkMan
                        Query query = 
                            session.createQuery(
                                "from Customer c inner join c.setLinkman");
                (2)左外连接( left outer join)
                    返回的list中的值是数组
                    Query query = 
                        session.createQuery(
                            "from Customer c left outer join c.setLinkman");
                (3)右外连接
                    返回的list中的值是数组
                    Query query = 
                        session.createQuery(
                            "from Customer c right outer join c.setLinkman");
                (4)迫切内连接(inner join fetch)
                    底层实现是一样的,
                    区别是使用内连接返回的list内容是数组,迫切内连接返回的是对象
                    Query query = 
                            session.createQuery(
                                "from Customer c inner join fetch c.setLinkman");
                (5)迫切左外连接( left outer join fetch)
                    返回的list集合中的值是对象
                    Query query = 
                            session.createQuery(
                                "from Customer c left outer join fetch c.setLinkman");
        7.hibernate的检索策略
            概念分为两种:
                (1)立即查询:
                    根据id查询,调用get方法,一调用get方法马上发送语句查询数据库

                (2)延迟查询
                    根据id查询,调用get方法或者load方法,
                    一调用get方法马上发送语句查询,调用load方法不会马上发送语句查询数据库,
                    只有得到对象里边的值的时候才会查询数据库
            延迟查询分为两类:
                (1)类级别延迟
                    根据id查询实体类对象,使用load方法不会马上查询
                (2)关联级别延迟
                    查询某个客户,并查询所有联系人(对象导航查询),
                        判断是否需要延迟,这个过程就是关联延迟
            自己修改延迟方式:
                主要通过配置实现
                    到映射文件中进行配置,在User的配置文件中的set标签中设置两个属性
                        lazy(默认是true(延迟)/false/extra(极其懒惰))和
                        fetch(默认是select)
        8.hibernate中的批量抓取
            查询所有客户,返回list集合,遍历集合,得到每个客户,并得到每个客户下边的所有联系人
            对查询的次数做优化,减少查询次数
                在set标签中加入batch-size属性,值越大,发送的语句越少
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值