hibernate读后总结
马士兵视频
http://www.youku.com/playlist_show/id_3923405_ascending_1_mode_pic_page_4.html
马士兵文档
http://www.cnblogs.com/alamps/archive/2012/05/13/2498332.html
1.增
在hibernate中对象有3中状态:
1.Transient(刚刚new出来)内存中一个对象,没id,缓存中也没有
2.Persistent 内存中有,缓存中有,数据库有(Id)
3.Detached 内存有,缓存没有,数据库有id
2.删除
删除是根据id来删除的
3.查询
load 并不会执行sql语句。只是返回一个代理对象,只有用到对象时候才会执行sql语句
不存再对应记录的时候 不会报错
get 立即执行sql语句,不会延迟
不存在对应记录的时候会报错
load的代理对象:
------------------------------------------------------------------------------------------------------------------------------
映射关系:对象之间的关系
1、一对一
单项
双向
2、一对多
单项
使用注解的时候 要在一的一方使用onetomany,并且还要有@JoinColumn(name="XXXXX")这个属性,不然hibernate会默认创建一张中间表
双向
3、多对一
单项
双向
4、多对多
单项
双向
5.组建映射
表现形式
在数据库表中是一个表结构。在java中是两个类一个中包含一个
比如:用户实体类+用户详细信息实体类
在xml中使用component标签来表示
在注解中使用@embedded(这里和组合主键有点像)
------------------------------------------------------------------------------------------------------------------------------
级联关键词
@ManyToOne(cascade=(CascadeType.ALL))
merge合并
all所有操作
.双向关系在程序中需要设置双相关联
.双向的一定要设定mappedBy
.双向关联最好只在一方设FetchType.EAGER,不然会出现多次加载 相当于 inverse="true"
------------------------------------------------------------------------------------------------------------------------------
hibernate性能优化
1.session.clear() 批量查询的时候来session.clear()
2.1+n问题(如果在一个对象中关联另外一个对象,主要是针对manyToOne的)
解决方法:{1.FetchType.Lazy
2.使用createCriteria(默认是join的)类似于在createQuery(from A a left outer join B b on a.id= b.id)这个也是一种
注意:也可以说createCriteria使用了join的方式
3.BatchSize 设置在one
}
3.List 和 Iterator
表结构如下:
Category 和 Topic
区别一、获取方式不一样
。List直接把对象全部取出来
。把主键先取出来,用到对象的时候根据主键从数据库取
List测试代码如下:
@Test
public void testQueryList() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
List<Category> categories = (List<Category>)session.createQuery("from Category").list();
for(Category c : categories) {
System.out.println(c.getName());
}
session.getTransaction().commit();
session.close();
}
运行结果:(直接把对象全部取出来)
Hibernate:
select
category0_.id as id0_,
category0_.name as name0_
from
Category category0_
c0
c1
c2
c3
c4
c5
c6
c7
c8
c9
Iterator
@Test
public void testQueryIterate() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
Iterator<Category> categories = (Iterator<Category>)session.createQuery("from Category").iterate();
while(categories.hasNext()) {
Category c = categories.next();
System.out.println(c.getName());
}
session.getTransaction().commit();
session.close();
}
运行结果:把主键先取出来,用到对象的时候才从数据库取
Hibernate:
select
category0_.id as col_0_0_
from
Category category0_
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c0
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c1
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c2
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c3
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c4
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c5
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c6
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c7
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c8
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c9
区别二、。List 没法利用session级的查询缓存 查询第二次仍然会发出sql查询
。Iterator利用session级的查询缓存 查询第二次不会发出sql查询
List代码
@Test
public void testQueryList() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
List<Category> categories = (List<Category>)session.createQuery("from Category").list();
for(Category c : categories) {
System.out.println(c.getName());
}
List<Category> categories2 = (List<Category>)session.createQuery("from Category").list();
for(Category c : categories2) {
System.out.println(c.getName());
}
session.getTransaction().commit();
session.close();
}
运行结果:
Hibernate:
select
category0_.id as id0_,
category0_.name as name0_
from
Category category0_
c0
c1
c2
c3
c4
c5
c6
c7
c8
c9
Hibernate:
select
category0_.id as id0_,
category0_.name as name0_
from
Category category0_
c0
c1
c2
c3
c4
c5
c6
c7
c8
c9
Iterator测试代码
@Test
public void testQueryIterate() {
Session session = sf.openSession();
session.beginTransaction();
//List<Topic> topics = (List<Topic>)session.createCriteria(Topic.class).list();
Iterator<Category> categories = (Iterator<Category>)session.createQuery("from Category").iterate();
while(categories.hasNext()) {
Category c = categories.next();
System.out.println(c.getName());
}
Iterator<Category> categories2 = (Iterator<Category>)session.createQuery("from Category").iterate();
while(categories2.hasNext()) {
Category c = categories2.next();
System.out.println(c.getName());
}
session.getTransaction().commit();
session.close();
}
运行结果
Hibernate:
select
category0_.id as col_0_0_
from
Category category0_
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c0
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c1
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c2
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c3
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c4
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c5
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c6
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c7
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c8
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c9
Hibernate:
select
category0_.id as col_0_0_
from
Category category0_
c0
c1
c2
c3
c4
c5
c6
c7
c8
c9
注意:第一次使用list,第二次使用Iterator,也可以使用缓存
4.hibernate缓存
什么是缓存?
介于客户端和数据源之间,源于数据源,快速给客户端提供数据的数据源
缓存的算法:(缓存算法定义:内存中缓存满了之后怎么处理?)
A、最近不用的
B、使用最少的
C、最早进入的
cpu闪存 > 内存 > 硬盘 > 数据库
A、一级缓存
session级别的缓存
@Test
public void testCache1() {
Session session = sf.openSession();
session.beginTransaction();
Category c = (Category)session.load(Category.class, 1);
System.out.println(c.getName());
Category c2 = (Category)session.load(Category.class, 1);
System.out.println(c2.getName());
session.getTransaction().commit();
session.close();
}
运行结果:
Hibernate:
select
category0_.id as id0_0_,
category0_.name as name0_0_
from
Category category0_
where
category0_.id=?
c0
c0
一级缓存只在session范围内,如果在其他session中如下:这样就不能从缓存中查询,这样就需要使用二级缓存
@Test
public void testCache2() {
Session session = sf.openSession();
session.beginTransaction();
Category c = (Category)session.load(Category.class, 1);
System.out.println(c.getName());
session.getTransaction().commit();
session.close();
Session session2 = sf.openSession();
session2.beginTransaction();
Category c2 = (Category)session2.load(Category.class, 1);
System.out.println(c2.getName());
session2.getTransaction().commit();
session2.close();
}
B、二级缓存
sessionFactory级别的缓存,对session来说是公用的
使用条件:
1、经常访问
2、改动不频繁
3、数量有限
使用
1、加注解 @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
2、增加配置
<!-- 开关 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 使用二级缓存的类别 -->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!--
<property name="cache.use_query_cache">true</property> -->
3、ehcache配置xml
4、添加ehcache.jar
{
默认情况下load、iterator会使用二级缓存
默认情况下List查询出来的数据 会加载到二级缓存中,但是查询的时候不使用二级缓存
}
C、三级缓存(查询缓存) 依赖与二级缓存
重复的查询(相同的sql语句)会使用查询缓存
使用
在配置文件中打开查询缓存
<property name="cache.use_query_cache">true</property>
//join fetch
@Test
public void testQueryCache() {
Session session = sf.openSession();
session.beginTransaction();
List<Category> categories = (List<Category>)session.createQuery("from Category")
.setCacheable(true).list();
session.getTransaction().commit();
session.close();
Session session2 = sf.openSession();
session2.beginTransaction();
List<Category> categories2 = (List<Category>)session2.createQuery("from Category")
.setCacheable(true).list();
session2.getTransaction().commit();
session2.close();
}
5、事务并发处理
事物特性:ACID
原子性(Atomicity)、
一致性(Consistency)、
隔离性(Isolation)、
持久性(Durability)
事物并发出现的问题:
A、丢失更新(一般数据库【支持事务】都有这块的处理)
B、脏读(读了另外一个事务没提交的数据)
C、不可重复读(同一个事务读了两次,两次数据都不一样)
D、幻读(两次查询不一样) 一般不考虑
处理事务并发---------》
数据库事务隔离级别:
A、read-uncommitted 允许读取没提交的数据 代码:1
B、read-committed 读取提交的数据 代码:2
C、repeatable read 不可重复读(MySql默认的事务隔离级别) 代码:4
D、serial 禁止事务并发(一般适用数据库调优) 代码: 8
hibernate处理事务并发
1、hibernate事务级别设定
hibernate.connection.isolation=2 不设置的话 默认为数据库设定值可以解决赃读、丢失更新
2、使用悲观锁,乐观锁
悲观锁,乐观锁 解决repeatable read的问题【还是依赖数据库本身机制】
A、悲观锁
借助数据库的锁,在数据库中给要读取的数据设定一把锁.load(XXX.class,LockMode.UPGRADE)
生成的sql语句中多一个【for update】
B、乐观锁
查询的时候给字段设定一个标识版本字段,每改动一次版本号改动一次
做法
在实体类上添加字段:
private int version;
@Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}