Hibernate框架常用知识点总结

相关概念

  • 用于操作数据库
  • hibernate可以用面向对象的方式操作数据库
  • ORM框架-将对象与表的关系使用配置文件映射

框架搭建

  1. 导包
    导入lib下的required下的包
  2. 准备实体&映射文件
    在实体所在包下新建映射文件(名称:类名.hbm.xml),导入dtd约束(在hibernate-mapping-3.0.dtd)

    <hibernate-mapping>
        <class name="类名" table="表名">
            <!--配置主键-->
            <id name="主键对应的属性名" column="表的主键名" >
                <!--配置id生成策略-->
                <generator class="native"></generator>
            </id>
            <!--配置其他属性-->
            <property name="属性名" column="表的字段"></property>
        </class>
    </hibernate-mapping>
    
  3. 准备主配置文件
    在src目录下,新建hibernate.cfg.xml主配置文件,导入dtd约束(在hibernate-configuration-3.0.dtd)

    <session-factory>
        <!--5个必选项-->
        <proprrty name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <proprrty name="hibernate.connection.url">jdbc:mysql:///test</property>
        <proprrty name="hibernate.connection.username">root</property>
        <proprrty name="hibernate.connection.password">123</property>
        <!--mysql方言,选择最短的选项-->
        <proprrty name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <!--3个可选项-->
        <!--选择标准的sql打印在控制台-->
        <property name="hibernate.show_sql" >true</property>
        <property name="hibernate.format_sql" >true</property>
        <!--自动建表-->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!--引入映射文件-->
        <mapping resource="cn/it/domain/User.hbm.xml" />
    </session-factory>
    
  4. 书写代码

配置详解

映射文件

hibernate-mapping

package属性:填写一个包名,后续配置中默认类所在包即为package属性填写的包

class属性

映射表与类的对应
name属性:类名
table属性:表名

id属性(映射主键)

name属性:类中主键属性名
column属性:表中主键名,默认列名为属性名
length属性:当前列的长度,默认数据库对于类型最大长度
type属性:当前列的类型,默认自动检测属性

generator属性:主键生成策略

代理主键:
increment:先查询表中主键最大值,加1作为新的主键值.
identity:依赖于数据库的主键自增
sequence:使用数据库中的序列
hilo:hibernate自己用高低位算法完成主键自增
uuid:生成随机字符串作为主键(长度应大于32位)
native(常用):自动根据数据库 三选一.(identity|sequence|hilo)

自然主键:
assigned:hibernate不生成主键.由开发人员自己设置主键值.

property属性(映射普通列)

name属性:类中主键属性名
column属性:表中主键名,默认列名为属性名
length属性:当前列的长度,默认数据库对于类型最大长度
type属性:当前列的类型,默认自动检测属性

主配置文件

整体结构在框架搭建的主配置文件中。

自动建表(hibernate.hbm2ddl.auto)
create:自动建表,每次启动hibernate都会自动建表,即使表已经存在,仍然会删除重新建。
create-drop:自动建表,每次启动hibernate都会自动建表,每次运行完成后会将表删除。
update:自动建表,如果有表,就不在重新创建,如果配置改变,自动更改表结构。
validate:不会自动创建表结构,只负责在启动时检验表结构,检出问题后会抛出异常。

API详解

configuration

config,读取配置文件
buildSessionFactory,创建sessionFactory

Configuration conf = new Configuration().config;
SessionFactory sf = conf.buildSessionFactory;

SessionFactory

根据配置信息创建session对象。
1. SessionFactory创建需要消耗较多的内存资源。
2. SessionFactory是线程安全的设计。
结论:在一个web项目中确保只有一个SessionFactory存在。

//获得一个全新的session
Session session = sf.openSession();
//获得与线程绑定的session,使用需要两个条件:1.在主配置文件中配置2.不需手动关闭session
Session session = getCurrentSession

Session

hibernate中操作数据库的核心对象。
1. 操作增删改查
2. 获得事务操作对象

