hibernate你必须知道的知识点(敲黑板,划重点)!

本文详细介绍了Hibernate的映射配置文件、核心配置文件、添加操作、API使用及主键生成策略等关键知识点,包括实体类的CRUD操作、事务管理、一级缓存机制、对象状态管理,以及各种查询方式。对于数据库的持久化操作,文章深入浅出地解析了Hibernate的实战应用。

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

ORM,object relation mapping 对象关系映射,底层是对JDBC的封装,来对数据库进行crud操作。

 

1.hibernate映射配置文件

 

    xxx.hbm.xml

    <引入dtd约束>

 

    <!--配置映射的实体类-->

    <class name="实体类全路径" table="数据库表名">

 

        <!--配置实体类的id类型字段,一般在数据库中作为主键的属性,native代表自增>

        <id name="实体类中id属性全名" column="数据库对应的字段名,一般和name一样即可">

            <generator class="native"></generator>    

        </id>

 

        <!--配置实体类其他属性-->

        <property name="实体类中属性名字" column="数据库中的字段名,一般和name一致即可"/>

    <class>

 

2.hibernate核心配置文件

 

放置于src下面,名字是hibernate.cfg.xml

 

<session-factory>

<!--配置数据库信息,四大参数-->

<property name="数据库驱动">com.mysql.jdbc.Driver</property>

<property name="...url">jdbc:mysql://localhost:3306/数据库名</property>

<property name="username">用户名</property>

<property name="passwrord">密码</property>

 

<!--配置hibernate信息-->

<!--输出底层的sql语句-->

<property name="hibernate.show_sql">true</property>

<!--格式化输出的sql语句-->

<property name="hibernate.format_sql">true</property>

<!--自动构建数据库表-->

<property name="hibernate.hbm2ddl.auto">update</property>

<!--配置数据库方言-->

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

 

<!--配置实体类映射文件-->

<mapping resources="实体类映射文件的全路径,把.改为/"/>

 

3.实现添加操作

 

第一步 加载核心配置文件

Configuration cfg = new Configuration();

cfg.configure();

第二部 创建SessionFactory对象

SessionFactory sessionFactory = cfg.buildSessionFactory();

第三部 通过SessionFactory对象创建Session

Session session = sessionFactory.openSession();

第四部 开启事务

Transaction tx = session.beginTransaction();

第五步 编写具体逻辑crud操作

User user = new User();

user.setSid(101);

user.setSname("霸天虎");

session.save(user);

第六步 提交事务

tx.commit();

第七部 关闭资源

session.close();//后打开的先关闭

sessionFactory.close();//先打开的后关闭

 

4.hibernate的核心api

Configuration

    1.读取src下的hibernate.cfg.xml配置文件

    2.读取实体类映射文件xxx.hbm.xml映射文件

    3.配置访问数据库的参数,驱动、url、username、password

    4.管理hibernate的配置信息

SessionFactory 

    1.使用Configuration的buildSessionFactory方法构建SessionFactory,在构建SessionFactory的时候会根据映射生成表;

    2.创建SessionFactory的过程特别消耗资源

        因此我们通常一个项目只创建一个SessionFactory,通过编写工具类,在工具类中的静态代码块构建SessionFactory,保证只有在类加载时会执行静态代码块创建SessionFactory的实例,然后对外提供静态的get方法,用来获取SessionFactory。

Session

    1.调用session中的方法对数据库进行crud操作

        添加 save()

        删除 delete()

        修改 update()

        根据id查询 get()

    2.session对象是单线程对象,不能供用,只能够自己使用。

Transaction

    事务涉及到的两个操作,commit()提交和rollback()回滚

    涉及到的四个特性

    原子性:多个操作绑定在一起,要么全部成功,要么全部失败;

    一致性:比如转账,事务成功或者失败前后,转账人资金和被转账人资金的总和是一致的;

    隔离性:事务之间是相互隔离的,一个事务的操作和数据不能和其他事物交互。

    持久性:事务提交完成之后,数据库中的数据改变必须是持久的。

 

5.主键生成策略

    <id name="实体类id属性名" column="数据库表中id字段名">

        <generator class="这个值有很多种"></generator>

        1.native:hibernate支持跨平台自动识别数据库,比如mysql和oracle的自增是不一样的,使用native字段可以自动识别;

        2.increment:自动增长,用于long、int、short类型生成的唯一标识,只有在没有其他进程向同一张表中插入数据时才能使用,集群下不要使用;

        3.sequence:序列,一般用于oracle、DB2等数据库;

        4.identity:支持自动增长的数据库,比如mysql,DB2;

        5.uuid:生成String类型的32位16进制的唯一标识。

 

6.实体类的crud操作

    1.添加

        User user = new User();

        user.setSid(101);

        user.setSname("大哥");

        session.save(user);

    2.根据id查询

        User user = session.get(User.class,101);

    3.修改

        User user = session.get(User.class,101);

        user.setSname("二哥");

        session.update(user);

    4.删除

        User user = session.get(User.class,101);

        session.delete(user);

 

7.hibernate实体类对象状态

    瞬时态

        对象没有id值,不在session的管理范围内

        一般执行save操作

    持久态

        执行save操作后,

        对象有id值,在session的管理范围内

        要注意,不一定在数据库中也有,执行save操作后,会先放到一级缓存中,事务提交后,会完成添加到数据库。

    托管态

        有id,但是不再session的管理范围内。他在内存中存在,只是session关闭后,hashmap(key存放OID,value存放指向内存中对象的引用)缓存也没了,指向这个对象的引用也关闭了。

 

8.hibernate一级缓存

    缓存特点:

        一级缓存:默认打开;

                         使用范围是session创建到关闭

                         存储的数据必须是持久态的

        二级缓存:目前不使用,使用redis替代

 

        特性:

                持久态会自动更称数据库

                当查询到持久态对象后,会保存在一级缓存和快照中,我们修改对象后,一级缓存中的对象改变,但是快照的对象没有改变,提交事务时会对比一级缓存中和快照的对象,如果不一致就会更新一级缓存中的对象到数据库。

 

9.hibernate绑定session,保证为本地单线程

    在hibernate.cfg.xml中配置

        <property name="hibernate.current_session_context_class">thread</property>

    调用sessionFactory方法返回与本地线程绑定的session;

    public static Session getSessionObject(){

        return sessionFactory.getCurrentSession();

    }

    绑定后的session不需要手动关闭;

 

10.hibernate的api使用

    Query对象,支持使用hql语句

    Query query = session.createQuery("from User");

    List<User> userlist = query.list();

 

    Criteria对象,支持使用方法

    Criteria criteria = session.createCriteria(User.class);

    List<User> userlist = criteria.list();

 

    SQLQuery对象,支持调用底层sql语句

    SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");

    SQLQuery返回的结果List中默认是数组形式的,可以通过调用addEntity(User.class)方法让它以对象形式返回;

    sqlQuery.addEntity(User.class);

    List<User> userlist = sqlQuery.list();

 

11.表和表之间的关系

    一对多:通过外键关联,在表中数据较多的一方建立外键;

    多对多:通过第三张表创建两个字段作为外键,分别指向两张表的主键;

 

12.hibernate的一对多操作

    首先建立以下情景:用户类User和银行卡类Card类,一个用户有多的银行卡,但是每个银行卡只能有一个用户。

    1.在用户的实体类中,使用set集合用来表示有多张银行卡

        Set<Card> cardSet = new HashSet<Card>;

        生成set和get方法;

    2.在银行卡的实体类中,使用一个用户对象来表示有一个用户

        User user = new User();

        生成set和get方法;

    3.在实体类映射文件user.hbm.xml和card.hbm.xml中进行配置

        user.hbm.xml

        <class name="user类的全路径" table="t_user">

            <id name="uid" column="uid>

                <generator class="native"></generator>

            </id>

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

            ...

            <set name="cardSet注意是用户实体类中set集合的属性名">

                <key column="cid"></key>

                    <one-to-many class="card实体类的全路径"></one-to-many>

            </set>

        </class>

 

        card.hbm.xml

        <class name="card类的全路径" table="t_card">

            <id name="cid" column="cid">

            ...

            ...

            <property ...></property>

            ...

            <many-to-one name="user" class="user类的全路径" column="uid"/>

        </class>

 

13.一对多级联操作

    1.级联保存

    新添加一个用户,为这个用户添加多张银行卡。

    同时操作两张表,就是级联操作。

    User user = new User();

    user.setUsername("大哥");

    

    Card card1 = new Card();

    card1.setCname("卡1");

 

    user.getCardSet.add(card1);

    card1.setUser(user);

 

    session.save(user);

    session.save(car1);

    

    2.级联删除

    删除一个用户,这个用户下的所有银行卡也都删除。

    1).在user.hbm.xml文件中的set标签内进行以下配置

    <set name="cardSet" cascade="delete">

    2).代码中即可直接删除用户

    User user = session .get(User.class,1);

    session.delete(user);

    底层是这样的:

    首先先根据id查询到用户,然后根据用户的外键查询到银行卡,将银行卡中的外键值全部设置为null,然后删除银行卡,删除用户。

    

    3).修改一张银行卡的所有者为另一个用户

    User user = session.get(User.class,2);

    Card card = session.get(Card.class,1);

 

    user.getCardSet.add(card);

    card.setUser(user);

    

    tx.commit();//持久太会自动更新数据库

 

    4).inverse属性

    因为hibernate是双向维护外键的,造成在修改银行卡对象时修改了一次外键,修改用户的时候又修改了一次外键,造成效率和性能问题。

    解决方法:

    令其中一方放弃外键维护。一般让一对多中一的那一方放弃维护外键,就比如,一个老师可能记不住所有学生,但是学生都能记住老师。

    在user.hbm.xml中配置,在set标签中使用Inverse属性

    <set name="cardSet" inverse="true">

    true的意思是确认放弃外键维护。

 

14.多对多操作

    1.多对多映射配置

    在两个实体类中均使用set集合作为外键关联;

    然后生成set和get方法。

    创建实体类映射文件,配置多对多关系

    情景:一个用户有多个角色,一个角色也有多个用户。

    在user.hbm.xml的class标签中添加set标签

    <set name="roleSet" table="user_role这里写第三张表的名字">

        <key column="uid当前实体类在第三章表中的外间名"></key>

        <many-to-many class="role实体类的全路径" column="rid"></many-to-many>

    </set>

    在role.hbm.xml的class标签中添加set标签

    <set name="userSet" table="user_role这里写第三张表的名字">

        <key column="rid当前实体类在第三章表中的外间名"></key>

        <many-to-many class="user实体类的全路径" column="uid"></many-to-many>

    </set>

    在hibernate.cfg.xml中添加两个配置文件的映射

 

    2.多对多级联保存

    在用户的映射配置文件中的set标签内配置cascade属性

    <set name="roleSet" table="user_role" cascade="save-update">

    代码

    User user = new User();

    user.setSname("大哥");

    

    Role role = new Role();

    role.setRname("职员");

 

    user.getRoleSet.add(role);

    session.save(user);


    3.多对多级联删除

    在用户的映射配置文件的set标签内,配置cascade属性

    <set name="roleSet" table="user_role" cascade="save-update,delete">

    代码

    User user = session.get(User.class,1);

    session.delete(user);

    但这样的级联删除存在问题,因为多对多的关系,

    大哥→职员,酒鬼

    二哥→职员,学者

    级联删除大哥,会先删除用户大哥,级联删除职员和酒鬼两个角色,二哥就只剩下了学者。

 

    4.维护第三张表

    用户和角色这样的多对多关系,一般通过对第三张表的维护来实现一些级联操作。

    添加——为用户添加某个角色操作

    User user = session.get(User.class,2);

    Role role = session.get(Role.class,3);

    user.getRoleSet().add(role);

    删除——为用户删除某个角色操作

    User user = session.get(User.class,2);

    Role role = session.get(Role.class,3);

    user.getRoleSet().remove(role);

 

15.hibernate查询方式

    1.对象导航查询(通过获得实体类外键属性set集合)

    情景:根据id查到公司,然后通过公司的外间属性员工获得所有员工

    Company com = session.get(Company.class,1);

    Set<Employee> eeSet = com.getEmployeeSet();

    然后遍历set集合即可。

 

    2.OID查询

    根据id查询,就是Session中的get方法

    情景:查询cid为1的公司

    Company com = session.get(Company.class,1);

 

    3.HQL查询

    使用Query对象

    Query query = session.createQuery("from Company");//hql主要是对实体类对象的操作,因此from后面跟的不是表名,是对应的实体类对象名字

    List<Company> comlist = query.list();

 

        1.hql条件查询

            from 实体类名字 where 实体类属性 =?

            Query query = session.createQuery("from Company where cid=? and cname=?");

            处理占位符,使用Query中的setParameter()方法,需要注意的是:方法中的第一个参数指的是hql语句中第几个占位符,并且从0开始算第一个。

            query.setParameter(0,1);

            query.setParameter(1,"保护伞");

            List<Company> comlist = query.list();

        

        2.排序查询

            Query query = session.createQuery("from Company order by cid desc");

            同样使用order by关键字,并且asc为默认升序,desc为降序

            List<Company> comlist = query.list();

 

        3.分页查询

            先查出所有

            Query query = session.createQuery("from Company");

            然后设置开始的位置,每页显示的最大数量

            query.setFirstResult(0);    //表示从0开始

            query.setMaxResults(10);    //每页显示10条记录

            List<Company> comlist = query.list();

 

        4.投影查询

            就是查询表中的特定字段,部分字段

            Query query = session.createQuery("select cname,cmem_num from Company");

            List<Object[]> list = query.list();

            遍历list集合中的数组

        

        5.聚集函数

            举例:count()

            Query query = session.createQuery("select count(*) from Company");

            Object num = query.uniqueResult();    //因为返回的只是计数的一个值,因此使用uniqueResult方法转化为一个对象。

 

    4.QBC查询

        使用Criteria对象操作

        Criteria criteria = session.createCriteria(Company.class);

        List<Company> comlist = criteria.list();

        遍历list即可

 

        1.条件查询

            Criteria criteria = session.createCriteria(Company.class);

            设置查询条件,通过Restrictions设置条件

            criteria.add(Restrictions.eq("cid",1)),    //Restrictions类提供很多匹配方法,例如eq就是条件匹配中的"=",ht大于,gt小于,模糊查询则可以使用like("cname","阿里%");

            criteria.add(Restrictions.eq("cname","保护伞"));

            List<Company> comlist = criteria.list();

            

        2.排序查询

            Criteria criteria = session.createCriteria(Company.class);

            使用Criteria的方法addOrder添加排序条件,使用Order的类方法asc表示按照参数进行升序排列

            criteria.addOrder(Order.asc("cid"));

            

        3.分页查询

            Criteria criteria = session.createCriteria(Company.class);

            设置分页参数,起始位置,每页显示数量

            criteria.setFirstResult(0);

            criteria.setMaxResults(10);

 

        4.统计查询

            Criteria criteria = session.createCriteria(Company.class);

            设置计数操作,Projections类静态方法rowCount表示计数

            criteria.setProjection(Projections.rowCount);

            同样返回的只是一个数字,我们把结果转化为对象

            Object num = criteria.uniqueResult();

 

        5.离线查询

            查询条件一般是由web层传来,然后由web层到service再到dao层,通过session创建Criteria对象,组装查询条件来执行。

            离线查询的Criteria对象创建时是脱离session的,离线查询的好处是可以在web层创建Criteria对象,然后组装查询条件,将criteria对象发送至dao层后再关联session执行查询,这样做简化了dao层的操作。

            DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Company.class);

            Criteria criteria = detachedCriteria.getExecuteCriteria(session);

            List<Company> comlist = criteria.list();

 

    5.HQL多表查询

        1.内连接

            from Company C inner join C.employeeSet

            内连接返回的结果在list中是数组的形式

        2.迫切内连接

            from Company C inner join fetch C.employeeSet

            迫切内连接返回的结果在list中是对象的形式

        3.左外连接

            from Company C left outer join C.employeeSet

            左外连接返回的结果在list中是数组形式

        4.迫切左外连接

            from Company C left outer join fetch C.employeeSet

            迫切左外连接返回的结果在list中是对象的形式

        5.右外连接

            from Company C right outer join C.employeeSet

 

    6.hibernate检索策略

        1.立即检索(立即查询)

            get方法,即执行get方法时立刻向数据库发送底层sql语句

        2.延迟检索(延迟查询)

            load方法

            User user = session.load(User.class,1);    //此时不会发送语句

            System.out.println(user.getUid());    //这个时侯也不会发送语句,因为这个时候内存中有id值,不需要向数据库发送语句,会返回给id值

            System.out.println(user.getUsername());    //这个时候会发送语句,只有当你请求的属性内存中没有,才会向数据库发送语句

            

            类级别延迟 

                返回为类对象,且不会立刻发送语句

            关联级别延迟

                查询某个公司,在查询公司的所有职员,查询公司的所有职员的过程中的延迟

                在映射文件中配置关联级别延迟,在公司的配置文件中set标签添加属性fetch和lazy

                <set name="employeeSet" fetch="select" lazy="false/true(默认)/extra">

                lazy的取值:false表示不开启延迟,立即查询

                                    true表示开启延迟,默认情况,当在关联查询中通过公司的外键属性的get方法获取时不会立刻发送语句

                                                                                    Set<Employee> eeSet = user.getEmployeeSet();    //此时不会向数据库发送查询语句,使用employee对象的时候才会发送

                                    extra表示加强延迟,不仅不会立刻发送,使用的时候需要什么字段返回什么字段

            

    7.批量抓取

        情景:查询所有公司的所有职员

        通常情况下我们先查询出所有公司,返回存放公司的list集合后,遍历公司list,并且每遍历一个公司,再遍历这个公司下的所有员工

        问题:每次遍历都会向数据库中发送语句,性能低

        优化:再公司的映射配置文件中的set标签内配置batch-size属性

           <set name="employeeSet" batch-size="4">

            batch-size的值要求整数,并且没有特殊要求,当数值越大,遍历时像数据库中发送的语句越少,性能越好。

            值为几就表示一次关联查询出多少条记录,为4则一次关联查询4条关联记录,一共10条就会分3次查询。

            底层其实是通过指定的外键列表,使用单条select语句一次批量查出多条关联记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值