Hibernate学习笔记(二)
传统的JDBC的缺陷:
1.完全面向sql语句的编程,因为不同SQL的语法会有不同,所以如果更换数据库,
不易于项目的移植。
2.不是面向对象的开发思想
ORM (Object Relation Mapping)对象关系映射
把java的对象和SQL中的数据产生关联关系
类 -- 表
属性 -- 字段
对象 -- 一条数据
这样,操作对象就相当于操作数据库中的一条数据,实现面向对象的开发
基于ORM实现的框架:hibernate、ibatis、mybatis
ORM框架的作用用来对程序中的模型层进行持久化操作
使用hibernate的步骤
1.引入相关的依赖
2.创建hibernate的核心配置文件,配置session-factory
3.创建javaBean,配置实体类的mapping文件.这一步让java类和数据库的表产生映射关系
4.把mapping文件在核心配置文件中加载
hibernate.cfg
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?xml version= "1.0" encoding= "UTF-8" ?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" > <hibernate-configuration> <session-factory> <property name= "connection.username" >sc1812</property> <property name= "connection.password" >sc1812</property> <property name= "connection.driver_class" >oracle.jdbc.driver.OracleDriver</property> <property name= "connection.url" >jdbc:oracle:thin: @localhost : 1521 :orcl</property> <!--方言--> <property name= "dialect" >org.hibernate.dialect.Oracle10gDialect</property> <property name= "show_sql" > true </property> <property name= "format_sql" > true </property> <property name= "hbm2ddl.auto" >create</property> <!--mapping文件需要在这里引入 <mapping resource= "config/Student.hbm.xml" ></mapping> <mapping resource= "config/Classes.hbm.xml" ></mapping>--> <mapping resource= "config/Goods.hbm.xml" ></mapping> <mapping resource= "config/Category.hbm.xml" ></mapping> </session-factory> </hibernate-configuration> |
hibernate的所有事务操作都是非自动提交的,所以在执行完增删改以后需要手动提交
事务,或者设置AutoCommit为true(不可以这样做)
建议在调用增删改之前打开事务,成功后提交或者失败回滚事务,使用Transaction
hibernateSession打开有两种方式
1.通过OpenSession,这种方式需要手动打开和在事务提交后手动关闭Session
2.getCurrentSession 这个方式会得到当前正在使用的session,没有就会创建,
并且在提交后无需手动关闭session
第二种方式需要配置
<property name="hibernate.current_session_context_class">thread</property>
hibernate执行流程
1.加载核心配置文件,创建SessionFactory
2.打开session
3.打开事务
4.执行CRUD操作
5.提交或者回滚事务
6.关闭session,关闭sessionFactory
Session接口:可以理解为用来操作数据库的一个对象,里面提供了对于数据库的数据
的增删改查的功能:get、load、save、persist、update、delete....
get和load,这两个方法都是用来根据主键值查询某单个具体的对象。但是两者有区别
缓存:介于应用程序和物理数据源之间的用来存储数据的临时的容器。缓存的好处在于
减少对数据库的访问次数,提高效率。当数据查询出来可以存放在缓存中,这样下一次
查询不用再向数据库发送命令。hibernate中有两种缓存级别
1.一级缓存,也被称为session或事务缓存,一级缓存的应用范围只在当前的session或
事务内。也就是说在打开一个session,到session的关闭(清除)这个过程之间,
查询到的数据都会存在一级缓存中,再次发出相同的查询不会去发出新的命令,而是在
缓存中得到。被称为命中缓存
2.二级缓存,也被称为应用级缓存,集群缓存。在多个应用进程中共享一个服务器中的
二级缓存。二级缓存随着应用的开启而开启,消亡而结束。存在二级缓存中的数据会及时
更新到集群上所有的节点,使用二级缓存应当考虑是否会被同步修改等问题
get查询的时候会先去一级缓存中寻找是否存在数据,存在就使用缓存中的数据。否则
向二级缓存中查询, 还没有就发出sql命令, 如果命令也查询不到就返回null.
load查询的时候也会先找一级缓存,如果一级缓存中不存在。先看对象是否需要使用
非主键的其他字段。如果使用非主键的其他属性,就继续向二级缓存查询,再没有就发送
sql命令,如果查询不到结果,会抛出一个ObjectNotFound的异常
如果对象使用的是主键属性,那么根据load支持的lazy(延迟加载策略),不会发出
查询,而是返回一个代理对象,代理对象中只保存主键数据.
save:用来向数据库中添加一条数据,对象不需要设置主键列,设置了也不会报错.
save会立马发出insert命令来确保对象马上变为持久态
persist:和save一样用来保存数据,但是如果set主键值会产生异常
update:更新对象,但是必须要有主键列.实际上我们不会通过update去编写更新
而是通过查询得到一个对象,然后对对象的属性修改,这个时候会自动发出一条update
的命令
flush:
这个方法的作用是判断当前持久态的对象和缓存中的数据是否是一致的.如果不一致
在提交事务的时候commit之前会先执行这个方法,然后产生update的命令。
delete 删除一个对象,只要有id就可以
clear 清空session中的所有持久态对象和一级缓存以及待执行的命令等
close 关闭session
saveOrUpdate 如果对象主键有值就认为是update,没有就save,如果有id数据库又没有
数据就报错
hibernate对象状态:
1.瞬时态
瞬时态的对象指的是通过new创建的对象,这个时候对象和数据库中的任何一条数据都没有
关系,对对象的任何操作都不会产生实际的影响.可以通过save、saveOrUpdate等命令
让一个瞬时态的java对象变成持久态的
2.持久态
通过get、load等方法得到的对象都是持久态的。持久态的特征是数据库中有某条数据和
这个对象产生了关联。这个时候对持久态对象的任何改变都会产生一条update的命令
等待执行,提交事务的时候发出这些update命令.当持久态的对象执行了delete操作后
这个对象就变为了瞬时态,因为数据库中的数据被删除,对象也会等待垃圾回收
如果执行的是session.clear 或者session.close 这个对象会变为游离态
3.游离态
游离态的对象是由持久态转变过来的,数据库中存在一条数据和该对象的属性一致,但是
对游离态的对象的任何操作不会影响数据库中的数据。也可以通过save等方法重新变为
持久态。如果delete,那么就会变成瞬时态
关联关系映射
分为单向和双向
具体类别:多对一,一对多,一对一,多对多
单向多对一:
就以学生和班级为例,多个学生属于同一个班级,这就是多对一
配置:在多的一端添加1的一端的对象。在多的一端的映射文件中添加many-to-one
many-to-one:
name表示多的一端中1的一端的对象名
class 1的一端的类路径
column 1的一端在多的一端中的外键名
单向一对多
配置:在1的一端的类中添加多的一端的集合
在1的一端的配置文件中添加set
在双向关系中,插入数据时双方都会主动去维护关系,这个时候会产生多的update语句
所以应该使用inverse 属性来解决
inverse表示是否主动维护关系,默认false,false表示主动,true为被动
在实际开发我们应该设置1的一端被动,不去主动维护每个子项。在1的一端的配置的
set上,设置inverse=true
关联关系级联操作 casecade ,在设置物理外键的情况下,用来级联删除
order-by 指定列进行排序
使用双向多对多需要一方放弃维护,设置inverse=true
检索策略
hibernate数据检索分为立即加载和延迟加载
lazy=true 表示延迟加载,延迟加载的好处是不需要使用到数据时避免发出查询
每个类节点上都有个lazy,默认为true,但是class上的lazy只对load生效,get时不考虑
是否延迟加载。
除了class节点上可以设置lazy,关系映射的多对一,一对多,多对多等都可以在对应
的配置上设置lazy。默认都是true的
但是需要注意,延迟加载可能发生异常,例如在session清空后发出关联对象的查询
hibernate查询,hibernate查询有5种方式
1.根据id查询单个对象,get和load方法
2.对象导航查询, 查询出一个对象后,用对象.关联的对象
3.HQL查询
4.QBC查询
5.本地SQL查询
HQL hibernate自带的一种查询语言,语法和sql类似,但是完全是用对象和属性在
查询。hql支持多种查询的使用
1.排序
2.分组 having
3.where条件
4.子查询
5.联查
6.分页
7.支持链式编程
8.支持占位符,预编译
使用HQL需要用到hibernate核心接口Query,Query由session来创建
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现