beginTransaction|getTransaction 获得事务对象,第一个还具有开启事务的功能。
get|load   根据给定标识和实体类返回持久化对象的实例
save    增
delete  删
update  改
saveOrUpdate 根据给定的实例的标识属性的值来决定执行增或改的操作。
createQuery 根据给定的HQL查询条件创建一个新的Query实例。
createCriteria  根据给定的实体的名称,创建一个新的Criteria实例。
createSQLQuery 根据给定的SQL查询条件创建一个新的SQLQuery实例。

get方法不会应用类级别加载策略,立即加载。
load方法会应用类级别加载策略,load方法调用时,不会发送任何sql语句,返回一个代理对象,使用对象时才执行查询加载数据。

Transaction

用于操作事务的对象

tx.tx.begin();//开启事务
tx.commit();//提交事务
tx.rollBack();//回滚事务

创建实体对象规则

  1. public的空参构造
  2. 准备属性,public的set/get方法
  3. 提供oid,映射主键字段
  4. 标识属性尽量使用基本数据类型的包装类
  5. 类不能被final修饰

对象的三种状态

瞬时 没id,没关联

持久 有id,有关联

游离 有id,没关联

持久化状态:持久化状态对象会在事务提交时会持久化到数据库,我们需要将对象持久化到数据库,就需要把对象转换为持久化状态。

一级缓存

一级缓存:也称为session缓存.属于线程级别缓存. 该缓存本质其实就是一个集合.该集合被放置到了session对象中.所以也叫session缓存.因为session是线程级别的.所以该缓存属于线程级别缓存.
缓存的作用:提高查询、修改效率。

查询:
1. 根据id查询对象
2. ResultSet会被封装成对象,放入缓存以及返回程序。如果缓存中存在要查id的对象,返回缓存中的对象。

修改:
1. 根据id查询对象
2. ResultSet会被封装成对象,一式两份,分别放入session缓存以及缓存快照中
3. 事务在提交时,会比对session缓存中的以及快照中的对象是否发生变化。如果发生变化执行修改。

hibernate中的事务管理

设置事务隔离级别

<!--数值可设置为1、2、4、8-->
<property name="hibernate.connection.isolation">4</property>

hibernate中事务的应用

  1. 事务在service层管理。
  2. 确保service层和dao层使用的时同一个Connection,调用getCurrentSession方法是从ThreadLocal中获得与线程绑定的session。
  3. getCurrentSession必须配置才能使用

    <!--指定getCurrent获得session与当前线程绑定-->
    <property name="hibernate.current_session_context_class">thread</property>
    
  4. getCurrentSession方法获得的session对象,会在事务提交时自动关闭,不用手动关闭。

一对多|多对一关系

ORM

ORM:对象关系映射

  • o:一的一方使用集合,多的一方直接引用一的属性
  • r:多的一方使用外键引用一的一方
  • m:一对多关系映射,多对一关系映射

    <!--配置一对多关系-->
    <set name="集合属性名">
        <key column="外键名"></key>
        <one-to-many class="多的一方对应的类名" />
    </set>
    
    <!--配置多对一关系-->
    <many-to-one name="引用一的属性名" column="外键名" class="一的一方对应的类名"><many-to-one>
    

应用

Cascase属性:级联操作
  • none:默认值,不级联
  • save-update:级联保存或级联更新
  • delete:级联删除
  • all:save-update+delete

结论:Cascase属性的性质属于减少开发时书写代码量的配置,可以不用靠写代码代替,级联操作尤其级联删除配置使用风险大,不建议使用。

inverse属性:是否放弃维护关系

inverse属性:
- true:放弃
- false(默认):维护

一对多中可以使用Inverse属性放弃维护关系,多对一中不能放弃维护关系。

<set name="linkMen" inverse="true">
    <key column="lkm_cust_id"></key>
    <one-to-many class="LinkMan"></one-to-many>
</set>

结论:为了避免维护关系SQL打印冗余,可以在一的一方放弃维护。配置后注意,表达关系只能通过多的一方来维护。

多对多关系

ORM

ORM:对象关系映射

  • r:使用第三张表,该表至少两列,两列都是外键
  • o:两方都用集合来表达引用多个对方
  • m: 多对多映射文件




应用

Cascade属性:级联操作

与一对多|多对一关系中相同的操作

不推荐使用delete

inverse属性:是否放弃维护关系

inverse属性:

  • true:放弃
  • false(默认):维护

结论:为了避免维护关系重复造成异常抛出,根据业务需要由一方放弃维护。放弃的规则:谁不依赖,谁放弃。例如:订单和商品,商品不依赖订单的存在,商品放弃维护。

Hibernate中的查询

  • 根据OID查询
  • 对象属性导航
  • HQL查询
  • Criteria查询
  • 原生SQL查询

HQL

Hibernate Query Language:hibernate查询语言
该查询语言是面向对象的查询语言.
HQL语句中绝对不可能出现与数据库相关的信息.
该语言是Hibernate独有的语言.只能在Hibernate中使用

语法

一. 基础语法

    //1.书写sql
    //String hql = "select c from cn.it.domain.Customer c";//完整写法
    String hql = "from Customer";//简写
    //2.创建查询对象
    Query query = session.createQuery(hql);
    //3.执行查询
    List<Customer> list = query.list();

二. 投影查询

查询一个属性

    String hql = "select c.id from Customer c";
    Query query = session.createQuery(hql);
    List<String> list = query.list();

查询两个属性

    String hql = "select c.id,c.name from Customer c";
    Query query = session.createQuery(hql);
    List<Object[]> list = query.list();

查询多个对象,并封装到对象中

    String hql = "select new Customer(c.id,c.name,c.password) from Customer c";
    Query query = session.createQuery(hql);
    List<Customer> list = query.list();

三. 条件查询

问号占位符

String hql = "from Customer c where c.name=?";
Query query = session.createQuery(hql);
query.setParameter(0,"张%");//从0开始
List<Customer> list = query.list();

命名占位符

String hql = "from Customer c where c.id between :low and :high";
Query query = session.createQuery(hql);
query.setParameter("low",2);
query.setParameter("high",5);
List<Customer> list = query.list();

四. 分页查询

String hql = "from Customer";
Query query = session.CreateQuery(hql);
query.setFirstResult(2);//startIndex
query.setMaxResults(2);//pageSize
List<Customer> list = query.list();

五. 排序
desc降序,asc升序

String hql = "from Customer c order by c.id desc ";
Query query = session.createQuery(hql);
List<Customer> list = query.list();

六. 聚合函数查询
Count、Max、Min、Sum、Avg

String hql = "select count(c) from Customer c";
Query query = session.createQuery(hql);
Long count = (Long)query.uniqueResult();

七. 多表查询

内连接

String hql = "from Customer c inner join c.linkMen";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();

迫切内连接

String hql = "from Customer c inner join fetch c.linkMen";
Query query = session.createQuery(hql);
List<Customer> list = query.list();

左外连接

String hql = "from Customer c left join c.linkMen";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();

左外迫切连接

String hql = "from Customer c left fetch c.linkMen";
Query query = session.createQuery(hql);
List<Customer> list = query.list();

右外连接、右外迫切连接在左的基础上把left换为right即可。

结论:HQL适用于单表或简单多表,业务逻辑较为复杂的多表仍然需要使用原生SQL书写.

Criteria查询

hibernate框架中独有的查询方式.
Criteria是无语句面向对象查询.
Criteria一般用于单表查询.

语法

一、基础查询

//1.创建查询对象
Criteria c = session.createCriteria(Customer.class);
//2.执行查询
List<Customer> list = c.list();

二、条件查询

Criteria c = session.createCriteria(Customer.class);
//设置查询参数
c.add(Restrictions.and(Restrictions.between("id",2,5),Restrictions.like("name","李%")));
//查询
List<Customer> list = c.list();

三、分页查询

Criteria c = session.createCriteria(Customer.class);
c.setFirstResult(2);
c.setMaxResults(2);
List<Customer> list = c.list();

四、排序查询

