标签:
Hibernate定义的映射类型都是小写的
Hibernate框架提供了多种主键生成方式,使用时,通过hbm.xml文件<id>元素部分,利用<generator class="主键生成类型">指定。
1)sequence
--是采用sequence来生成ID,针对的是Oracle数据库
--<generator class="sequence">
<param name="sequence">序列名</param>
</generator>
2)identity
--采用数据库主键自增长的机制来生成ID,针对初Oracle外的数据库,如MySql,SqlServer
--<generator class="identity"></generator>
注意:创建表时,指定主键可以自增长
3)native
--Hibernate会根据你设置的方言,判断出是哪种数据库,如果是Oracle就使用sequence方式生成主键,如果不是就使用identity方式生成主键。
--<generator class="native">
<param name="sequence">序列名</param>
</generator>
4)increment
--也是采用自增长的方式生成主键,但是这种方式不是用数据库的机制,而是Hibernate自己的机制,并且适用于所有的数据库。
--Hibernate提供一个组件,在需要主键时,它会从表中查询出最大的ID值,然后+1,以此结果作为新的主键。
--<generator class="increment"></generator>
--注意:通常不用,原因时在并发量大时可能会出现并发问题。
5)assigned
--Hibernate放弃生成主键,由程序员自行维护主键字段的值。
--<generator class="assigned"></generator>
6)uuid、hilo(高低位算法)
--采用uuid/hilo算法来生成一个主键,该主键是一个没有规律的,不重复的,长的字符串
--<generator class="uuid"></generator>
1)什么是一级缓存?
--Hibernate在创建Session时,会自动的给Session分配一块内存空间,用于存储该Session取到的对象值,那么这个内存空间就是一级缓存,或称为Session级缓存。
2)一级缓存的维护
--在使用Session进行查询时,Hibernate会优先上一级缓存中查找对应的数据,如果缓存中已经存在则直接返回,不用查库。如果缓存中不存在,再去执行查询数据库的行为。减少了对数据库的访问。
--Session在执行完查询数据库后,会将新查到的数据自动放入一级缓存中。
3)一级缓存的管理
--session.evict(Object);
把传入的对象从一级缓存中移除。
--session.clear();
移除一级缓存中所有的对象。
--session.close();
关闭session,释放缓存空间。
4)*重点关注
--Session级缓存是独享的,即每创建一个Session
对象,就给这个对象分配一个独立的缓存区,
其他的Session不能访问当前Session的缓存区。
--Session仅仅是把查询到的数据放入缓存区,
没有查询过的,是不会放入缓存区。
注意:
--一级缓存缓存的目标只能是实体对象
1)Hibernate中实体对象具有3种状态,围绕着这三种状态的转换过程,我们称之为对象持久性。
2)3种状态
a、临时态
--通过new创建的对象是临时态的
--临时态的对象可以被垃圾回收
--持久态的对象通过delete方法可以转化为临时态
*b、持久态
--通过session的save,update方法可以将临时态/游离态的对象转化为持久态
--通过session的get,load方法将查询到的对象默认置为持久态
特点:
--持久态的对象不能被垃圾回收
--持久态的对象存在于一级缓存中,由Session负责管理
--持久态的对象可以自动的与数据库同步更新
--持久态的对象同步的时机是事务提交时即ts.commit,实际上是调用session.flush()时触发同步的,commit方法中调用了session.flush()
注意:session.flush();//将缓存中改变的对象数据更新到数据库记录仅仅是触发同步,但并没有提交事务
即:ts.commit()=session.flush()+原有事务提交功能
c、游离态
--通过session的evict,clear,close方法可以将持久态的对象
转化为游离态(从一级缓存中移除)
--游离态的对象可以被垃圾回收
session.flash()和缓存相关。执行时会清除session缓存并向数据库发送SQL语句并执行,但此时如果数据库当前存在一个事务,数据库会先将这些SQL语句缓存起来,那么此时在数据库中是无法看到SQL语句执行结果的。除非执行commit提交了事务。只要没有执行commit()方法,就能通过rollback()方法进行回滚。
1)session在什么情况下清理缓存:
--默认情况下,当应用程序提交事务,如:Transaction.commit;
--当我们显示调用flush的时候
--在执行某些查询的时候,如:iterate
2)session.flush()主要完成两件事情:
--清理缓存
--执行sql
3)flush执行的顺序:hibernate按照save,update,delete顺序提交相关操作commit()和事务相关。执行时会先隐式调用flush()方法,再提交事务。执行之后无法rollback()进行回滚。
1)什么是延迟加载?
Hibernate中有一些方法,在查询时并不是立刻查询数据库返回结果,而是给返回一个空(属性值)对象,当我们真正去使用这个对象getter时,才触发查询。这种将查询时机推迟到使用时间的机制,称之为延迟加载。
2)哪些方法具有延迟加载机制
a、session.load(Emp.class, id);//查询单个对象
--当调用该方法时,Hibernate并没有立刻查询数据库,而是new Emp(),然后setId(id),即我们得到的对象是一个只有id有值,其他属性为空的对象。
--当我们调用该对象时,比如e.getName()时,此时会触发查询。我们使用这个对象任何一个属性都可以触发查询,但使用id却不触发。
--不管是调用哪个属性触发的查询,那么本次查询都会将当前的记录完整的返回,此时对象中属性都可以有值。
b、query.iterate();//查询多个对象集合
--当调用该方法时,Hibernate会返回一个迭代器,迭代器中存的是一个空(属性空)的对象,该对象中仅仅是id有值,其他属性为空。
--此时,Hibernate执行了一次查询,但是为了效率,仅仅是查询出了ID的值select id from emp;
--当我们从迭代器中读取出对象,并且使用该对象时会触发真正的查询,将其他属性都查询出来,此时是根据当前对象的ID查询当前ID对应的一条记录,并非是查询所有的记录。
c、关联属性查询
3)延迟加载的好处
--可以提升内存资源的使用率
--可以降低对数据的并发访问(使用时机错开)
4)在使用延迟加载时要注意,不能在使用对象前关闭Session否则会报错:
LazeInitializationException:No Session
两种解决办法:
--不使用延迟加载的方法session.load()、query.iterate(),可使用session.get()、query.list()等
--在使用对象后关闭Session
5)在项目中,采用OpenSessionInView的机制来保证session关闭的时机。
a、OpenSessionInView指的是在视图层加载阶段保证Session处于非close状态,而视图层加载完成后,再关闭Session。
b、如何实现
--Servlet:监听器
public class MyFilter implents Filter{ public void doFilter(request,response,chain){ //添加逻辑--前期处理 //通过过滤器,调用后续资源 chain.doFilter(request,response); //添加逻辑--后期处理(关闭session) } }--Struts2:拦截器
public class MyInterceptor implements Interceptor{ public String intercept(ActionInvocation in){ //前期处理 in.invoke();//执行Action--Result //后期处理(关闭session) } }--Spring:AOP
b、代码解读
public class Emp$.$.EnhancerByCGLIB$.$.88def978 extends Emp {//.是分割示意用,避免排版紊乱
//覆写get方法
public String getName() {
if(没有查询过) {
1.查询并给当前对象所有属性赋值
2.设置当前对象为查询后的状态
}
return this.name;
}
...
}
Session session = HibernateUtil.getSession(); Transaction ts = session.beginTransaction(); for(int i=0;i<10000;i++){//不做处理,容易使一级缓存溢出 Foo foo = new Foo();//foo处于临时态 //TODO 设置不同属性 session.save(foo);//foo处于持久状态,会放入缓存 if(i%20==0){ session.flush();//将缓存foo对象同步 session.clear();//清除缓存foo对象 } } tv.commit();//不能分批提交,即不可破坏事务的完整性 session.close();
for(String id : ids){//如果数据量大,所有取出的对象放进一级缓存而不作处理,容易溢出 Foo foo = (Foo)session.load(Foo.class,id) //处理foo session.evict(foo);//手动移除对象,提升健壮性 }
标签:
原文地址:http://blog.csdn.net/daijin888888/article/details/51605071