Hibernate框架常用知识点

相关概念
用于操作数据库
hibernate可以用面向对象的方式操作数据库
ORM框架-将对象与表的关系使用配置文件映射
框架搭建
导包 
导入lib下的required下的包
准备实体&映射文件 
在实体所在包下新建映射文件(名称:类名.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>

--------------------- 
准备主配置文件 
在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>

书写代码

配置详解
映射文件
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();//回滚事务


创建实体对象规则
public的空参构造
准备属性,public的set/get方法
提供oid,映射主键字段
标识属性尽量使用基本数据类型的包装类
类不能被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中事务的应用
事务在service层管理。
确保service层和dao层使用的时同一个Connection,调用getCurrentSession方法是从ThreadLocal中获得与线程绑定的session。
getCurrentSession必须配置才能使用

<!--指定getCurrent获得session与当前线程绑定-->
<property name="hibernate.current_session_context_class">thread</property>


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管理。
 

猜你喜欢

转载自blog.csdn.net/m0_37822534/article/details/83856828