Criteria c = session.createCriteria(Customer.class);
c.addOrder(Order.asc("age"));
List<Customer> list = c.list();

五、聚合查询

Criteria c = session.createCriteria(Customer.class);
c.setProjection(Projections.Count("id"));
Long count = (Long)c.uniqueResult();
离线Criteria查询对象

离线Criteria:不需要session就可直接创建

//获得离线查询对象
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
//设置条件
dc.add(Restrictions.like("name","王%"));
//将离线查询对象与session关联
Criteria c = dc.getExecutableCriteria(session);
//执行操作
List<Customer> list = c.list(); 

结论:适合单表

原生SQL

语法

一、基本查询

String sql = "select * from t_customer";
//创建查询对象
Query query = session.createSQLQuery(sql);
List<Object[]> list = query.list();

将指定结果封装到对象中

String sql = "select * from t_customer";
Query query = session.createSQLQuery(sql);
//指定将结果封装到对象中
query.addEntity(Customer.class);
List<Customer> list = query.list();

二、条件查询

参数查询:可以用问号|命名占位符

String sql = "select * from t_customer where name like ?";
Query query = session.createSQLQuery(sql);
query.setParameter(0,"陈%");
query.addEntity(Customer.class);
List<Cutomer> list = query.list();

三、分页查询

String sql = "select * from t_customer limit ?,?";
Query query = session.createSQLQuery(sql);
query.setParameter(0,2);//设置起始页
query.setParameter(1,3);//设置每页封装数量
query.addEntity(Customer.class);
List<Customer> list = query.list();

用于复杂业务查询

查询策略

类级别查询策略

lazy属性:是否懒加载|延迟加载

  • true(默认值):懒加载|延迟加载
  • false:立即加载

    <!--配置类级别查询策略-->
    <class name="User" table="cn.it.domain.User" lazy="true"></class>
    

原理:懒加载时,load方法不会立即查询,会返回要查询的对象的代理对象,这个代理对象对当前操作的session进行封装,在获得对象的属性时,能够根据关联的session加载数据。

注意事项:返回对象的初始化操作一定要在session关闭之前完成,否则会抛出no-session异常。

关联级别查询策略

集合加载策略(一对多|多对多)

lazy属性:决定集合加载策略

  • true(默认值):懒加载|延迟加载
  • false:立即加载
  • extra:极其懒惰,在查询数量时,只查询数量,不查询内容。

fetch属性:指定集合的加载方式

  • select(默认值):加载集合时使用单表查询加载
  • join:加载集合时使用左外连接查询(使用改属性,lazy属性会失效)
  • subselect:使用子查询加载多个集合,如果只加载一个,效果和select相同。

    <set name="linkMen"  inverse="true" lazy="true" fetch="subselect" >
        <key column="lkm_cust_id"></key>
        <one-to-many class="LinkMan"></one-to-many>
    </set>
    

属性加载策略(多对一)

lazy属性:决定属性加载策略

  • proxy(默认值):由对方类级别策略代我决定
  • false:立即加载

fetch属性:指定属性的加载方式

  • select(默认值):单表查询加载数据
  • join:使用多表查询同时加载数据(使用改属性,lazy属性会失效)

    <many-to-one name="customer" column="lkm_cust_id" class="Customer" lazy="proxy" fetch="select"></many-to-one>
    

查询策略结论:查询策略中涉及的所有属性都使用默认值

两个问题

问题一:sql语句打印n+1问题

batch-size属性:一次加载几个客户的集合,默认值为1.使用该属性选择一次加载几个客户的集合来缓解n+1问题

<set name="linkMen" batch-size="5" >
    <key column="lkm_cust_id"></key>
    <one-to-many class="LinkMan"></one-to-many>
</set>  

问题二:dao返回的代理对象,service中关闭了session。在web层使用代理对象时,session已经关闭。会抛出no-session异常。

解决方案:
1. 不使用getCurrentSession,自己将session与现程绑定。
2. 使用过滤器,由过滤器中后处理代码将session关闭。

上述操作,交由spring管理。

  • 15
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值