配置:<set fetch="join/select/subselect">
Class.hbm.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 name="cn.itcast.hiberate.sh.domain.Classes"> <id name="cid" length="5" type="java.lang.Long"> <generator class="increment"></generator> </id> <property name="cname" length="20" type="java.lang.String"></property> <property name="description" length="100" type="java.lang.String"></property> <!-- set元素对应类中的set集合 通过set元素使classes表与student表建立关联 key是通过外键的形式让两张表建立关联 one-to-many是通过类的形式让两个类建立关联 cascade 级联 save-update 1、当 保存班级的时候,对学生进行怎么样的操作 如果学生对象在数据库中没有对应的值,这个时候会执行save操作 如果学生对象在数据库中有对应的值,这个时候会执行update操作 delete all inverse 维护关系 true 不维护关系 false 维护关系 default false --> <set name="students" cascade="save-update" inverse="true" lazy="false" fetch="join"> <!-- key是用来描述外键 --> <key> <column name="cid"></column> </key> <one-to-many class="cn.itcast.hiberate.sh.domain.Student"/> </set> </class> </hibernate-mapping>FetchTest.java
package cn.itcast.hibernate.sh.test; import java.util.List; import java.util.Set; import org.hibernate.Session; import org.junit.Test; import cn.itcast.hiberate.sh.domain.Classes; import cn.itcast.hiberate.sh.domain.Student; import cn.itcast.hibernate.sh.utils.HiberanteUtils; public class FetchTest extends HiberanteUtils{ static{ url = "hibernate.cfg.xml"; } /** * n+1的问题 * ------------------------------------ * n:4个班级,班级表中,表的记录数 * 1:查询班级 * 查询班级1条 + 每个班级查询一条学生(4条) = 5条 * ------------------------------------ * select:5条 * subselect:2条。如果需要分析翻译成sql语句存在子查询,这个时候用该策略效率最高 * ------------------------------------ * 针对这种问题:采用抓去策略解决 * 抓取策略:通过一个对象查询关联对象 * 解决问题的方案:子查询 fetch="subselect" */ @Test public void testAll_Classes(){ Session session = sessionFactory.openSession(); List<Classes> cList = session.createQuery("from Classes").list(); for(Classes classes:cList){ Set<Student> students = classes.getStudents(); for(Student student:students){ System.out.println(student.getSname()); } } session.close(); } /** * n+1的问题 * 解决问题的方案:子查询 fetch="subselect" */ @Test public void testClasses_Some(){ Session session = sessionFactory.openSession(); List<Classes> cList = session.createQuery("from Classes where cid in(1,2,3)").list(); for(Classes classes:cList){ Set<Student> students = classes.getStudents(); for(Student student:students){ System.out.println(student.getSname()); } } session.close(); } /** * 先查询班级,再查询学生 * ----------------------------- * subselect:2条 * join:1条 */ @Test public void testQueryClasses_Id(){ Session session = sessionFactory.openSession(); Classes classes = (Classes)session.get(Classes.class, 1L); Set<Student> students = classes.getStudents(); for(Student student:students){ System.out.println(student.getSname()); } session.close(); } }
session.getCurrentSession的用法
<property name="current_session_context_class">thread</property>
代码:SessionCreateTest.java
package cn.itcast.hibernate.sh.test; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import cn.itcast.hiberate.sh.domain.Classes; import cn.itcast.hibernate.sh.utils.HiberanteUtils; /** * session的产生方式。 * @author Administrator * */ public class SessionCreateTest extends HiberanteUtils{ static{ url = "hibernate.cfg.xml"; } /** * 只要执行sessionFactory.openSession就会新创建一个session */ @Test public void testOpenSession(){ Session session = sessionFactory.openSession(); } /** * crud操作必须在事务的环境下运行。 * 注意:此刻的查询也必须开启事务 * ---------------------------------------------------------------- * session和事务绑定在一起了:说明hibernate让强制使用事务 * 原因:1.为了不让出现多个事务。2. * ----------------------------------------------------------------- * 告诉hibernate,session由当前线程产生,必须得在hibernate.cfg.xml中如下配置 * <property name="current_session_context_class">thread</property> * * ------------------------------------------------------------------- * 利用sessionFactory.getCurrentSession();在事务提交的那一刹那,session自动关闭;饿 */ @Test public void testGetGurrentSession(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); transaction.commit(); //session.close(); } }
SessionCacheTest.java
package cn.itcast.hibernate.sh.test; import java.util.Set; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import cn.itcast.hiberate.sh.domain.Classes; import cn.itcast.hiberate.sh.domain.Student; import cn.itcast.hibernate.sh.utils.HiberanteUtils; /** * session的缓存 * 没发出sql说明存在缓存,是从缓存中拿数据 * @author Administrator * */ public class SessionCacheTest extends HiberanteUtils{ static{ url = "hibernate.cfg.xml"; } /** * session.get方法把数据存放在一级缓存中了 * 如果第二次在查询时,没有发出sql语句,则证明放到了缓存中 */ @Test public void testGet(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); classes = (Classes)session.get(Classes.class,1L);//没sql transaction.commit();//提交事务的时候,已经关闭了session } /** * session.load方法把数据存放在一级缓存中 */ @Test public void testLoad(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.load(Classes.class, 1L); classes.getCname(); classes = (Classes)session.load(Classes.class,1L); classes.getCname();//没sql transaction.commit(); } /** * session.save方法把数据保存在一级缓存中 * 先保存。如果在get的时候没有发出sql语句,则说明存在缓存 */ @Test public void testSave(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = new Classes(); classes.setCname("aaa"); classes.setDescription("asfd"); session.save(classes); classes = (Classes)session.get(Classes.class, classes.getCid());//没sql transaction.commit(); } /** * session.update */ @Test public void testUpdate(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.evict(classes);//classes对象从session中清空了 session.update(classes);//把classes对象放入到了session缓存中 classes = (Classes)session.get(Classes.class, 1L);//没发出sql transaction.commit(); } /** * session.clear */ @Test public void testClear(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.clear();//classes对象从session中清空了 classes = (Classes)session.get(Classes.class, 1L); transaction.commit(); } /** * 回顾一下典型的错误 * 标示符的意义-----不同的对象标示符必须不一样 * 两个持久化对象标识符相同 */ @Test public void testClearTest(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.clear();//如果不加这句话,两个不同的对象,相同的ID值,所以得把其中的一个清空 Classes classes2 = new Classes(); classes2.setCid(1L); classes2.setCname("asfd"); session.update(classes2); transaction.commit(); } /** * 把数据库中的数据刷新到缓存中 */ @Test public void testRefresh(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); classes.setCname("66"); session.refresh(classes);//把cid为1的值从数据库刷到了缓存中 System.out.println(classes.getCname()); transaction.commit(); } /** * session.flush * */ @Test public void testFlush(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes =(Classes)session.get(Classes.class, 1L); classes.setCname("afdsasdf"); Set<Student> students = classes.getStudents(); for(Student student:students){ student.setDescription("asdf"); } session.flush(); transaction.commit(); } /** * 插入100000万条数据到数据库中 */ @Test public void testSaveBatch(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); for(int i=6;i<1000000;i++){ Classes classes = new Classes(); classes.setCname("aaa"); classes.setDescription("afds"); session.save(classes); if(i%50==0){ session.flush(); session.clear(); } } transaction.commit(); } /** * session.flush只是发出SQL语句了,并没有清空session缓存 */ @Test public void testFlush2(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.flush(); classes = (Classes)session.get(Classes.class, 1L); transaction.commit(); } }
区别:
flush: 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务,;
commit:先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来。
reresh:刷新,让session和数据库同步,执行查询,把数据库的最新信息显示出来,更新本地缓存的对象状态.
clear:清空缓存,等价于list.removeAll();
Classes.hbm.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 name="cn.itcast.hiberate.sh.domain.Classes"> <!-- 缓存策略 --> <cache usage="read-write"/> <id name="cid" length="5" type="java.lang.Long"> <generator class="increment"></generator> </id> <property name="cname" length="20" type="java.lang.String"></property> <property name="description" length="100" type="java.lang.String"></property> <!-- set元素对应类中的set集合 通过set元素使classes表与student表建立关联 key是通过外键的形式让两张表建立关联 one-to-many是通过类的形式让两个类建立关联 cascade 级联 save-update 1、当 保存班级的时候,对学生进行怎么样的操作 如果学生对象在数据库中没有对应的值,这个时候会执行save操作 如果学生对象在数据库中有对应的值,这个时候会执行update操作 delete all inverse 维护关系 true 不维护关系 false 维护关系 default false --> <set name="students" cascade="save-update" inverse="true" fetch="select"> <!-- key是用来描述外键 --> <key> <column name="cid"></column> </key> <one-to-many class="cn.itcast.hiberate.sh.domain.Student"/> </set> </class> </hibernate-mapping>
hibernate.cfg.xml
<?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只能连接一个数据库 --> <session-factory> <!-- 数据库的用户名 --> <property name="connection.username">root</property> <!-- 密码 --> <property name="connection.password">root</property> <!-- url --> <property name="connection.url"> jdbc:mysql://localhost:3306/itcast_sh_hibernate </property> <!-- 作用:根据持久化类和映射文件生成表 validate create-drop create update --> <property name="hbm2ddl.auto">update</property> <!-- 显示hibernate内部生成的sql语句 --> <property name="show_sql">true</property> <property name="format_sql">true</property> <!-- 告诉hibernate,session由当前线程产生 --> <property name="current_session_context_class">thread</property> <!-- 开启二级缓存 --> <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> <mapping resource="cn/itcast/hiberate/sh/domain/Classes.hbm.xml" /> <mapping resource="cn/itcast/hiberate/sh/domain/Student.hbm.xml" /> <!-- <class-cache usage="read-only" class="cn.itcast.hiberate.sh.domain.Classes"/> --> </session-factory> </hibernate-configuration>
SecondCacheTest.java
package cn.itcast.hibernate.sh.test; import java.util.List; import java.util.Set; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import cn.itcast.hiberate.sh.domain.Classes; import cn.itcast.hiberate.sh.domain.Student; import cn.itcast.hibernate.sh.utils.HiberanteUtils; /** * hibernate的二级缓存 * @author Administrator * */ public class SecondCacheTest extends HiberanteUtils{ static{ url = "hibernate.cfg.xml"; } /** * session.get * 把数据存在一级缓存和二级缓存 * 数据从一级缓存找---二级缓存---数据库,如果数据中也找不到,报错 */ @Test public void testGet(){ Session session = sessionFactory.openSession(); Classes classes = (Classes)session.get(Classes.class, 1L); session.close(); session = sessionFactory.openSession(); classes = (Classes)session.get(Classes.class, 1L);//不发出 session.close(); } /** * session.load * 同上 */ @Test public void testLoad(){ Session session = sessionFactory.openSession(); Classes classes = (Classes)session.load(Classes.class, 1L); classes.getCname(); session.close(); session = sessionFactory.openSession(); classes = (Classes)session.load(Classes.class, 1L);//不发出 classes.getCname(); session.close(); } /** * session.update */ @Test public void testUpdate(){ Session session = sessionFactory.openSession(); //session.beginTransaction(); Classes classes = new Classes(); classes.setCid(1L); classes.setCname("aaa"); session.update(classes); session.close();//放倒了一级缓存,并关闭session session = sessionFactory.openSession(); classes = (Classes)session.get(Classes.class, 1L);// 如果发出语句,说明在一级缓存。不发出,在二级缓存中 session.close(); } }
package cn.itcast.hibernate.sh.test; import java.util.List; import java.util.Set; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import cn.itcast.hiberate.sh.domain.Classes; import cn.itcast.hiberate.sh.domain.Student; import cn.itcast.hibernate.sh.utils.HiberanteUtils; /** * 查询缓存 * ----------------------------- * 如果系统中设计大量的查询,例如大量报表。则利用查询缓存很有优势 * @author Administrator * */ public class QueryCacheTest extends HiberanteUtils{ static{ url = "hibernate.cfg.xml"; } @Test public void testQuery(){ Session session = sessionFactory.openSession(); Query query = session.createQuery("from Classes");//此处不能在.list(),而是返回Query对象 query.setCacheable(true);//classes里的所有的数据要往查询缓存中存放了。通过query放倒了缓存中 List<Classes> classesList = query.list(); query = session.createQuery("from Classes");//只有和上面一样的sql查询才能起到查询缓存的作用。否则又要重新查询 query.setCacheable(true);//这个query把缓存中的数据查出来。//如果这句话没有,发出两条sql classesList = query.list(); session.close(); } }
将查询出来的数据放在硬盘上,必须借助类路径下的ehcache.xml
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="C:\\TEMP1"/> <defaultCache maxElementsInMemory="12" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <Cache name="cn.itcast.hiberate.sh.domain.Classes" maxElementsInMemory="5" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
/** * 查询缓存---是建立在二级缓存之上 * ---------------------------------- * 针对超大数据的解决方案:将数据可以从数据库中拿出来放到硬盘上。 * 需要借助类路径下的ehcache.xml配置 */ @Test public void testAllClasses(){ Session session = sessionFactory.openSession(); List<Classes> classesList = session.createQuery("from Classes").list(); session.close(); try { Thread.sleep(1000); //因为代码的执行速度慢。缓存下,就可以看到 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }