📄 hibernate_note.txt
字号:
if(i%20==0){
//这样做就好想JDBC的批量长度一样.
//session的刷新.
session.flush();
session.clear();
}
}tx.commit();session.close();
什么时候做刷新操作.
Flushing the Session
s.flush(),
1.tx.commit()
在事务提交的时候
2.query is executed
在执行查询之前会做查询,
有可能在缓存查,有可能在数据库里拿, 如果缓存里的和db里的不一致,那么就会出现错误.
只是在某些查询之前,
3.when the application calls Session.flush() explicitly
直接自己调用
如果这种刷新的方式不满意.
可以使用session.setFlushMode()
FlushMode.AUTO 默认情况上面
FlushMode.COMMIT 只有在提交的时候进行刷新
FlushMode.AUTO 除非调用session.flush才进行刷新.
主要是介绍性的内容比较多.事务的api,事务隔离级别,悲观锁和乐观锁.
hibernate的事务就是jdbc的事务.
分布式事务,
try{}catch(){}毕竟是数据库操作,hibernate把异常屏蔽了.
异常不要传到另一层.异常是特定的.
Isolation里面已经有了这个选项
2,代表防止脏读
4,不可重复读
8,事务串行化
hibernate再生成jdbc代码的时候就会象数据库申请
我们在hibernate里面去设置这些东西,hibernate
数据库的锁机制
其实数据库只有一种锁悲观锁
pessimistic
把一个数据提取出来修改的时候,为了防止在修改期间另外一个事务也来修改这个数据,就对这个数据加上了悲观锁
之所以叫悲观,整个改的过程始终把它锁着这就是悲观了.你怕别人在你修改的时候改你的数据,那么就基于一种悲观的预期,数据库之所以采用,是因为数据库要保证数据的正确性.
悲观锁曾经用过,当初读blob 后面加了一个for update
在写的一瞬间数据库是自动加的而且不加也要加
现在讨论的是在读的时候,就有的商量了,对性能影响比较大.
可以采用乐观锁,
它不是一种严格意义上的锁,它是避免并发冲突的机制.只有悲观锁才叫锁
optimistic locking.
它作为管理并发的机制,它要代码参与.
在数据上增加一个数据,这个数据叫做版本.
然后要存这个数据,它的版本回再加1,如果更新版本大于原有版本,就存入了数据.
真的有这个事务来读这个事务.
别人把锁解开了,大于二,不能往里写了,
然后再读出来处理之后再加成三再存进去.
大大提高数据库的利用率.
读过来改一次版本就增加一次.
再类的映射文件里面加一个version标签就可以了.
如果版本冲突了,就不会有问题了.
如果我是个web客户端,
持久化类里面加一个version字段.
加一个version属性,加个version标签,加一个version字段.
version标签必须要写再id标签后面.id字段要紧跟version字段.
写法
hibernate就是加version标签
<version name="">标签 标签必须出现在普通属性的上面
po version属性
table version字段
集合映射:
Set: 无序不重复
Bag: 无序重复
在其他语言里面有,java里面没有,hibernate模拟出来了.
hibernate里面用List模拟了Bag,去掉了List的重复.
po: 集合使用list模拟
table: po一张,集合用一张三个字段的表,外键,集合id,内容
xml: 主键由外键和集合序列共同生成
<idbag 描述无序但重复的集合映射
name="files" 属性名
table="t_files" 对应的表名
>
<collection-id 生成无序的集合序列的
type="integer" 这个集合序列的类型,可以不写
column="cid" 序列号对应的字段
>
<generator 描述序列生成策略
class="increment" 生成策略
这个生成方式,是在应用程序里面有个计数器,给这些记录编辑一个序号.
这个计数器是hibernate的,它通过这个计数器,产生键值.
increment不能给po产生id只能给集合产生id,因为如果两个应用程序应用相同的po
那么在不同的数据库里面产生相同po的id是相同的,那么这两个应用程序就不能相互通信了.
给集合元素编号,存另外一个集合那么就重新开始了.
></generator>
</collection-id>
<key 描述参照主键的外键字段名
column="fdid" 字段名
></key>
<element
type="string" 集合里面的内容都是object
column="file" 集合元素存放的字段名
>
</element>
</idbag>
List: 有序重复
比bag多了一个顺序,利用list就是要使用它的顺序.
List的开销比较大
<list name="descs">
<key
column="fwid" 参照主表主键的外键
></key>
<list-index 用来存放在集合中的顺序
base="0" 默认就是0
column="index" 记录list集合的顺序,对应表里的一个字段
/>
或者 <index column/>
<element
type="string" 集合元素和数据库表种类型对应关系
column="ds" 对应的字段的名字
desc是关键子
></element>
</list>
注意标签出现的顺序.
集合的id是算出来的,比如bag它的collection-id是计算出来的.
而这里用的是集合的下标.因此每个集合都是1,2,3,4,5,6,7.....
Map: <k,v>键值对
map的两个值肯定都要存的.
在map里面这个value是可以重复的,但是key不可以重复
那么这个key value对是不可以重复的.
map里面存的就是Map.Entry,
和list很象,就是<list里面加index,map里面就是key
组件映射:
比集合映射用的要多:
用效率的观点来完成映射
一对一和一对多关系的两端都需要映射,那么就要两张表,级联和inverse等操作.
组件映射把一对一和一对多按照业务要求进行退化.
例如:
po order该order由几个adress
Set里面是po可以用一对多.
除了order使用其他的都不使用,可以说他们是组合关系.
组件映射和关联的强度由关.
address 离开order就没有用了.这样由必要把他们做成组件映射.
address就不再算po了算是组件,如果order只有一个address那么就可以表达成1对1;
1.复杂性降低:
映射越复杂执行效率低,映射越简单效率越高.
2.代码复杂
要考虑cascade和inverse等等操作带来的复杂性.
组件映射
按照可靠的标准,生成组件映射,如果对象可以不把它当作po来看,那么就可以做成组件映射.
如果真正是组合关系.就可以很放心的使用,如果不是那么就要想好了再去使用.
如果是订单和订单项:
订单项和订单就可以使用组件映射.shoppingcart项目可以使用
写法:
pojo
Person{id, name, Address address}
把address拆散了映射到一张表里面.
Address{...,...;...;}
table
只需要一张表,把组件的属性直接的建立到拥有组件对象对应的表里面.
xml
一对一的组件映射的方式
<component 该标签没有映射的作用
name="engine" 属性名
class="Engine" 属性类型
>除了描述属性和类型,还有一个就是把属性名相同的分开,
<property name="engin_no" column="ENGIN_NO"></property>
<property name="type" column="engin_type"></property>
组件中的属性
</component>
再组件pojo那一方,不需要id了.
如果由多个组件那么就增加<component>的数量.
一对多的组件映射的方式
<set
<key
<composite-element class="image">
<property...>
和组件映射是一样一样的.
</composite-element>
</set>
多太是继承关系的正向使用.
接口回调是继承关系的反向使用.
继承映射:
使用的比较多,再数据库的表结构的基础上,把po的继承关系表达出来.
A类 B类 C类
B C 继承自 A类.
父子类的关系,从对象的角度去看,就是一对一的关系.
初始化的时候就可以初始化了.子类的实例里面由他所有父类的实例,
再继承关系里面 b是a 这是正确的.在类型里面是一致性的关系.
b是以个内容更多,更具体的a,a是一个更抽象的b
如果分开存这两个类型.这个表和表之间就是共享主键的关系.
把这种共享主键的一对一就叫做继承映射.
我的关联为什么要有关联.就是为了把父类的属性继承下来所以关联了起来.
普通的一对一那么就没有上面的属性,不去做级联操作,po之间是独立的.
子类的这个必须要父类的属性,这就是一个类一个表.
一个类一个表,
缺点
表的数量比较多.
查询效率低.
统计报表比较复杂.
优点
没有数据冗余,存储的效率高.
和OO的继承结构最接近.
对多态支持良好,支持多态查询
多态查询
我对父类类型的对象进行检索,能找到子类的对象.要使用(HQL)
抽象父类
如果父类是抽象类那么它没有对象,实际上是可以的.
在数据库里面不用父类的表,只有子类的表.那么父类的属性就直接的出现在子类表.
继承关系体现在子类表里面有父类的属性,可是子类之间的表就没有任何关系
它也能体现类的继承关系,但是比刚才的类少了一个表.
缺点
数据冗余比较大,是有冗余的数据定义,父类在子类里面都要定义.
查询效率比较低.
表之间没有主外键关系.那么只能去做unin查询,不能做join查询.
不能显式的支持多态查询.跟父类没有对应的表.
优点
和刚才的一个类一张表相比,没有什么优点.
它的缺点更严重.
如果在程序里面不使用多态,那么就可以选择这个方案,少一张表
所有类一张表
oid,x,b,c,d,e
把左右的类的属性放到一个表里面,这种方式还是可以把继承关系表达出来.
缺点:
很大的数据冗余.每条记录里面除了要描述的子类继续其余子类的属性字段都为null.
所有字段都要能够是空.
表比较大.字段数量多,维护起来比较难,索引很难建立,
优点:
效率高,任何种类的查询都很高,不管做什么都不用做表连接操作.
对多态支持的比较好,这个表是父类的表,子类算是寄宿的.
有一个问题,但是不知道查出来的对象的实际类型.这个问题可以用加一个辨别字段来解决
因为就只有一个表,对数据库的schema的结构非常的简单.
程序员最大的追求,速度快,简单.人和技术都一样最忌讳没有特点.
java 非常突出的优点 跨平台 安全性
练习 一个类一个表
先设计一个场景.
payment
reason
amount
cashpament
carrency
cardpament
owner
bank
三个类每个类一个表
注意在写子类带参的构造方法的时候,我们应该把父类构造要的参数也传进来.用super构造父类.
xml
三个类就一个class标签
用一个类一个表的时候必然要做join操作,所以子类利用hibernate的
<joined-subclass 子类的描述
name
table
>
<key 是个外键引用自父类的主键,在自己这里是主键和父类共享主键
column="外键名"/>
<property 子类的属性
/>
</joined-subclass>
今天重点组件映射和继承映射
父类没有表,
...
数据的结构在面向对象里面已经设计好了,
现在任务是持久化到数据库,
手段和结果都不会影响原因.
ooad不会改变,只是映射的方式和数据库里的表没有影响.
这种情况在one-to-one比较明显.继承有三种方法来映射.
子类的id都是继承自父类的id,如果你不给子类id属性,并不会对代码产生影响.
<id name="pid" column="pid"></id>
<discriminator column="type" type="string"></discriminator>
<property name="reason"></property>
<subclass name="CashPayment" discriminator-value="cash">
<property name="currency"></property>
</subclass>
HQL:
hql使用来操作对象的查询语言,这种语言面对的直接就是对象
左外连接:
能连的连接,不能连的用null填充.
如果利用多张表的那种方式就会左两个左外连接生成一张表.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -