Hibernate

Hibernate

Hibernate应用在dao层

在dao层路面对数据库进行crud操作的,使用hibernate实现,hibernate在底层代码就是jdbc,hibernate对jdbc就行封装,使用hibernate好处,就是不需要写复杂的jdbc代码
hebernate是轻量级的框架

orm思想:

让实体类与表进行一一对应

hibernate本身没有支持日志的jar包,所有需要其他的jar包

log4j
slf4j-api
alf4j-log4j

建实体类

hibernate要求实体类有一个属性唯一的set,get方法

配置实体类和数据库表一一对应关系

使用配置文件实现映射关系
映射文件名称和位置没有固定要求
建议在实体类所在包中(.hbm.xml)
首先引入约束(dtd)
引入mapping.dtd约束

创建hibernate的核心配置文件

核心配置文件格式xml,核心配置文件名称和位置固定的
位置:src下面
名称: hibernate.cfg.xml
引入config.dtd约束

hibernate操作过程中,只会加载核心配置文件,其他配置文件不会加载

第一部分,配置数据库信息

第二部分,配置hibernate信息

第三部分,将映射文件放到核心配置文件中

实现添加操作

第一步,加载hibernate核心配置文件

第二步,创建SessionFactory对象

第三步,使用SessionFactory创建Session对象

第四步,开启事务

第五步,写具体crud操作

第六步,提交事务

第七步,关闭资源

//加载hibernate核心配置文件
Configuration configuration = new Configuration();
configuration.configure();
//读取hibernate核心配置文件内容,创建sessionFactory
//在过程中,根据映射关系,在配置数据库里把表创建
SessionFactory sessionFactory = configuration.buildSessionFactory();
//创建session对象
//类似于连接
Session session = sessionFactory.openSession();
//开启事务
Transaction tx = session.beginTransaction();
//写具体crud操作
User user = new User();
user.setUsername("刘政杉");
user.setPassword("53767");
user.setAddress("北京");
session.save(user);
//提交事务
tx.commit();
//关闭资源
session.close();
sessionFactory.close();

Hibernate配置文件详解

hibernate映射配置文件 .hbm.xml

1.映射配置文件名称和位置没有固定要求
2.映射配置文件中,标签name属性值写实体类相关内容

class标签name属性值实体类全路径
id标签property标签name属性值 实体类属性名称

3.id标签和property标签,column属性可以省略
4.peoperty标签type属性,设置生成表字段的类型,自动对应类型

hibernate核心配置文件

1.配置写位置要求


2.配置三部分要求

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

3.核心配置文件和位置固定的

位置:src下面
名称:hibernate.cfg.xml

session

1.session类似于jdbc中的connection
2.调用session里面不同方法实现crud操作
3.session对象单线程对象

transaction

1.事务对象
开启事务
Transaction tx=session.beginTransaction();
2.事务提交和回滚
tx.commit()
tx.rollback()
3.事务四个特性:
原子性,一致性,隔离性,持久性

1.实体类编写规则

实体类里面属性私有
私有属性使用public的set和get方法
要求实体类有一个唯一值(一般id值)
实体类属性建议不适用基本数据类型,使用其包装类
基本数据类型无法表示“空,无”

2.hibernate主键生成策略

hibernate要求实体类里有一个属性作为唯一值,作为唯一值,主键可以不同生成策略
hibernate主键生成策略有很多值
<generator class="native"/>
native(Integer ),uuid(String)

3.实体类操作

crud操作

根据id查询
调用session里面的get方法
session.get(实体类.class,id值)

修改操作
session.update(实例)
执行过程,到user对象里找到uid,根据uid进行修改

删除
session.delete(实例)
执行过程,到user对象里找到uid,根据uid进行删除

实体类对象状态

瞬时态
对象里面没有id值,对象与session没有关联
添加操作时

持久态
对象里面有id值,对象与session关联
根据id查询

托管态
对象有id值,对象与session没关联
删除时

saveOrUpdate()
就是根据对象状态不同进行的操作
当实体类对象为瞬时态时进行添加操作
当实体类为托管态,持久态 进行修改操作

4.hibernate的一级缓存

什么是缓存?

数据库存到内存里面。数据存到数据库里面,数据库本身是文件系统,通过流方式操作文件。

hibernate缓存特点:

hibernate的一级缓存默认是打开的
hibernate的一级缓存使用范围是session范围,从session创建到关闭
hibernate的一级缓存中存储数据必须持久态数据

第二类hibernate的二级缓存:
目前不适用,替代技术redis
二级缓存默认不是打开的,需要配置
二级缓存使用范围,是sessinFactory范围

一级缓存流程:

首先查询一级缓存,如果没有发现数据,就会去查询数据,返回对象(持久态对象)然后,把持久太对象存放到一级缓存中。这里注意,一级缓存中存放的不是对象,仅仅是键值。如果发现一级缓存中有相同的数据,直接返回。根据主键查询,然后将数据装配成对象返回。

