一、什么是Hibernate
1.一种框架,一种orm框架(objext relation mapping)对象关系映射框架。
2.hibernate处于项目的持久层位置,又叫持久化框架。
3.hibernate实际上是对jdbc进行轻量级的封装。
二、搭建Hibernate环境
1.导入Hibernate必须的jar包
加入数据库驱动的jar包
2.在src目录下创建hibernate.cfg.xml配置文件(文件的名字不能改!)
手动配置hibernate.cfg.xml文件,该文件用于配置连接的数据库类型,diver,用户名,密码....同时管理对象关系映射文件和该文件的名称,这个文件一般放在src目录下。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Hibernate 连接数据库的基本信息 --> <property name="connection.username">scott</property> <property name="connection.password">java</property> <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver </property> <property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl </property> <!-- Hibernate 的基本配置 --> <!-- Hibernate 使用的数据库方言 --> <property name="dialect">org.hibernate.dialect.Oracle10gDialect </property> <!-- 运行时是否打印 SQL --> <property name="show_sql">true</property> <!-- 运行时是否格式化 SQL --> <property name="format_sql">true</property> <!-- 生成数据表的策略 --> <property name="hbm2ddl.auto">update</property> <!-- 删除对象后, 使其 OID 置为 null --> <property name="use_identifier_rollback">true</property> <!-- 设置 Hibernate 的事务隔离级别 --> <property name="connection.isolation">2</property> <!-- 配置 C3P0 数据源 --> <property name="hibernate.c3p0.max_size">10</property> <property name="hibernate.c3p0.min_size">5</property> <property name="c3p0.acquire_increment">2</property> <property name="c3p0.idle_test_period">2000</property> <property name="c3p0.timeout">2000</property> <property name="c3p0.max_statements">10</property> <!-- 设定 JDBC 的 Statement 读取数据的时候每次从数据库中取出的记录条数 --> <property name="hibernate.jdbc.fetch_size">100</property> <!-- 设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小 --> <property name="jdbc.batch_size">30</property> <!-- 启用二级缓存 --> <property name="cache.use_second_level_cache">true</property> <!-- 配置使用的二级缓存的产品 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- 配置启用查询缓存 --> <property name="cache.use_query_cache">true</property> <!-- 配置管理 Session 的方式 --> <property name="current_session_context_class">thread</property> <!-- 需要关联的 hibernate 映射文件 .hbm.xml --> <mapping resource="com/atguigu/hibernate/entities/Department.hbm.xml"/> </session-factory> </hibernate-configuration>
3.创建持久化java类以Person为例
package test.Hibernate.model; import java.util.HashSet; import java.util.Set; public class Person { @Override public String toString() { return "Person [id=" + id + ", name=" + name + "]"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<String> getAddress() { return address; } public void setAddress(Set<String> address) { this.address = address; } private int id; private String name; private Set<String> address = new HashSet<String>(); }
4.运用Hibernate插件编写生成Person.hbm.xml实体类配置文件
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping package="test.Hibernate.model"> <class name="Person" table="person"> <id column="id" name="id" type="int"> <!-- Hibernate 的主键生成策略 --> <generator class="native"></generator> </id> <property name="name" column="name" length="50" type="string"></property> <set name="address" table="address"> <key column="personId"></key> <element column="address" type="string" length="50"></element> </set> </class> </hibernate-mapping>
主键生成策略
identity:使用数据库的自动增长策略,不是所有数据库都支持,比如oracle就不支持。
sequence:在 DB2,PostgreSQL,Oracle,SAP DB,McKoi 中使用序列(sequence)在使用Oracle数据库时可以使用这一个。
hilo:使用高低位算法生成主键值。只需要一张额外表,所有的数据都支持。
native:根据底层数据库的能力选择 identity、sequence 或者 hilo中的一个
assigned:手工指定主键值。
uuid:由Hibernate自动生成UUID并指定为主键值。
5.在hibernate.cfg.xml中加入映射信息
<mapping resource="test/Hibernate/model/Person.hbm.xml" />
6.生成sessionFactory工厂工具类
package test.Hibernate.SessionFactory; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; public class SessionFactory { private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); private static org.hibernate.SessionFactory sessionFactory; private static Configuration configuration = new Configuration(); private static ServiceRegistry serviceRegistry; static { try { configuration.configure(); serviceRegistry=new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } private SessionFactory() { } public static Session getSession() throws HibernateException { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } public static void rebuildSessionFactory() { try { configuration.configure(); serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); } } public static org.hibernate.SessionFactory getSessionFactory() { return sessionFactory; } public static Configuration getConfiguration() { return configuration; } }
7.编写测试类
package test.Hibernate.dao; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import test.Hibernate.SessionFactory.SessionFactory; import test.Hibernate.model.Person; public class PersonDao { @Test public void add(){ Session session = SessionFactory.getSession(); Transaction tr = session.beginTransaction(); //---------------------------------------------- Person p = new Person(); p.setName("test"); p.getAddress().add("firstAddr"); p.getAddress().add("secondAddr"); p.getAddress().add("thirdAddr"); p.getAddress().add("fourthAddr"); session.save(p); //---------------------------------------------- tr.commit(); SessionFactory.closeSession(); } @Test public void get(){ Session session = SessionFactory.getSession(); Transaction tr = session.beginTransaction(); //---------------------------------------------- Person p = (Person)session.get(Person.class, 2); System.out.println(p); //---------------------------------------------- tr.commit(); SessionFactory.closeSession(); } }
三、Hiberbate映射关系配置
1.one-to-one: 身份证<---->人 丈夫<--->妻子
2.one-to-many: 部门<--->员工
3.many-to-one:员工<--->部门
4.many-to-many:学生<--->老师(尽量避免)
(在实际开发过程中,如果出现了多对多的关系,我们应该尽量装换为两个一对多或者多对一的关系,这样程序好控制,同时不会有冗余)
1.one-to-one
一对一两种方式:
(1)基于主键的一对一
(人<--->身份证 one<--->one)
//Person.java,略去了相关的get/set方法 private Integer id; private String name; private IdCard idCard;
/Person.hbm.xml <hibernate-mapping package="com.sun.hibernate.model"> <class name="Person"> <id name="id" type="java.lang.Integer"> <!-- 我们手动分配id --> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="128" /> </property> <!-- 这里配置person和idcard属性是一对一关系 --> <one-to-one name="idCard"></one-to-one> </class> </hibernate-mapping>
/IdCard.java,略去了相关的get/set方法 private Integer id; private Date validata; private Person person;
//IdCard.hbm.xml <hibernate-mapping package="com.sun.hibernate.model"> <class name="IdCard"> <id name="id" type="java.lang.Integer"> <!-- 因为我们这里是基于主键的one-to-one, 所以我们使用外键策略 --> <generator class="foreign"> <!-- 这里值,是指跟那个属性ont-to-one --> <param name="property">person</param> </generator> </id> <property name= "validata" type="java.util.Date"> <column name="validata" /> </property> <!-- constrained设置为true才会使得在数据提交的时候同时提交相关的关联关系,在此例中如果没有IdCard表将不会有外键--> <one-to-one name="person" constrained="true" /> </class> </hibernate-mapping>
2)基于外键的一对一
(人<--->身份证 one<--->one)
//Person.java,略去了相关的get/set方法(和基于主键的Person.java一致) private Integer id; private String name; private IdCard idCard;
//Person.hbm.xml(和基于主键的Person.hbm.xml一致) <hibernate-mapping package="h_hbm_oneToOne"> <!-- User表对应的映射关系 --> <class name="Person" table="person"> <id name="id"> <generator class="native" /> </id> <property column="name" name="name" type="string" /> <!-- IdCard属性:IdCard类型 表达的是本类与IdCard的一对一关系 采用基于外键的一对一映射的方式 cascade {//级联的作用域 delete, update, all, None unique="true"//唯一约束 } --> <many-to-one name="idCard" class="IdCard" column="idCardId" unique="true" cascade="all"> </many-to-one> </class> </hibernate-mapping>
//IdCard.java,略去了相关的get/set方法(和基于主键的IdCard.java一致) private Integer id; private Date validate; private Person person;
//IdCard.hbm.xml(注意与基于主键的IdCard.hbm.xml的区别) <hibernate-mapping package="h_hbm_oneToOne"> <!-- User表对应的映射关系 --> <class name="IdCard" table="idCard"> <id name="id"> <generator class="native" /> </id> <property column="number" name="number" type="string" /> <!-- person属性:Person类型 表达的是本类与IdCard的一对一关系 采用基于外键的一对一映射的方式 本方无外间房 property-ref:写的是对方映射中外键列对应的属性名,也就是Person类下的idCard属性名 --> <one-to-one name="person" class="Person" property-ref="idCard"> </one-to-one> </class> </hibernate-mapping>
2.one-to-many and many-to-one(以Father和Children为例)
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="test.Hibernate.model"> <class name="Father" table="father"> <id name="id" type="int" column="id" > <generator class="native"></generator> </id> <property name="name" type="string" column="name"/> <set name="children" cascade="all"> <key column="fatherId"></key> <one-to-many class="Children"/> </set> </class> </hibernate-mapping>
?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="test.Hibernate.model"> <class name="Children" table="children"> <id name="id" type="int" column="id" > <generator class="native"></generator> </id> <property name="name" type="string" column="name"/> <many-to-one name="father" class="Father" column="fatherId"></many-to-one> </class> </hibernate-mapping>
3.many-to-many
学生<--->课程
many-to-many在实际开发过程中,如果出现这种多对多的关系,我们应该尽量转换为两个一对多或者多对一的关系,这样程序好控制,同时不会有冗余。
所以学生<--->课程我们转换为学生<--->选课记录表(many<--->one) 选课记录表<--->课程(one<--->many)
//Student.java private Integer sid; private String sname; private String sdept; private Set<Studcourse> studcourses = new HashSet<Studcourse>(0);
//Student.hbm.xml <hibernate-mapping> <class name="com.domain.Student" table="student" catalog="course"> <id name="sid" type="java.lang.Integer"> <column name="sid" /> <generator class="identity" /> </id> <property name="sname" type="string"> <column name="sname" length="20" not-null="true" /> </property> <property name="sdept" type="string"> <column name="sdept" length="10" not-null="true" /> </property> <set name="studcourses" inverse="true"> <key> <column name="sid" /> </key> <one-to-many class="com.domain.Studcourse" /> </set> </class> </hibernate-mapping>
//Studcourse.java private Integer idstudCourse; private Course course; private Student student; private Integer grade;
<hibernate-mapping> <class name="com.domain.Studcourse" table="studcourse" catalog="course"> <id name="idstudCourse" type="java.lang.Integer"> <column name="idstudCourse" /> <generator class="identity" /> </id> <many-to-one name="course" class="com.domain.Course" fetch="select"> <column name="cid" /> </many-to-one> <many-to-one name="student" class="com.domain.Student" fetch="select"> <column name="sid" /> </many-to-one> <property name="grade" type="java.lang.Integer"> <column name="grade" /> </property> </class> </hibernate-mapping>
Course.java private Integer cid; private String cname; private Integer ccredit; private Set<Studcourse> studcourses = new HashSet<Studcourse>(0);
//Course.hbm.xml <hibernate-mapping> <class name="com.domain.Course" table="course" catalog="course"> <id name="cid" type="java.lang.Integer"> <column name="cid" /> <generator class="identity" /> </id> <property name="cname" type="string"> <column name="cname" length="40" not-null="true" /> </property> <property name="ccredit" type="java.lang.Integer"> <column name="ccredit" /> </property> <set name="studcourses" inverse="true"> <key> <column name="cid" /> </key> <one-to-many class="com.domain.Studcourse" /> </set> </class> </hibernate-mapping>
四、Session的核心方法
Save()
1.使一个临时对象变为持久化对象.
2.为对象分配ID.
3.在flush缓存时会发送一条insert语句.
4.在save方法之前的ID是无效的
5.持久化对象的ID是不能被修改的
Persist()和save()的区别
1.Persist()也会执行insert操作
2.在persist方法之前,若对象已经有ID了,则不会执行insert,则抛出异常
Get()和load()区别
1.执行get()方法会立即加载对象,而执行load方法,若不适用该对象,则不会立即执行查询操作,而返回一个代理对象,get是立即检索,load是延迟检索
2.若数据表中没有对应的记录,session没有关闭,同时需要使用该对象,get返回null 而load抛出一个异常
3.Load方法可能会抛出懒加载异常lazyInitializationException 在需要初始化代理对象之前已经关闭了session
Update()
1.使一个游离的对象变成一个持久化对象,并执行一个update语句
2.若更新一个持久化对象不需要显示的调用update方法,因为在调用Transaction的commit()方法时,会先执行session的flush方法
3.跟新一个游离对象需要显示的调用update()可以比一个游离对象变为持久化对象
4.若数据库表中没用对应的记录,还调用了update会发生异常
5.当update方法关联一个游离对象时,如果在session缓存中已经存在相同的OID的持久化对象,会抛出异常,因为在session缓存中不能有两个OID相同的对象
注意的是:
1.无论要更新的游离对象是否和数据库表的记录是否一致,都会执行update()
如何让update方法不盲目的触发语句呢?
在hbm.xml文件中添加 select-befor-update=”true”默认为FALSE.但通常不需要设置该属性,这样效率反而降低了
saveorUpdate()
1.若OID不为空但数据表中还没用对应的记录会抛出一个异常
2.了解 OID的值等于id的unsave-value的属性的值,也被认为是一个游离对象
Delete()
1.执行删除操作,只要OID和数据表中一条记录对应,就会准备执行delete操作
2.若OID在数据表中没有对应的记录,则抛出异常
3.可以通过设置hibernate文件的一个属性hibernate.use_identifier_roback为true,使删除对象后OID制为null一般开发也不需要设置
Evict()
从session缓存中把指定的持久化对象移除
Dowork()
Hibernate调用存储过程session需要先调用dowork实现execute方法拿到connection,执行存储过程
Hibernate和触发器协同工作的时候避免触发器盲目的触发update的方法
在hbm.xml文件中添加 select-befor-update=”true”默认为FALSE.且在执行完session的相关操作后,立即调用session的flush()和reflush()方法,迫使session的缓存和数据库同步。
五、检索策略
lazy
1.类级别的检索策略Lazy = true\false 默认是true通常情况下不用修改使用默认就可以 在使用load()是使用懒加载的检索策略
2.1-n或n-n检索策略 set的lazy属性1-n或n-n的集合属性默认使用懒加载检索策略
可以通过设置set的lazy属性来修改默认的检索策略,默认为true,并不建议设置false
Lazy还可以设置为extra,增强的延迟检索,该取值会尽可能的延迟集合初始化的时机
Batch-Size
Set 元素的batch-size 属性 设定批量检索的数量 设置一次初始化set集合的数量
Fetch
Set集合的fetch属性
1.默认值为select。通过正常的方式来初始化set元素
2.可以取值为subselect。通过子查询的方式来初始化所有的set集合。子查询作为where子句的in条件出现,子查询查询所有1的一端的ID此时lazy有效
3.若取值为join,则在加载1的一端的对象时,使用迫切的做外链接(使用左外链接进行查询,并把集合进行初始化)的方式检索n的一段的集合属性,忽略lazy属性HQL查询忽略fetch=join取值
inverse和cascade的区别
1.inverse=false在一对多删除时是把孩子的外键设置为null,然后删除父亲,孩子不删除,而casecade=all在一对多删除时是把孩子的外键设置为null,然后删除父亲,然后再删除孩子
2.many to many的时候由一方维护,所以一方要设置inverse=false,但是inverse=true的另一方直接删除会出错,这个时候可以用casecade完成级联删除
3.inverse=false只用于set等集合属性,在one to one关系中可以用casecade完成级联删除
六、使用c3p0连接池
1.需要额外导入3个jar包
2.在hibernate.cfg.xml中加入C3P0配置信息
<!-- C3P0连接池设定-->
<!-- 使用c3p0连接池 配置连接池提供的供应商-->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
七、HQL语句
@Test public void HQLSearch(){ Session session = SessionFactory.getSession(); Transaction tr = session.beginTransaction(); //----------------------------------------- //common search with where // String hql= "select e.id,e.name from User e where e.id>=5 and e.id<=9"; // Query query = session.createQuery(hql); // List list = query.list(); // for(Object o : list){ // System.out.println(Arrays.toString((Object[])o)); // } //paging search // String hql= "select e.id,e.name from User e"; // Query query = session.createQuery(hql); // query.setFirstResult(0); // query.setMaxResults(10); // List list = query.list(); // for(Object o : list){ // System.out.println(Arrays.toString((Object[])o)); // } //search with parameters // String hql= "select e.id,e.name from User e where id>=? and id<=?"; // Query query = session.createQuery(hql) // .setParameter(0, 1) // .setParameter(1, 3); // List list = query.list(); // for(Object o : list){ // System.out.println(Arrays.toString((Object[])o)); // } //search with parameters whose type is collection // String hql= "select e.id,e.name from User e where id in (:ids)"; // Query query = session.createQuery(hql) // .setParameterList("ids",new Object[]{1,2,3,8} ); // List list = query.list(); // for(Object o : list){ // System.out.println(Arrays.toString((Object[])o)); // } //----------------------------------------- tr.commit(); SessionFactory.closeSession(); }
八、QBC语句
@Test public void testQBC(){ //1. 创建一个 Criteria 对象 Criteria criteria = session.createCriteria(Employee.class); //2. 添加查询条件: 在 QBC 中查询条件使用 Criterion 来表示 //Criterion 可以通过 Restrictions 的静态方法得到 criteria.add(Restrictions.eq("email", "SKUMAR")); criteria.add(Restrictions.gt("salary", 5000F)); //3. 执行查询 Employee employee = (Employee) criteria.uniqueResult(); System.out.println(employee); }
九、开启二级缓存
- 需要导入以下jar包
2.在hibernate.cfg.xml中加入以下配置
<!-- 使用二级缓存,默认是未打开的。 --> <!-- 指定要使用的缓存的提供商,这也就打开了二级缓存--> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- 开启使用查询缓存 --> <property name="cache.use_query_cache">true</property> <!-- 指定要使用二级缓存的实体类 --> <class-cache usage="read-write" class="test.Hibernate.model.Person" />
3.在src下创建ehcache.xml
<ehcache> <!-- Sets the path to the directory where cache .data files are created. If the path is a Java System Property it is replaced by its value in the running VM. The following properties are translated: user.home - User's home directory user.dir - User's current working directory java.io.tmpdir - Default temp file path --> <!-- 指定一个目录:当 EHCache 把数据写到硬盘上时, 将把数据写到这个目录下. --> <diskStore path="d:\\tempDirectory"/> <!--Default Cache configuration. These will applied to caches programmatically created through the CacheManager. The following attributes are required for defaultCache: maxInMemory - Sets the maximum number of objects that will be created in memory eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used if the element is not eternal. Idle time is now - last accessed time timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used if the element is not eternal. TTL is now - creation time overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit. --> <!-- 设置缓存的默认数据过期策略 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <!-- 设定具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域 缓存区域(region):一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略。 如果没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略。即:<defaultCache.../> Hibernate 在不同的缓存区域保存不同的类/集合。 对于类而言,区域的名称是类名。如:com.atguigu.domain.Customer 对于集合而言,区域的名称是类名加属性名。如com.atguigu.domain.Customer.orders --> <!-- name: 设置缓存的名字,它的取值为类的全限定名或类的集合的名字 maxElementsInMemory: 设置基于内存的缓存中可存放的对象最大数目 eternal: 设置对象是否为永久的, true表示永不过期, 此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。 当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。 timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。 如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值 overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中 --> <cache name="com.atguigu.hibernate.entities.Employee" maxElementsInMemory="1" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> <cache name="com.atguigu.hibernate.entities.Department.emps" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" /> </ehcache>
十、Hibernate对象状态及转换