-
Notifications
You must be signed in to change notification settings - Fork 19
Hibernate
目录 start
目录 end|2020-05-17 16:13|
- JDBC
- 使用其简洁精悍,最快,但是使用时反序列化数据麻烦,手动管理容易出内存泄漏
- Hibernate
- 单表操作是很便捷的,但是涉及到多表复杂操作时比较复杂,不便调优
如果后续需要添加表的话,就这个顺序
- 先有数据库和表,建立cfg.xml文件配置好数据库的基本参数
- 使用工具建立POJO持久类
- 导入Hibernate所必需JAR包,最好使用Myeclipse的配置,自己导包总有一堆错误
- 使用MyEclipse自动创建hbm.xml文件,还有各种文件。配置好hbm文件里关于表间关系的映射,或者在Myeclipse配置时手动选择
- 配置好DAO类中事务开启和关闭,以及各种所必需的配置,若表没有设立主键,那么POJO类需要继承自动生成的抽象类(含有主键)
- 调用DAO或者自己的Utils类,通过Hibernate来操作数据库
Hibernate 3.6
- required目录下所有JAR都要导入
- jpa的JAR包(做注解用)
- 日志包:
- slf4j-api-* .jar 该包是一个日志接口,需要一个JAR包的实现:
- slf4j-log4j12.jar 该包是转换的JAR包
- log4j-1.2.11.jar 实现SLF4J接口的JAR包
- 数据库驱动包 mysql-connector-java-5.1.7-bin.jar
- 在src同级目录下新建一个lib目录,把JAR包复制进去,然后右击将jar文件 Add to build path 加入到类搜索路径里
- 使用自己的工具类创建到对应的包下,或者用相关工具生成,类型要自己多加注意
作为默认的主配置文件
- 数据库连接属性 驱动,url,用户名,密码
- 数据库方言
- 辅助配置
- POJO类配置文件的映射
- etc/hibernate.properties里可以看到更多配置,数据库连接池,SQL优化等
- SessionFactory
重量级容器:消耗大量资源,不能有太多实例,二级缓存 通常将该工厂类是单例模式,一个工厂类实例表示一个数据库
所以Hibernate一般是不能跨数据库来做事务操作。但是EJB和JPA可以实现 如下配置选项:
- hibernate.hbm2ddl.auto create-drop 在一个数据库中创建,然后使用完关闭实例时就删除所有建立的表
- hibernate.hbm2ddl.auto create 清除数据库的表及数据,重新创建表
- hibernate.hbm2ddl.auto update 更改配置文件,能够在数据库进行操作(更新,建立)
- hibernate.hbm2ddl.auto validate
- session
轻量级的容器,一级缓存 是非线程安全的对象
在Hibernate中唯一标识对象的属性,每个实体都是必须要有OID的
- assigned:要求用户去手动指定对象的OID;该对象ID的类型可以是任意的
- identity:MySQL的自动生成
- native:数据类型是数值型,id的生成策略为数据库底层自增长(数据库自己去决定使用哪种方式,MySQL用identity,Oracle用序列等)
- sequence:Oracle数据库推荐,数值型(Long)
- seqhilo oracle :推荐使用的策略,使用序列来搭配高低机制
- uuid.hex :32位字符
- uuid:
- hilo:类型为数值型(long) [实际开发中推荐使用]
id = hi+lo (高位和低位进行组合) sessionFactory实例化,高位就会加一,生成算法是:hi*(max lo +1)+lo;
<generator class="hilo" >
<param name="table">stu_hilo</param>
<!-- 放高值的表名 最好是一个对象对应于一个高低值的表避免了并发-->
<param name="cloumn">next_hi</param>
<!-- 高的值放在表的哪个字段 -->
<param name="max_lo">100</ param>
<!-- 每个轮回值的上限是多少 虚拟机启动频繁就设小一些,避免编码的浪费-->
</generator>
- Set集合:
<set name="Nos" table="表">
<key column="外码"></key><!-- 外码 是必须的 -->
<element column="号码" type="string"/>
</set>
- List集合:
<list>
<key></key>
<index></index>
<element></element>
</list>
- 查询列 属性:
<property name="" formula="(select sum() from 选修表 as u where u.id=id)"></property>
- 注意:一定要两个都有oid的情况才能配置一对多的映射,不能是依赖于另一个主键类
- 一方:
<set name="" [cascade=""]>
<key column="这是外键"></key>
<one-to-many class="多方的类"></one-to-many>
</set>
- 多方:
<many-to-one name="" class="一方的类" column="外键,key要一致" />
- 双向的关联,会有update的SQL语句的执行来维护关系,影响效率
- 多方维护:一方中set标签加inverse="true"一方就不会维护,代码一定要多方执行set**(*)
- 一方维护:一方代码一定要执行**.add*()
- 1.在一的一方,修改xml文件,添加一个set 属性,表示 多方 的一个集合
<set name="类中属性名(集合)" inverse="true">
<key>< column name="数据库列名"/></key>
<one-to-many class="多方类路径"/>
</set>
-
2.在一的一方,修改POJO持久类文件,添加一个hashset,用来存储多方,添加setget方法,名字就是配置文件里添加的那个名字 注意修改构造器
-
3.在多的一方,修改xml文件,置换掉那个外键,换成many-to-one标签,里面写上外键的列
<many-to-one name="类中属性名(对象)" class="一方的类路径" column="数据库中列名"></many-to-one>
-
4.在多的一方,修改POJO持久类文件,添加一个一方的对象添加setget方法,名字就是配置文件里添加的那个名字 注意修改构造器
- 一方的set集合中有inverse属性,多方是没有的,Hibernate中inverse是和外键对应的,一方配置了inverse是false,一方就不会维护关系(外键),一般是给多方维护,因为效率高
- cascade是对象和对象之间的操作,和外键没有关系
- 处于持久化状态的对象在Session中,客户端不需要做Session的save/update 操作,Hibernate会自动的去检查处于持久化的对象的状态的属性是否发生改变,改变了就发送update语句。
- 如果该对象是一方,在一的一方映射文件中有cascade=all时,Hibernate内部还会检查该持久化对象关联的集合,对此集合进行update操作,但是该操作和外键没有关系,只有当通过多方建立关系后,才能使外键有值。
- 关系在第三方表中,和两张表本身没有关系
- 多对多维护关系,谁都能维护关系(效率是一样的)维护一般是在页面上进行的
- table 是多对多的中间表(存放了一个关系)
- key中的column一般是填当前配置文件中的id
- 多对多的配置是需要两个外键的
- 如果使用了反转并使用了级联,就只会保存实体,但是关系是没有维护的(就是不会插入到第三方表),和一对多一样的(一对多是外键列没有值)。
- !!如果双方都级联了,必须要有一方inverse,不然会有重复维护的错误发生
<set name="students" table="student_course">
<key column="cid"></key>
<many-to-many class="Student" column="stu_id"></many-to-many>
</set>
<set name="courses" table="student_course">
<key column="stu_id"></key>
<many-to-many class="Course" column="cid"></many-to-many>
</set>
- 单向
只要配置单向的配置文件添加:
<many-to-one name=""class="映射的类" column="数据库字段" unique="true"></many-to-one>
- 双向
- 一方 甲:
<many-to-one name="" class="乙方类"column="数据库字段" unique="true"></many-to-one>
- 一方 乙:
<one-to-one name="" class="甲方类" property-ref="甲方配置的标签的name"></one-to-one>
- 一方 甲:
- 当需要添加一个多方时,一看成课程,多看成成绩。当然的首先得有相关课程,再添加成绩记录。
- 那就先实例化一个课程对象,配置好信息
- 实例化多个成绩实例,再 课程对象.get**Set().add(成绩对象); 将成绩对象添加到集合中,
- session.save(课程对象);
注意:既然实现了这样的操作,那就说明了在实例化成绩的时候,不需要指定课程的值,那就需要添加一个构造器
- 如果删除一方,那就会将一删除,如果没有配置级联,就会将多方的外键置空,不会删除多方表
- 如何通过一方修改多方的一条, 把一方的set中的要修改的一条,(查找之前需要对象 = session.load(对象.class,主键名)将多方的数据加载进来)
- 注意多方不能有空列必须指定一个默认值(是和构造器有关么?)
- 再查找出来,修改再update,新增也是如此增加多的一方的时候,就是在一方的set中新增一条记录,多方的操作都体现在了一方那里
两种方式,一般采用前者
<!-- 将子类插入到父类的配置文件 需要使用key来关联的-->
<joined-subclass name="cn.hibernate.extend.Student" table="extend_student">
<key column="id"></key>
<property name="sru_id" type="long"></property>
</joined-subclass>
<!--
union是相当于将父类的所有属性复制到子类里,是共享父类的OID,
所以父类的OID是不能和子类的OID重复的
不然 查询的时候就会报错,
所以就需要改父类的主键生成策略是高低值(或者是手动set),可以手动配置高低值的表的生成
-->
<union-subclass name="cn.hibernate.extend.Student" table="union_student">
<property name="sru_id" type="long"></property>
</union-subclass>
主要是对象内存和Session中的状态区别,而不是Session和数据库
-
临时态
:刚实例化对象。对象在数据库中不存在,Session中也不存在 -
游离态
:刚实例化的对象,但是该对象手动指定了OID并且OID在数据库中已经存在,并且是没有绑定Session的(特殊的临时态)- 保存两个有关联关系的对象,update时,如果配置文件中配置了级联,就会一起保存,一般建议在一方级联
-
持久态
:该对象在数据库中存在,该对象绑定在Session(一级缓存)中 -
删除态
:session.delete(对象),删除后对象从数据库和Session中都移除了,但是OID还在内存中。- 游离态delete后就成了删除态
- 持久态delete后就成了删除态
- 分析: JDK源码 DefaultMergeEventListener中的onMerge方法
- save
- update
- delete
- saveOrUpdate 由入参的OID来自动选择是要save还是update
- merge 形参:临时态的对象。形参和Session没有任何关系,返回对象Object2(持久化对象),所以在Session关闭的时候Object2的更改会同步到数据库中
- get 将数据库中指定对象获取为持久态,查不到就是返回null
- load 懒加载。使用代理对象,延迟加载。用到了别的属性就去查数据库。查不到就抛异常
- flush 刷新Session
- evict 定点清除 将指定的对象从Session中移除,变成游离态
- clear 全部清除
- close
-
一个对象(内存)不能存在于多个Session中,一个存,一个改的情况是会错误的
-
但是数据库中同一条记录可以实例化为多个对象(内存),那么这些对象(内存)放在不同的Session中是可以的
-
get:
- 只延迟加载有外键关联的那部分属性,没有使用就不会查询,只有用到了才会查询
- 多方:立即加载就要在配置文件中将对应的属性中添加 fetch="join"
- 一方:配置文件中set标签 加上lazy="false"(两条SQL),再添加 fetch="join"后就只有一条SQL语句,但是这个一方是不能做分页查询的
-
load:
- 在你确定OID是一定有的时候使用load提高效率,但是实际开发过程中用的少,因为实际上没有这么确定。
-
懒加载如果Session关闭了或者是对象游离态。就会有懒加载初始化的异常
原因:
- 可能真的没写get方法,或者get方法不合规范 setget方法中不允许两个连续大写字母
- *.hmb.xml文件中的属性名和pojo持久类中属性名不一致(一定不能在表名中添加下划线)
-
【 Algorithm 】
-
【 Blog 】
-
【 C 】
-
【 Database 】
-
【 Distributed 】
-
【 FrontEnd 】
- 【 FrontEnd/Frame 】
- 【 FrontEnd/Node 】
- Font
- Hexo
- JavaScript
- LearnPS
- ResponseCode
- SVG
- ViewSolution
- extjs学习笔记
-
【 Functional 】
-
【 Go 】
-
【 Groovy 】
-
【 Java 】
- 【 Java/AdvancedLearning 】
- 【 JavaBasic 】
- 【 JavaCache 】
- 【 JavaCollection 】
- 【 JavaConcurrency 】
- 【 JavaMap 】
- Annotation
- ClassFile
- Collection
- Concurrency
- Deploy
- Exception
- ExtendsAndInterface
- Generics
- IO
- JDBC
- JDKAndJRE
- JMX
- JVM
- Java11
- Java7
- Java8
- JavaNetwork
- JavaReleaseVersion
- JavaWeb
- JvmPerformance
- MQ
- MultipleLanguage
- Proxy
- Reflection
- Serialize
- SyntaxAndType
- Thread
- WebPerformance
- 【 Java/Android 】
- 【 Java/Ecosystem 】
- 【 Java/MSA 】
- 【 Java/Spring 】
- 【 Java/TemplateEngine 】
- 【 Java/Test 】
- 【 Java/Tool 】
- 【 Java/thread 】
- AlibabaJavaStandard
- DesignPattern
- HashMap解析
- Java-NIO
- Java虚拟机
- Log
- MIS
- Quartz
- RESTful
- WebSocket学习笔记
- ZooKeeper学习笔记
- android学习笔记
- 【 Java/AdvancedLearning 】
-
【 Kotlin 】
-
【 Linux 】
- 【 Linux/Alpine 】
- 【 Linux/Arch 】
- 【 Linux/Base 】
- 【 Linux/Centos 】
- 【 Linux/Container 】
- 【 Linux/Debian 】
- 【 Linux/Tool 】
- JavaDevInit
- Linux系统学习
-
【 MyBlog 】
-
【 Python 】
- 【 Python/Tool 】
- Python
- PythonConcurrent
- PythonGUI
- PythonGame
- PythonNet
- PythonOffices
- PythonWeb
- Python基础
- Python核心学习
-
【 Reactive 】
-
【 Rust 】
-
【 Scala 】
-
【 Script 】
-
【 Skills 】
- 【 Skills/Application 】
- 【 Skills/CS 】
- 【 Skills/Cache 】
- 【 Skills/Councurrency 】
- 【 Skills/DevOps 】
- 【 Skills/Document 】
- 【 Skills/Ecology 】
- 【 Skills/Network 】
- 【 Skills/Search 】
- 【 Skills/SoftwareEngineering 】
- 【 Skills/Spider 】
- 【 Skills/Test 】
- 【 Skills/Vcs 】
- 【 Skills/Work 】
- AppManual
- CelebrityQuotes
- Miscellaneous
- Platform
- Problem
- Protobuf
- RegularExpression
- SoftwareDesignEngineer
- Website
-
【 Windows 】