hibernate一级缓存特性:
持久态自动更新数据库

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

2.user.setUsernaem("hanmeimei");
一句查询到数据后,把user持久态放到一级缓存中以及其对应的快照区中。二句重新设置username时会自动更新到一级缓存中,而不会修改快照区。
最后提交事务时,数据库会比较缓存内容与快照区内容是否相同,如果不相同,就把一级缓存中内容更新到数据库中。

5.hibernate的事务操作

1.什么是事务

对于数据库的操作

2.事务特性

原子性:一个事务要被完全的无二义性的做完或者撤销
一致性:一个事务应该把系统从一个一致性换到另一个一致状态
隔离性:每个事务独立执行
持久性:被完成的事务的效果应该是持久的

3.不考虑隔离性产生读问题

脏读:A事务读取到B事务中未提交的数据
不可重复读:A事务读取到了B事务中已提交的数据
虚读:A事务中读取B事务已提交的新插入的数据

4.解决读问题

(1)设置隔离级别
mysql默认隔离级别:
repeatable read

<property name="hibernate.connection.isolation">4</property>

事务代码规则写法:
代码结构

try{
    开启事务
    提交事务
}catch{
    回滚事务
}finally{
    关闭
}

如何保证session一定是单线程?

与本地线程绑定
底层实现threadLocal,
获取与本地线程绑定:
在hibernate核心配置文件中配置

<property name="hibernate.current_session_context_class">thread</preperty>
调用sessionFactory里面的方法得到
    public static Session getSessionobject(){
        return sessionFactory.getCurrentSession();
    }

获取与本地线程绑定session时候,关闭session,会报错,不需要手动关闭

6.hibernate其他的api

Query对象
使用query对象,不需要写sql语句,但是需要写hql语句。
sql操作表和表字段
hql操作实体类和属性

查询所有hql语句:
from 实体类名称

query对象使用
1.创建query对象
Query query = session.createQuery("from User");
List<User> list = query.list();
2.调用query对象里面的方法得到结果



Criteira对象
不需要写语句,直接调用方法
1.创建criteria对象
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
2.调用方法得到结果



SQLQuery对象
使用hibernate时候,调用底层sql实现

创建对象,调用对象方法得到结果
SQLQuery sqlQuery = session.createSQLQuery("sql语言");
List list = sqlQuery.list();
默认返回数组形式

怎样返回对象形式?
SQLQuery sqlQuery = session.createSQLQuery("sql语言");
sqlQuery.addEntity(User.class);
List<User> list = sqlQuery.list(); 

表与表之间关系回顾

1.一对多

在多的那一方创建字段作为外键,只想一的那一方的主键

2.多对多

创建第三张表

hibernate一对多操作

1.一对多映射配置

hibernate要求使用集合表示多的数据,使用set集合,在实体类里面表示
private Set setUser = new HashSet();
写在Customer映射配置文件之后,在客户映射文件中,表示所有联系人。

<!-- 在客户映射文件中,表示所有联系人
使用set标签表示所有联系人
set标签里面有name属性,属性值写在客户实体类里面表示联系人的set集合名称
 -->
<set name="setLinkMan">
<!-- 一对多建表,有外键
hibernate机制:双向维护外键,在一和多那一方都配置外键
column属性值:外键名称
-->
<key column="cid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径-->
<one-to-many class=""/>
</set>

在联系人中表示所属客户

<!-- name:因为在联系人实体类使用customer对象表示,写customer名称
class:customer全路径
column:外键名称,与之前在客户中配置的外键一样
-->
<many-to-one name="customer" class=" " column=""/>

2.一对多级联保存

设置级联
在客户映射文件里面,set标签进行配置

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

第二步,创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户

3.一对多级联删除

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

4.inverse属性

在做级联更新时,因为hibernate外键双向维护特性,所以会引起两次update
解决:一对多里面,让其中一方放弃外键的维护
具体做法:
set标签上inverse属性
inverse=”false”
false不放弃关系维护,
true放弃关系维护

hibernate多对多操作

多对多,两方使用set
1.多对多映射配置

<!-- 在用户里面表示所有角色,使用set标签
name属性,角色set集合名称
table属性,第三张表名称 
-->
<set name= "setRole" table="user_role">
    <!-- key标签里面配置
    配置当前映射文件在第三张表外键名称
    -->
    <key column="userid"></key>
    <!--class,实体类全路径
    column,另一个实体类在第三张表外键名称
    -->
    <many-to-many class=" " column="另一个实体类在第三张表名称"></many-to-many>
</set>

在对应的映射配置中,做相同的配置,只不过改成相应的值

2.多对多级联保存

3.多对多级联删除

4.维护第三张表

hibernate查询

1 hibernate的查询方式
  1. 对象导航查询
    根据id查询某个客户,在查询这个客户里面所有联系人
  2. oid查询
    根据id查询某一条记录,返回对象
  3. hql查询
    Query对象,写hql语句实现查询
    hql hibernate query language
    hibernate提供一种查询语言,sql操作数据表和字段,hql操作实体类和属性

使用hql查询时
创建Query对象,写hql语句
调用query对象里面的方法得到结果

  1. 查询所有

    from 实体类名称
    
  2. 条件查询

    from 实体类名称 where 实体类属性名称=? and 实体类属性名称=? 
    from 实体类名称 where 实体类属性名称 like ?
    
    创建完query后,要设置条价值,即向?里面添加值
    setParameter方法两个参数
    第一个参数,int类型是?位置,?位置从0开始
    第二个参数,具体参数值
    query.setParameter(0,"baidu");
    
  3. 排序查询

    from 实体类名称 order by 实体类属性名称 asc/desc
    (升序/降序)
    
  4. 分页查询

    在mysql 中实现分页查询语句:
    select * from 表名 limit 0,3
    0:起始位置
    3:每页显示数量
    
    在hql中实现分页,不能写limit,因为limit是MySQL的关键字,hibernate的query封装两个方法实现分页操作
    Query query = session.createQuery("from Customer");
    设置分页数据
    设置开始位置
    query.setFirstResult(0);
    设置每页记录数
    query.setMaxResults(3);
    
  5. 投影查询

    什么是投影查询?
    查询的不是所有字段值,而是部分字段的值
    
    select 实体类属性名称1,实体类属性名称1 from 实体类名称
    seslet后面不能写*,不支持的
    
  6. 聚集函数使用

    query对象里面有方法,直接返回对象形式
    query.uniqueResult();
    count sum avg max min
    
  7. qbc查询

    使用hql查询需要写hql语句实现,但是使用qbc时候,不需要写语句,直接调用方法
    使用qbc时候,操作实体类和属性
    使用qbc,使用Criteria对象实现
    Criteria对象
    Criteria criteria = session.createCriteria(实体类.class);
    
    1. 查询所有

      criteria.list() 
      
    2. 条件查询

          调用Restrictions里面静态方法,里面方法很多,eq意味等于
          criteria.add(Restrictions.eq(实体类属性名,值)); 
          会查找表中字段等于该值的并返回,依旧使用list方法
      
    3. 排序查询

          criteria.addOrder(Order.asc/desc(实体类属性名))
      
    4. 分页查询

          cirteria.setFirstResult(0)
          criteria.setMaxResults(3)
          开始位置 = (当前页-1)* 每页记录数 
      
    5. 统计查询

          criteria.setProjection(Projections.rowCount())
      
    6. 离线查询

          开始时候不直接从session创建critirea
          DetachedCriteria detachedcriteria = DetachedCriteria.forClass(实体类.class);
          //最终执行时才需要session
          Criteria criteria = detachedCriteria.getExecutableCriteria(session)
      
为什么离线查询?
servlet --> service --> dao
为了不在dao中创建,并且拼接条件,可以使用离线查询
本地sql查询
SQLQuery对象,使用普通sql实现查询

对象导航查询

mysql中多表查询

内连接查询
select * from customer c,linkman l where c.cid = l.cid
select * from customer c inner join linkman l on c.cid = l.cid
左外连接
左边表所有数据,右边表关联数据,没有显示null
select * from customer c left outer join linkman l on c.cid = l.cid
右外连接
select * from customer c right outer join linkman l on c.cid = l.cid

hql 中多表查询

内连接
from Customer c inner join c.setLinkMan 
setLinkMan是customer中linkman的set集合
返回以数组形式
迫切内连接
迫切内连接和内连接底层实现是一样的
区别:使用内连接返回list中每部分是数组,迫切内连接返回list每部分是对象
from Customer c inner join fetch c.setLinkMans
左外连接
from Customer c left outer join c.setLinkMan
迫切左外连接
from Customer c left outer join fetch c.setLinkMan
左外连接list中返回每部分是数组,迫切左外连接返回的是对象
右外连接
from Customer c right outer join c.setLinkMans

hiernnate 检索策略

检索策略的概念

hibernate检索策略分为两类
1.立即查询,根据id查询,调用get方法,一调用get方法马上发送语句查询数据库
2.延迟查询,根据id查询,还有load方法,调用load方法不会马上发送语句查询数据库,只有用得到对象里面的值才会发送语句查询数据库,返回的对象里面只有id值
延迟查询分成两类
1.类级别延迟
根据id查询返回实体类对象,调用load方法不会马上发送语句
2.关联级别延迟
查询某个客户,再查询这个客户的所有联系人(这里涉及外键),查询客户所有联系人的过程是否需要延迟
关联级别延迟操作
1在映射文件中进行配置
根据客户得到所有联系人,在客户映射文件中配置

fetch:select 默认
lazy:
true 延迟(默认)
false 不延迟
extra 极其延迟,绝不多给
批量抓取:

查询所有客户,返回list集合,遍历list集合,得到每个客户,得到每个客户的所有联系人
返回list中,发送多条语句,开销大

优化:在客户的映射文件中,set标签进行配置
batch-size=”值”
值越大发送语句越少效率越高

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值