- 浏览: 14897 次
- 性别:
- 来自: 上海
文章分类
最新评论
前言:
对象的三个状态:
临时状态(Transient):当new一个实体对象后,这个对象处于临时状态,即这个对象只是一个保存临时数据的内存区域,如果没有变量引用这个对象,则会被jre垃圾回收机制回收。这个对象所保存的数据与数据库没有任何关系,除非通过Session的save或者SaveOrUpdate把临时对象与数据库关联,并把数据插入或者更新到数据库,这个对象才转换为持久对象。
持久状态(Persistent): 持久化对象的实例在数据库中有对应的记录,并拥有一个持久化表示(ID),既有个session跟他相连。对持久化对象进行delete操作后,数据库中对应的记录将被删除,那么持久化对象与数据库记录不再存在对应关系,持久化对象变成临时状态。持久化对象被修改变更后,不会马上同步到数据库,直到数据库事务提交。在同步之前,持久化对象是脏的(Dirty)。
游离状态(Detached):当Session进行了Close、Clear或者evict后,持久化对象虽然拥有持久化标识符和与数据库对应记录一致的值,但是因为会话已经消失,对象不在持久化管理之内,所以处于游离
常用方法:
load()和get()方法
都能根据给定OID从数据库中加载一个持久化对象.当数据库中不存在与OID对应的记录时,load()方法抛出空指针异常,而get()方法返回null.检索策略不同,默认情况下load()方法会采用延迟检索策略加载持久化对象,除非lazy=false,而get()方法总是采用立即检索策略.
saveOrUpdate()方法
如果传入参数是临时对象,调用save()方法,如果参数是游离对象,调用update()方法,如果参数是持久化对象,直接返回.
merge()方法
把一个游离对象的属性复制到一个持久化对象中.
Persist()和save()方法
Persist()把一个瞬态的实例持久化,但是并"不保证"标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。
save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert
flush() 和clear()/evict()方法
flush():强制持久化sessiong缓存中的持久化对象
clear()/evict():清除session缓存中的实体,目的是释放内存
Session的commit()和flush()方法的区别,flush()方法进行清理缓存的操作,执行一系列的SQL语句,但不会提交事务;
commit()方法会先调用flush(),然后提交事务.提交事务意味着对数据库所作的更新被永久保存下来.
一、部署hibernate:
最基本的部署需要将以下jar包放在lib目录下:
各配置目录层次如下:
配置hibernate.cfg.xml(以oracle为例)
配置User.hbm.xml
编写实体类(略),编写Dao类(基本的增删改查)如下:
public class UserDao {
public void save(){
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
Transaction ts = session.beginTransaction();
User user = new User();
// 保存
// user.setUsername("test1");
// user.setUserpwd("787787");
// user.setAge("26");
// user.setJob("developer");
// user.setLevel("3");
// try {
// session.save(user);
// ts.commit();
// System.out.println("保存成功");
// }catch(HibernateException exx) {
// exx.printStackTrace();
// }
//删除
// User user2 = (User) session.get(User.class, 2L);
// try {
// session.delete(user2);
// ts.commit();
// System.out.println("删除成功");
// }catch(HibernateException exx) {
// exx.printStackTrace();
// }
// 更改
// User user2 = (User) session.get(User.class, 2L);
// user2.setJob("superman");
// try {
// session.update(user2);
// ts.commit();
// System.out.println("更新成功");
// }catch(HibernateException exx) {
// exx.printStackTrace();
// }
// hql查询
// Query query = session.createQuery("from User");
// List users = query.list();
// Iterator iterator = users.iterator();
// while(iterator.hasNext()){
// user = (User) iterator.next();
// System.out.println("用户的年纪是"+user.getAge());
// }
// sql查询
// List users = session.createSQLQuery("select t.* from t_user t").list();
//原生态sql查询,hibernate不会把查询结果封装成实体类的
List users = session.createSQLQuery("select t.* from t_user t").addEntity(User.class).list();
Iterator it = users.iterator();
while(it.hasNext()){
user = (User) it.next();
System.out.println("用户的年纪是"+user.getAge());
// Object object[] = (Object[]) it.next();
// System.out.println("用户的ID是"+object[0]+";用户的职业是"+object[4]);
}
session.close();
sf.close();
}
}
注解:
要使用hibernate的注解,必须在hibernate.cfg.xml文件中加入<mapping class="bean.User"/>,否则框架是找不到实体类的。
使用log4j,web工程lib目录下加入log4j的jar包,当tomcat运行时,会自动去加载src根目录下的log4j.properties文件
一对多,多对多:
一对多核心:在“一(level)”中声明“多(user)”的对象为set类型,level.hbm.xml配置文件中one-to-many标签
多对一:在“多(user)”中声明“一(room)”的对象为Room类型,user.hbm.xml 配置文件中many-to-one标签
多对多:“多(course)”和“多(user)”,都需要声明一个set类型对象,用于存储对方的实体类。需要建立一个第三方的关联表,
详见代码
关于映射文件的常用标签:
cascade属性
cascade属性值 描述
none 在保存更新时,忽略其他关联对象,他是cascade默认属性
save-update 当通过Session的save(),update()以及saveOrUpdate()方法来保存
或更新当前对象时,及联保存所有关联的新建的临时对象,并且及联更新所有关联的游离对象
delete 当通过session的delete()方法删除当前对象时,及联删除所有对象
all 包含save-update及delete行为,此外对当前对象执行evict()或lock
()操作时,也会对所有关联的持久化对象执行evict()或lock()操作
delete-orphan 删除所有和当前对象解除关联关系的对象
all-delete-orphan 包含all和delete-orphan
用于控制insert or update 语句的映射属性
<property>元素的insert属性 如为false,在insert中不包含该字段,默认为true
<property>元素的update属性 如为false,在update中不包含该字段,默认为true
<class>元素的mutable属性 如为false,等价于所有字段的update属性为false,默认为true
<property>元素的dunameic-insert属性 如为true,表明动态生成insert语句,只有不为null,才会包含insert语句中,默认false
<property>元素的dunameic-update属性 如为true,表明动态生成update语句,只有不为null,才会包含insert语句中,默认false
<class>元素的dunameic-insert属性如为true,表明等价于所有字段动态生成insert语句,只有不为null,才会包含insert语句中 ,默认false
<class>元素的dunameic-update属性如为true,表明等价于所有字段动态生成update语句,只有不为null,才会包含insert语句中 ,默认false
fetch,outer-join 和 lazy 主要用于级联查询(select) 而 inverse和cascade主要用于级联增加,删除,修改(sava-update,delete)。
lazy是延时的意思,如果lazy=true,那么就是说数据库中关联子表的信息在hibernate容器启动的时候不会加载,而是在你真正的访问到字表非标识字段的时候,才会去加载。 反之,如果lazy=false的话,就是说,子表的信息会同主表信息同时加载。
cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。
fetch (可选 - 默认为 select): 在外连接抓取(outer-join fetching)和序列选择抓取(sequential select fetching)两者中选择其一。
outer-join关键字(many-to-one的情况)
outer-join关键字有3个值,分别是true,false,auto,默认是auto。
true: 表示使用外连接抓取关联的内容,这里的意思是当使用load(OrderLineItem.class,"id")时,Hibernate只生成一条SQL语句将OrderLineItem与他的父亲Order全部初始化。
select * from OrderLineItem o left join Order p on o.OrderId=p.OrderId where o.OrderLineItem_Id=?
from OrderLineItem o left join fetch o.OrderId
false: 表示不使用外连接抓取关联的内容,当load(OrderLineItem.class,"id")时,Hibernate生成两条SQL语句,一条查询 OrderLineItem表,另一条查询Order表。这样的好处是可以设置延迟加载,此处要将Order类设置为lazy=true。
select * from OrderLineItem o where o.OrderLineItem_Id=?
select * from Order p where p.OrderId=?
auto:具体是ture还是false看hibernate.cfg.xml中的配置
注意:如果使用HQL查询OrderLineItem,如 from OrderLineItem o where o.id='id',总是不使用外部抓取,及outer-join失效。
2、outer-join(集合)
由于集合可以设置lazy="true",所以lazy与outer-join不能同时为true,当lazy="true"时,outer-join将一直是false,如果lazy="false",则outer-join用法与1同
3.如果集合被声明为lazy=true,在HQL中如果显式的使用 join fetch 则延迟加载失效。
4.在one-to-many的one端显式设置fecth="join",则无论如何都采取预先抓取(生成一个SQl),延迟加载失效(生成两个SQL)
5.many- to-one的延迟加载是在配置文件的class标签设置lazy="true",one-to-many和many-to-many的延迟加载是在 set标签中设置lazy="true"。而one-to-one不只要在calss标签设置lazy="true",而且要在one-to-one标签 中设置constrained="true".
Hibernate的缓存机制
缓存是位于应用程序与物理数据源之间,用于临时存放复制数据的内存区域,目的是为了减少应用程序对物理数据源访问的次数,从而提高应用程序的运行性能.
Hibernate在查询数据时,首先到缓存中去查找,如果找到就直接使用,找不到的时候就会从物理数据源中检索,所以,把频繁使用的数据加载到缓存区后,就可以大大减少应用程序对物理数据源的访问,使得程序的运行性能明显的提升.
Hibernate缓存分类:
Session缓存,一级缓存.
SessionFactory的缓存分为内置缓存和外置缓存.内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定义SQL语句等),对于应用程序来说,它是只读的.外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备.
Hibernate的缓存范围
Hibernate的一级缓存和二级缓存都位于均位于持久层,且均用于存放数据库数据的副本,最大的区别就是缓存的范围各不一样.
缓存的范围分为3类:
1.事务范围
事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围.
2.应用范围
应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围.
3.集群范围
在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致,缓存中的数据通常采用对象的松散数据形式.
Hibernate的缓存管理
一级缓存的管理:
evit(Object obj) 将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象.
clear() 将一级缓存中的所有持久化对象清除,释放其占用的内存资源
contains(Object obj) 判断指定的对象是否存在于一级缓存中.
flush() 刷新一级缓存区的内容,使之与数据库数据保持同步.
二级缓存的管理:
evict(Class arg0, Serializable arg1) 将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源.
Java代码
sessionFactory.evict(Customer.class, new Integer(1));
sessionFactory.evict(Customer.class, new Integer(1));
evict(Class arg0) 将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源.
Java代码
sessionFactory.evict(Customer.class);
sessionFactory.evict(Customer.class);
evictCollection(String arg0) 将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源.
Java代码
sessionFactory.evictCollection("Customer.orders");
sessionFactory.evictCollection("Customer.orders");
Hibernate的二级缓存的配置
首先,不是所有的数据都适合放在二级缓存中,看一下,什么样的数据适合放在二级缓存中来?什么样的数据不适合放在二级缓存中来?
下面这几种情况就不适合加载到二级缓存中:
1.经常被修改的数据
2.绝对不允许出现并发访问的数据
3.与其他应用共享的数据
下面这己种情况合适加载到二级缓存中:
1.数据更新频率低
2.允许偶尔出现并发问题的非重要数据
3.不会被并发访问的数据
4.常量数据
5.不会被第三方修改的数据
Hibernate的二级缓存功能是靠配置二级缓存插件来实现的,Hibernate为了集成这些插件,Hibernate提供了org.hibernate.cache.CacheProvider借口,它充当缓存插件与Hibernate之间的适配器 .
常用的二级缓存插件
EHCache org.hibernate.cache.EhCacheProvider
OSCache org.hibernate.cache.OSCacheProvider
SwarmCahe org.hibernate.cache.SwarmCacheProvider
JBossCache org.hibernate.cache.TreeCacheProvider
简单介绍一下EHCache的配置
hibernate.cfg.xml
Xml代码
<hibernate-configuration>
<session-factory>
<!-- 设置二级缓存插件EHCache的Provider类-->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!-- 启动"查询缓存" -->
<property name="hibernate.cache.use_query_cache">
true
</property>
<!-- 启用二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
</session-factory>
</hibernate-configuration>
<hibernate-configuration>
<session-factory>
<!-- 设置二级缓存插件EHCache的Provider类-->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!-- 启动"查询缓存" -->
<property name="hibernate.cache.use_query_cache">
true
</property>
</session-factory>
</hibernate-configuration>
ehcache.xml
Xml代码
<ehcache>
<!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 overflowToDisk属性用来配置当缓存存储的数据达到maxInMemory限制时是否overflow到磁盘上-->
<diskStore path="java.io.tmpdir"/>
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
</ehcache>
<ehcache>
<!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 -->
<diskStore path="java.io.tmpdir"/>
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
</ehcache>
****.hbm.xml
Xml代码
<?xml version="1.0" encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class>
<!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->
<cache usage="read-write"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class>
<!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->
<cache usage="read-write"/>
</class>
</hibernate-mapping>
缓存的方式有四种,分别为:
CacheConcurrencyStrategy.NONE
CacheConcurrencyStrategy.READ_ONLY,只读模式,在此模式下,如果对数据进行更新操作,会有异常;
CacheConcurrencyStrategy.READ_WRITE,读写模式在更新缓存的时候会把缓存里面的数据换成一个锁,其它事务如果去取相应的缓存数据,发现被锁了,直接就去数据库查询;
CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,不严格的读写模式则不会的缓存数据加锁;
CacheConcurrencyStrategy.TRANSACTIONAL,事务模式指缓存支持事务,当事务回滚时,缓存也能回滚,只支持JTA环境。
如何解决Hibernate 的N+1问题
2012-05-24 21:41:26| 分类: 默认分类 | 标签: |字号大中小 订阅
【问题】什么时候会遇到N+1的问题?
【备注】 Hibernate默认抓取策略是fetch="select",不是fetch="join",这都是为了延迟加载而准备的。
【出现情况】
1)一对多(one-to-many) ,在1的这方,通过1条sql查找得到了1个对象,由于关联的存在 ,那么又需要将这个对象关联的集合取出,所以合集数量是n还要发出n条sql,于是本来的1条sql查询变成了 1 +n条 。
2)多对一<many-to-one> ,在多的这方,通过1条sql查询得到了n个对象,由于关联的存在,也会将这n个对象对应的1 方的对象取出, 于是本来的1条sql查询变成了1 +n条 。
3)iterator 查询时,一定先去缓存中找(1条sql查集合,只查出ID),在没命中时,会再按ID到库中逐一查找, 产生1+n条SQL。
【解决办法】
1)lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。
2)使用二级缓存, 二级缓存的应用将不怕1+N 问题,因为即使第一次查询很慢(未命中),以后查询直接缓存命中也是很快的。刚好又利用了1+N 。
3 ) 当然你也可以设定fetch="join",一次关联表全查出来,但失去了延迟加载的特性。
<!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数,overflowToDisk属性用来配置当缓存存储的数据达到maxInMemory限制时是否overflow到磁盘上 -->
关于数据库并发问题:
1. 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。
一个典型的依赖数据库的悲观锁调用:select * from account where name=”Erica” for update这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录,在Hibernate使用悲观锁十分容易,但实际应用中悲观锁是很少被使用的,因为它大大限制了并发性:
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。
2. 乐观锁的工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
Hibernate为乐观锁提供了3中实现:
基于version
基于timestamp
为遗留项目添加添加乐观锁
例子:
Hibernate乐观锁的的使用:
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();
MyEntity et1 = session1.load(MyEntity.class, id);
MyEntity et2 = session2.load(MyEntity.class, id);
//这里 et1, et2为同一条数据
Transaction tx1 = session1.beginTransaction();
//事务1开始
et1.setName(“Entity1”);
//事务1中对该数据修改
tx1.commit();
session1.close();
//事务1提交
Transaction tx2 = session2.beginTransaction();
//事务2开始
et2.setName(“Entity2”);
//事务2中对该数据修改
tx2.commit();
session2.close();
//事务2提交
在事务2提交时,因为它提交的数据比事务1提交后的数据旧,所以hibernate会抛出一个org.hibernate.StaleObjectStateException异常。
回到前面的问题,Hibernate怎么知道事务2提交的数据比事务1提交后的数据旧呢?
因为MyEntity有个version版本控制字段。
回头看看上面的源代码中的:
MyEntity et1 = session1.load(MyEntity.class, id);
MyEntity et2 = session2.load(MyEntity.class, id);
这里,et1.version==et2.version,比如此时version=1,
当事务1提交后,该数据的版本控制字段version=version+1=2,而事务2提交时version=1<2所以Hibernate认为事务2提交的数据为过时数据,抛出异常。
二、数据库事务并发可能带来的问题
1. 第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。
在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,T4时刻事务2取出了同一条数据,T5时刻事务1将age字段值更新为30,T6时刻事务2更新age为35并提交了数据,但是T7事务1回滚了事务age最后的值依然为20,事务2的更新丢失了,这种情况就叫做"第一类丢失更新(lost update)"。
2. 脏读(dirty read):如果第二个事务查询到第一个事务还未提交的更新数据,形成脏读。
在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,在T5时刻事务1将age的值更新为30,但是事务还未提交,T6时刻事务2读取同一条记录,获得age的值为30,但是事务1还未提交,若在T7时刻事务1回滚了事务2的数据就是错误的数据(脏数据),这种情况叫做" 脏读(dirty read)"。
3. 虚读(phantom read):一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成两次结果不一致,只是另一个事务在这两次查询中间插入或者删除了数据造成的。
在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1从数据库中查询所有记录,记录总共有一条,T4时刻事务2向数据库中插入一条记录,T6时刻事务2提交事务。T7事务1再次查询数据数据时,记录变成两条了。这种情况是"虚读(phantom read)"。
4. 不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事务更新了该数据,两次结果相异,不可信任。
在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,此时age=20,T4时刻事务2查询同一条数据,T5事务2更新数据age=30,T6时刻事务2提交事务,T7事务1查询同一条数据,发现数据与第一次不一致。这种情况就是"不可重复读(unrepeated read)"。
5. 第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。
在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1更新数据age=25,T5时刻事务2更新数据age=30,T6时刻提交事务,T7时刻事务2提交事务,把事务1的更新覆盖了。这种情况就是"第二类丢失更新(second lost updates)"。
三、数据库事务隔离级别
为了解决数据库事务并发运行时的各种问题数据库系统提供四种事务隔离级别:
1. Serializable 串行化
2. Repeatable Read 可重复读
3. Read Commited 可读已提交
4. Read Uncommited 可读未提交
Jndi数据源配置:
name:给数据源设置名字(jndi)
auth:表示数据源由谁管理
type:类型
maxActive:在连接池中最大的激活连接数 ,设 0 为没有限制
maxIdle:在连接池中最大的保留(空闲)连接数 ,设 0 为没有限制
maxWait:客户端在队列池中最大等待时间 ,当请求超过最大连接数时,就会进入队列等待。单位为 ms, 取值-1,表示无限等待,超过时间会出错误信息
对象的三个状态:
临时状态(Transient):当new一个实体对象后,这个对象处于临时状态,即这个对象只是一个保存临时数据的内存区域,如果没有变量引用这个对象,则会被jre垃圾回收机制回收。这个对象所保存的数据与数据库没有任何关系,除非通过Session的save或者SaveOrUpdate把临时对象与数据库关联,并把数据插入或者更新到数据库,这个对象才转换为持久对象。
持久状态(Persistent): 持久化对象的实例在数据库中有对应的记录,并拥有一个持久化表示(ID),既有个session跟他相连。对持久化对象进行delete操作后,数据库中对应的记录将被删除,那么持久化对象与数据库记录不再存在对应关系,持久化对象变成临时状态。持久化对象被修改变更后,不会马上同步到数据库,直到数据库事务提交。在同步之前,持久化对象是脏的(Dirty)。
游离状态(Detached):当Session进行了Close、Clear或者evict后,持久化对象虽然拥有持久化标识符和与数据库对应记录一致的值,但是因为会话已经消失,对象不在持久化管理之内,所以处于游离
常用方法:
load()和get()方法
都能根据给定OID从数据库中加载一个持久化对象.当数据库中不存在与OID对应的记录时,load()方法抛出空指针异常,而get()方法返回null.检索策略不同,默认情况下load()方法会采用延迟检索策略加载持久化对象,除非lazy=false,而get()方法总是采用立即检索策略.
saveOrUpdate()方法
如果传入参数是临时对象,调用save()方法,如果参数是游离对象,调用update()方法,如果参数是持久化对象,直接返回.
merge()方法
把一个游离对象的属性复制到一个持久化对象中.
Persist()和save()方法
Persist()把一个瞬态的实例持久化,但是并"不保证"标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。
save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert
flush() 和clear()/evict()方法
flush():强制持久化sessiong缓存中的持久化对象
clear()/evict():清除session缓存中的实体,目的是释放内存
Session的commit()和flush()方法的区别,flush()方法进行清理缓存的操作,执行一系列的SQL语句,但不会提交事务;
commit()方法会先调用flush(),然后提交事务.提交事务意味着对数据库所作的更新被永久保存下来.
一、部署hibernate:
最基本的部署需要将以下jar包放在lib目录下:
各配置目录层次如下:
配置hibernate.cfg.xml(以oracle为例)
配置User.hbm.xml
编写实体类(略),编写Dao类(基本的增删改查)如下:
public class UserDao {
public void save(){
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session session = sf.openSession();
Transaction ts = session.beginTransaction();
User user = new User();
// 保存
// user.setUsername("test1");
// user.setUserpwd("787787");
// user.setAge("26");
// user.setJob("developer");
// user.setLevel("3");
// try {
// session.save(user);
// ts.commit();
// System.out.println("保存成功");
// }catch(HibernateException exx) {
// exx.printStackTrace();
// }
//删除
// User user2 = (User) session.get(User.class, 2L);
// try {
// session.delete(user2);
// ts.commit();
// System.out.println("删除成功");
// }catch(HibernateException exx) {
// exx.printStackTrace();
// }
// 更改
// User user2 = (User) session.get(User.class, 2L);
// user2.setJob("superman");
// try {
// session.update(user2);
// ts.commit();
// System.out.println("更新成功");
// }catch(HibernateException exx) {
// exx.printStackTrace();
// }
// hql查询
// Query query = session.createQuery("from User");
// List users = query.list();
// Iterator iterator = users.iterator();
// while(iterator.hasNext()){
// user = (User) iterator.next();
// System.out.println("用户的年纪是"+user.getAge());
// }
// sql查询
// List users = session.createSQLQuery("select t.* from t_user t").list();
//原生态sql查询,hibernate不会把查询结果封装成实体类的
List users = session.createSQLQuery("select t.* from t_user t").addEntity(User.class).list();
Iterator it = users.iterator();
while(it.hasNext()){
user = (User) it.next();
System.out.println("用户的年纪是"+user.getAge());
// Object object[] = (Object[]) it.next();
// System.out.println("用户的ID是"+object[0]+";用户的职业是"+object[4]);
}
session.close();
sf.close();
}
}
注解:
要使用hibernate的注解,必须在hibernate.cfg.xml文件中加入<mapping class="bean.User"/>,否则框架是找不到实体类的。
使用log4j,web工程lib目录下加入log4j的jar包,当tomcat运行时,会自动去加载src根目录下的log4j.properties文件
一对多,多对多:
一对多核心:在“一(level)”中声明“多(user)”的对象为set类型,level.hbm.xml配置文件中one-to-many标签
多对一:在“多(user)”中声明“一(room)”的对象为Room类型,user.hbm.xml 配置文件中many-to-one标签
多对多:“多(course)”和“多(user)”,都需要声明一个set类型对象,用于存储对方的实体类。需要建立一个第三方的关联表,
详见代码
关于映射文件的常用标签:
cascade属性
cascade属性值 描述
none 在保存更新时,忽略其他关联对象,他是cascade默认属性
save-update 当通过Session的save(),update()以及saveOrUpdate()方法来保存
或更新当前对象时,及联保存所有关联的新建的临时对象,并且及联更新所有关联的游离对象
delete 当通过session的delete()方法删除当前对象时,及联删除所有对象
all 包含save-update及delete行为,此外对当前对象执行evict()或lock
()操作时,也会对所有关联的持久化对象执行evict()或lock()操作
delete-orphan 删除所有和当前对象解除关联关系的对象
all-delete-orphan 包含all和delete-orphan
用于控制insert or update 语句的映射属性
<property>元素的insert属性 如为false,在insert中不包含该字段,默认为true
<property>元素的update属性 如为false,在update中不包含该字段,默认为true
<class>元素的mutable属性 如为false,等价于所有字段的update属性为false,默认为true
<property>元素的dunameic-insert属性 如为true,表明动态生成insert语句,只有不为null,才会包含insert语句中,默认false
<property>元素的dunameic-update属性 如为true,表明动态生成update语句,只有不为null,才会包含insert语句中,默认false
<class>元素的dunameic-insert属性如为true,表明等价于所有字段动态生成insert语句,只有不为null,才会包含insert语句中 ,默认false
<class>元素的dunameic-update属性如为true,表明等价于所有字段动态生成update语句,只有不为null,才会包含insert语句中 ,默认false
fetch,outer-join 和 lazy 主要用于级联查询(select) 而 inverse和cascade主要用于级联增加,删除,修改(sava-update,delete)。
lazy是延时的意思,如果lazy=true,那么就是说数据库中关联子表的信息在hibernate容器启动的时候不会加载,而是在你真正的访问到字表非标识字段的时候,才会去加载。 反之,如果lazy=false的话,就是说,子表的信息会同主表信息同时加载。
cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。
fetch (可选 - 默认为 select): 在外连接抓取(outer-join fetching)和序列选择抓取(sequential select fetching)两者中选择其一。
outer-join关键字(many-to-one的情况)
outer-join关键字有3个值,分别是true,false,auto,默认是auto。
true: 表示使用外连接抓取关联的内容,这里的意思是当使用load(OrderLineItem.class,"id")时,Hibernate只生成一条SQL语句将OrderLineItem与他的父亲Order全部初始化。
select * from OrderLineItem o left join Order p on o.OrderId=p.OrderId where o.OrderLineItem_Id=?
from OrderLineItem o left join fetch o.OrderId
false: 表示不使用外连接抓取关联的内容,当load(OrderLineItem.class,"id")时,Hibernate生成两条SQL语句,一条查询 OrderLineItem表,另一条查询Order表。这样的好处是可以设置延迟加载,此处要将Order类设置为lazy=true。
select * from OrderLineItem o where o.OrderLineItem_Id=?
select * from Order p where p.OrderId=?
auto:具体是ture还是false看hibernate.cfg.xml中的配置
注意:如果使用HQL查询OrderLineItem,如 from OrderLineItem o where o.id='id',总是不使用外部抓取,及outer-join失效。
2、outer-join(集合)
由于集合可以设置lazy="true",所以lazy与outer-join不能同时为true,当lazy="true"时,outer-join将一直是false,如果lazy="false",则outer-join用法与1同
3.如果集合被声明为lazy=true,在HQL中如果显式的使用 join fetch 则延迟加载失效。
4.在one-to-many的one端显式设置fecth="join",则无论如何都采取预先抓取(生成一个SQl),延迟加载失效(生成两个SQL)
5.many- to-one的延迟加载是在配置文件的class标签设置lazy="true",one-to-many和many-to-many的延迟加载是在 set标签中设置lazy="true"。而one-to-one不只要在calss标签设置lazy="true",而且要在one-to-one标签 中设置constrained="true".
Hibernate的缓存机制
缓存是位于应用程序与物理数据源之间,用于临时存放复制数据的内存区域,目的是为了减少应用程序对物理数据源访问的次数,从而提高应用程序的运行性能.
Hibernate在查询数据时,首先到缓存中去查找,如果找到就直接使用,找不到的时候就会从物理数据源中检索,所以,把频繁使用的数据加载到缓存区后,就可以大大减少应用程序对物理数据源的访问,使得程序的运行性能明显的提升.
Hibernate缓存分类:
Session缓存,一级缓存.
SessionFactory的缓存分为内置缓存和外置缓存.内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定义SQL语句等),对于应用程序来说,它是只读的.外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备.
Hibernate的缓存范围
Hibernate的一级缓存和二级缓存都位于均位于持久层,且均用于存放数据库数据的副本,最大的区别就是缓存的范围各不一样.
缓存的范围分为3类:
1.事务范围
事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围.
2.应用范围
应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围.
3.集群范围
在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致,缓存中的数据通常采用对象的松散数据形式.
Hibernate的缓存管理
一级缓存的管理:
evit(Object obj) 将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象.
clear() 将一级缓存中的所有持久化对象清除,释放其占用的内存资源
contains(Object obj) 判断指定的对象是否存在于一级缓存中.
flush() 刷新一级缓存区的内容,使之与数据库数据保持同步.
二级缓存的管理:
evict(Class arg0, Serializable arg1) 将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源.
Java代码
sessionFactory.evict(Customer.class, new Integer(1));
sessionFactory.evict(Customer.class, new Integer(1));
evict(Class arg0) 将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源.
Java代码
sessionFactory.evict(Customer.class);
sessionFactory.evict(Customer.class);
evictCollection(String arg0) 将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源.
Java代码
sessionFactory.evictCollection("Customer.orders");
sessionFactory.evictCollection("Customer.orders");
Hibernate的二级缓存的配置
首先,不是所有的数据都适合放在二级缓存中,看一下,什么样的数据适合放在二级缓存中来?什么样的数据不适合放在二级缓存中来?
下面这几种情况就不适合加载到二级缓存中:
1.经常被修改的数据
2.绝对不允许出现并发访问的数据
3.与其他应用共享的数据
下面这己种情况合适加载到二级缓存中:
1.数据更新频率低
2.允许偶尔出现并发问题的非重要数据
3.不会被并发访问的数据
4.常量数据
5.不会被第三方修改的数据
Hibernate的二级缓存功能是靠配置二级缓存插件来实现的,Hibernate为了集成这些插件,Hibernate提供了org.hibernate.cache.CacheProvider借口,它充当缓存插件与Hibernate之间的适配器 .
常用的二级缓存插件
EHCache org.hibernate.cache.EhCacheProvider
OSCache org.hibernate.cache.OSCacheProvider
SwarmCahe org.hibernate.cache.SwarmCacheProvider
JBossCache org.hibernate.cache.TreeCacheProvider
简单介绍一下EHCache的配置
hibernate.cfg.xml
Xml代码
<hibernate-configuration>
<session-factory>
<!-- 设置二级缓存插件EHCache的Provider类-->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!-- 启动"查询缓存" -->
<property name="hibernate.cache.use_query_cache">
true
</property>
<!-- 启用二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
</session-factory>
</hibernate-configuration>
<hibernate-configuration>
<session-factory>
<!-- 设置二级缓存插件EHCache的Provider类-->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!-- 启动"查询缓存" -->
<property name="hibernate.cache.use_query_cache">
true
</property>
</session-factory>
</hibernate-configuration>
ehcache.xml
Xml代码
<ehcache>
<!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 overflowToDisk属性用来配置当缓存存储的数据达到maxInMemory限制时是否overflow到磁盘上-->
<diskStore path="java.io.tmpdir"/>
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
</ehcache>
<ehcache>
<!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 -->
<diskStore path="java.io.tmpdir"/>
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
</ehcache>
****.hbm.xml
Xml代码
<?xml version="1.0" encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class>
<!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->
<cache usage="read-write"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class>
<!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->
<cache usage="read-write"/>
</class>
</hibernate-mapping>
缓存的方式有四种,分别为:
CacheConcurrencyStrategy.NONE
CacheConcurrencyStrategy.READ_ONLY,只读模式,在此模式下,如果对数据进行更新操作,会有异常;
CacheConcurrencyStrategy.READ_WRITE,读写模式在更新缓存的时候会把缓存里面的数据换成一个锁,其它事务如果去取相应的缓存数据,发现被锁了,直接就去数据库查询;
CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,不严格的读写模式则不会的缓存数据加锁;
CacheConcurrencyStrategy.TRANSACTIONAL,事务模式指缓存支持事务,当事务回滚时,缓存也能回滚,只支持JTA环境。
如何解决Hibernate 的N+1问题
2012-05-24 21:41:26| 分类: 默认分类 | 标签: |字号大中小 订阅
【问题】什么时候会遇到N+1的问题?
【备注】 Hibernate默认抓取策略是fetch="select",不是fetch="join",这都是为了延迟加载而准备的。
【出现情况】
1)一对多(one-to-many) ,在1的这方,通过1条sql查找得到了1个对象,由于关联的存在 ,那么又需要将这个对象关联的集合取出,所以合集数量是n还要发出n条sql,于是本来的1条sql查询变成了 1 +n条 。
2)多对一<many-to-one> ,在多的这方,通过1条sql查询得到了n个对象,由于关联的存在,也会将这n个对象对应的1 方的对象取出, 于是本来的1条sql查询变成了1 +n条 。
3)iterator 查询时,一定先去缓存中找(1条sql查集合,只查出ID),在没命中时,会再按ID到库中逐一查找, 产生1+n条SQL。
【解决办法】
1)lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。
2)使用二级缓存, 二级缓存的应用将不怕1+N 问题,因为即使第一次查询很慢(未命中),以后查询直接缓存命中也是很快的。刚好又利用了1+N 。
3 ) 当然你也可以设定fetch="join",一次关联表全查出来,但失去了延迟加载的特性。
<!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数,overflowToDisk属性用来配置当缓存存储的数据达到maxInMemory限制时是否overflow到磁盘上 -->
关于数据库并发问题:
1. 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。
一个典型的依赖数据库的悲观锁调用:select * from account where name=”Erica” for update这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录,在Hibernate使用悲观锁十分容易,但实际应用中悲观锁是很少被使用的,因为它大大限制了并发性:
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。
2. 乐观锁的工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
Hibernate为乐观锁提供了3中实现:
基于version
基于timestamp
为遗留项目添加添加乐观锁
例子:
Hibernate乐观锁的的使用:
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();
MyEntity et1 = session1.load(MyEntity.class, id);
MyEntity et2 = session2.load(MyEntity.class, id);
//这里 et1, et2为同一条数据
Transaction tx1 = session1.beginTransaction();
//事务1开始
et1.setName(“Entity1”);
//事务1中对该数据修改
tx1.commit();
session1.close();
//事务1提交
Transaction tx2 = session2.beginTransaction();
//事务2开始
et2.setName(“Entity2”);
//事务2中对该数据修改
tx2.commit();
session2.close();
//事务2提交
在事务2提交时,因为它提交的数据比事务1提交后的数据旧,所以hibernate会抛出一个org.hibernate.StaleObjectStateException异常。
回到前面的问题,Hibernate怎么知道事务2提交的数据比事务1提交后的数据旧呢?
因为MyEntity有个version版本控制字段。
回头看看上面的源代码中的:
MyEntity et1 = session1.load(MyEntity.class, id);
MyEntity et2 = session2.load(MyEntity.class, id);
这里,et1.version==et2.version,比如此时version=1,
当事务1提交后,该数据的版本控制字段version=version+1=2,而事务2提交时version=1<2所以Hibernate认为事务2提交的数据为过时数据,抛出异常。
二、数据库事务并发可能带来的问题
1. 第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。
在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,T4时刻事务2取出了同一条数据,T5时刻事务1将age字段值更新为30,T6时刻事务2更新age为35并提交了数据,但是T7事务1回滚了事务age最后的值依然为20,事务2的更新丢失了,这种情况就叫做"第一类丢失更新(lost update)"。
2. 脏读(dirty read):如果第二个事务查询到第一个事务还未提交的更新数据,形成脏读。
在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,在T5时刻事务1将age的值更新为30,但是事务还未提交,T6时刻事务2读取同一条记录,获得age的值为30,但是事务1还未提交,若在T7时刻事务1回滚了事务2的数据就是错误的数据(脏数据),这种情况叫做" 脏读(dirty read)"。
3. 虚读(phantom read):一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成两次结果不一致,只是另一个事务在这两次查询中间插入或者删除了数据造成的。
在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1从数据库中查询所有记录,记录总共有一条,T4时刻事务2向数据库中插入一条记录,T6时刻事务2提交事务。T7事务1再次查询数据数据时,记录变成两条了。这种情况是"虚读(phantom read)"。
4. 不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事务更新了该数据,两次结果相异,不可信任。
在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,此时age=20,T4时刻事务2查询同一条数据,T5事务2更新数据age=30,T6时刻事务2提交事务,T7事务1查询同一条数据,发现数据与第一次不一致。这种情况就是"不可重复读(unrepeated read)"。
5. 第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。
在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1更新数据age=25,T5时刻事务2更新数据age=30,T6时刻提交事务,T7时刻事务2提交事务,把事务1的更新覆盖了。这种情况就是"第二类丢失更新(second lost updates)"。
三、数据库事务隔离级别
为了解决数据库事务并发运行时的各种问题数据库系统提供四种事务隔离级别:
1. Serializable 串行化
2. Repeatable Read 可重复读
3. Read Commited 可读已提交
4. Read Uncommited 可读未提交
Jndi数据源配置:
name:给数据源设置名字(jndi)
auth:表示数据源由谁管理
type:类型
maxActive:在连接池中最大的激活连接数 ,设 0 为没有限制
maxIdle:在连接池中最大的保留(空闲)连接数 ,设 0 为没有限制
maxWait:客户端在队列池中最大等待时间 ,当请求超过最大连接数时,就会进入队列等待。单位为 ms, 取值-1,表示无限等待,超过时间会出错误信息
相关推荐
在这个配置文件中,有几个常用的属性,对 Hibernate 的行为有着重要影响。以下是对这些配置的详细解释: 1. **Hibernate.show_sql**: 这个属性控制着 Hibernate 是否在运行时将执行的 SQL 语句打印到控制台。默认...
### 使用Hibernate连接各种数据库的方法 #### 一、前言 Hibernate是Java开发中非常流行的ORM(对象关系映射)框架之一,它简化了数据库操作,让开发者能够更加专注于业务逻辑而不是复杂的SQL语句编写。本文将详细...
15. 工具箱指南:Hibernate提供了许多工具类和实用方法来简化开发,这部分会介绍这些工具的使用方法。 16. 示例:父子关系:文档中会包含一个关于如何处理父子关系映射的例子,这是对象模型中常见的关系映射挑战。 ...
总结起来,Struts和Hibernate是Java Web开发中的两大基石,它们分别解决了MVC架构的实现和数据库操作的简化问题。了解并熟练掌握这两个框架,对于提升Java Web应用的开发效率和质量具有重要意义。而jar包作为Java的...
总结,这个"spring4搭配hibernate5和mysql的项目Demo"提供了一个完整的Web应用开发实例,展示了如何利用现代Java技术栈构建高效、可维护的数据库驱动的应用程序。对于初学者来说,这是一个很好的学习资源,可以帮助...
通过上述介绍,我们不仅了解了如何搭建基于 Tomcat 和 JDK 1.3.1 的开发环境,还详细探讨了 Hibernate 的核心配置文件 `hibernate.cfg.xml` 和 `.hbm.xml` 文件的使用方法,以及一些高级配置选项。这些知识对于使用 ...
Struts、Spring、Hibernate是Java开发中常用的三大框架,它们分别负责不同的职责:Struts用于MVC模式的控制器层,Spring作为IoC/DI容器和AOP代理,Hibernate则为ORM(对象关系映射)解决方案。这篇面试题总结主要...
在IT行业中,构建Web服务是常见的任务之一,而CXF、Spring和Hibernate是Java领域内常用的三大框架,它们各自在不同的层面上发挥着关键作用。本项目通过整合这三者来实现一个基于SOAP协议的WebService,以提供数据...
在IT行业中,构建高效、可维护的Web应用是至关重要的,而"Maven+Spring+SpringMVC+Hibernate"是一个常用的技术栈,它整合了多个强大的工具和框架来简化开发流程。下面将详细介绍这个项目示例中涉及的关键知识点。 1...
- **配置文件**:介绍 `hibernate.cfg.xml` 文件的结构和常用配置项。 - **数据库连接设置**:包括数据库驱动、URL、用户名和密码等基本信息的配置方法。 - **方言设置**:解释如何根据不同的数据库类型选择合适的...
- **最佳实践**:总结在项目开发过程中遇到的问题以及解决方法,提供实用的技术建议和策略。 - **技术趋势展望**:讨论未来JavaEE领域的发展方向,以及Struts2、Spring和Hibernate等相关技术的应用前景。 通过上述...
- **1.1 前言**:介绍了 Hibernate 的背景及其为何能成为 Java 开发者常用的 ORM 工具之一。 - **1.2 第一部分——第一个 Hibernate 应用程序** - **1.2.1 第一个 class**:创建一个简单的 Java 类来表示实体。 - ...
Ant是一个强大的构建工具,用于自动化构建过程,支持各种复杂的任务,非常适合用来构建和部署Hibernate应用。 2. **下载Hibernate相关软件包**:接下来,从官方网站下载最新的Hibernate、Hibernate-Extension和...
- 总结了系统的设计思路和实现方法。 #### 员工登录系统 最后,我们以员工登录系统为例,详细介绍如何使用Struts和Hibernate技术进行具体模块的开发。 - **5.1 系统分析和设计** - **5.1.1 需求分析**:明确...
- **1.2.5 启动与辅助类**:讲解如何初始化Hibernate SessionFactory以及常用的一些辅助类和工具方法。 - **1.2.6 加载与存储对象**:阐述如何使用Hibernate API来加载、保存、更新或删除持久化对象。 **1.3 映射...
这个系统是使用Spring、Hibernate和Eclipse构建的一个典型例子,它不仅展示了这些技术的集成使用方式,还演示了敏捷开发方法如何贯穿整个开发流程。 - **需求分析**:明确系统的功能需求和非功能性需求,比如安全性...
Weblogic和Tomcat都是常用的企业级应用服务器,它们各自具有独特的特点和优势。Weblogic提供了更为丰富的管理和监控功能,适用于大型企业级应用的部署;而Tomcat则以其轻量级和灵活性著称,更适合中小型应用的需求。...
总结来说,"常用的ANT蚂蚁脚本"涵盖了使用ANT配合XDoclet自动创建Hibernate映射文件,以及利用ANT自动化EJB项目的构建和部署流程。这些脚本对于理解ANT的工作原理,以及在实际开发环境中如何使用ANT进行项目管理具有...