hibernate总结【转】

  1. --hibernate.cfg.xml   
  2. *该文件一般位于src下面,当然可以任意放   
  3. *文件具体内容   
  4. <hibernate-configuration>//根节点   
  5.    <session-factory>//熟悉session-factory这个词   
  6.     <property name="key">value</property>//属性   
  7.     <mapping resource="xxx/xxx/xxx"/>//映射   
  8.    </session-factory>   
  9. </hibernate-configuration>   
  10. --xxx.hbm.xml   
  11. *该文件一般和实体类放在一起,其中hbm是hibernate mapping的简写形式   
  12. *文件具体内容   
  13. <hibernate-mapping>   
  14.    <class name="类完整路径" table="表名">//映射表   
  15.     <id name="属性名" colunm="列名">//主键列   
  16.      <generator class="主键生成策略"/>   
  17.     <id>   
  18.     <property name="属性名" colunm="列名"/>//普通列   
  19.    </class>   
  20. </hibernate-mapping>   
  21. --使用hbm2ddl工具导出数据表   
  22. //首先加载hibernate.cfg.xml文件   
  23. org.hibernate.cfg.Configuration cfg=neworg.hibernate.cfg.Configuration().configure("如果改名的话,可以写在里面");//如果不使用 configure()方法的话不会从根找xml而是找propoties文件   
  24. //然后通过该配置文件得到导出工具   
  25. org.hibernate.tool.hbm2ddl.SchemaExport export=neworg.hibernate.tool.hbm2ddl.SchemaExport(cfg);   
  26. //调用工具的导出方法   
  27. export.create(是否将生成的语句打印到控制台,是否执行导出);   
  28. --一次简单的保存数据过程   
  29. org.hibernate.cfg.Configuration cfg=neworg.hibernate.cfg.Configuration().configure();//首先加载hibernate.cfg.xml文件   
  30. SessionFactory sessionFac=cfg.buildSessionFactory();//通过hibernate.cfg.xml配置文件得到 sessionFactory(管理和创建session的工厂),一个数据库对应一个sessionFactory   
  31. Session session=null;   
  32. try{   
  33.    session=sessionFac.openSession();//创建一个session,对connection的一层封装,该方法抛出HibernateException,hibernate中全是RuntimeException   
  34.    session.beginTransaction();//手动开启事务,该方法抛出HibernateException   
  35.    User user=new User();   
  36.    session.save(user);该方法抛出HibernateException   
  37.    session.getTransaction.commit()//手动提交事务,该方法抛出HibernateException   
  38. }catch(Exception e){   
  39.    session.getTransaction.rollback();//发生异常,回滚事务,该方法抛出HibernateException   
  40. }finally{   
  41.   if(session!=null){   
  42.    if(session.isOpen()){   
  43.      session.close();//关闭session,该方法抛出HibernateException   
  44.     }   
  45.    }   
  46. }   
  47. --hibernate常用接口   
  48. *可以使用的数据源   
  49.    JDBC,常用的配置方式就是默认使用JDBC的连接方式的,该方式支持本地事务,不支持分布式事务   
  50.    JNDI, Java Name And Directory Interface(java名称和目录接口),每一个字符串对应到一个对象,相当于注册表一样,可以管理对象,以目录层次的方式管理注册上来的对象,解耦嘛,通过名称就能获取对象,而不不要知道具体对象的实现细节。可以通访问JNDI数据源的方式获取连接池中的连接   
  51.    JTA,Java Transaction Api,java 事务AIP,分布式事务的支持,因为hibernate.cfg.xml可以配置多个session-factory   
  52.     用容器的方式管理分布式数据库的事务,使用两阶段提交协议来实现分布式事务的原子性   
  53. *无侵入性的接口   
  54.    Configuration,用于读取hibernate.cfg.xml配置文件   
  55.    SessionFactory, 每一个SessionFactory对应一个数据库实例,它是重量级的,创建很耗时,所以一般一个程序只需要创建一份实例就行了,由于推荐只有一份实例,所以他是线程安全的,由于他对应的整个数据库,所以它中间管理的缓存能被多个session实例共享,就是说它维护二级缓存   
  56.    Session,一般每一次请求对应一个session,它是通过SessionFactory创建的,非线程安全,所以注意同步,自身管理它的事务,自身管理他的connection,并和一级缓存息息相关,用一套很复杂的机制管理对象的状态   
  57.     只有用的时候它才从连接池获取connection对象,而不是open之后就打开连接   
  58.     虽然我们配置的JDBC方式,但hibernate内部默认实现了连接池的,所以不会有多大的性能问题,就用常规的配置方法就够了   
  59.     session用完之后必须关闭   
  60.    Transaction,用于管理事务的接口,和session接口密切相关   
  61.    Query,hibernate中实现查询的接口,支持普通SQL语句和HQL(hibernate query language)语句(HQL也是adapter设计模式的运用,首先这套语法操作对象,适合于任何数据库,就是对sql语句功能的扩展的适配而已)   
  62.    UserType,扩展转换器使用的接口,和struts的Convert机制一致   
  63.    Interseptor,拦截器,类似于servletAPI中的Filter,能拦截到对象修改的事件,比如保存之前,修改之后的事件拦截(简单的说就是状态改变的事件会被拦截,可以再三种状态的转换过程中处理一些事情)   
  64. *有侵入性的接口(不建议使用)   
  65.    Lifecycle,和拦截器差不多,比如保存之前,修改之后之类的事件拦截(简单的说就是状态改变的事件会被拦截,可以再三种状态的转换过程中处理一些事情)   
  66.    Validatable,类似于struts中actionForm中的validate,没多大意义,因为一般情况下都是只有安全的数据才能进入持久层,没必要再验证了嘛   
  67.      
  68. --持久对象的生命周期(Persistent Object)   
  69. 在session的管理下对象的三种状态   
  70.    瞬时(Transient Object) 没有被session管理,并且数据库中没有对应的记录(对应是通过主键来判断的)   
  71.     刚new出来的对象,被session.delete()的持久化对象   
  72.    持久(Persistent Object) 被session管理,并且数据库中有对应的记录,管理意味着对象的引用地址被session持有,简单说就是引用地址放在session中维护的缓存里面了,当然不会被GC回收   
  73.     从数据库中get(),load(),find(),iterator().list()出来的对象,因为都是从数据库中本生就存在的记录读取出来,当然是持久的了   
  74.     当瞬时对象调用,save(),或者saveOrUpdate(),没有则插入,有则修改这些方法之后,成为持久对象   
  75.     当离线对象,调用它的update,saveOrUpdate,方法后成为持久对象   
  76.    离线(Detathed Object)   没有被session管理,但是数据库中有对应的记录   
  77.     当持久对象被evict(),或者session.close(),session.clear()之后,持久状态变为离线状态,因为session已经关闭,或者session的缓存已经不存在了   
  78. 注意三者之间会智能的转换,没有绝对的定义   
  79.    比如刚new出来的对象,但是通过ID可以判断他在数据库中有与之对应的记录,所以可以直接调用他的delete方法,在调用的时候实际上它已经是持久对象了   
  80.    刚new出来的对象,可以直接调用他的saveOrUpdate,或者update方法,如果在数据库有对应的记录,实际上将它看成离线状态了   
  81.    很简单,最重要的是是否有与之对应的记录,是否被session管理他会自动判断   
  82.   
  83. --请写一个单例   
  84. public class Singleton {   
  85.   private static Singleton singleton=null;   
  86.   private Singleton(){}   
  87.   public synchronized static Singleton getInstance(){   
  88.    if(singleton==null){   
  89.     return new Singleton();   
  90.     }else{   
  91.     return singleton;   
  92.     }   
  93.    }   
  94. }   
  95.   
  96. --JUnit   
  97. *单元测试工具,有了他就可以以方法作为单元进行测试,而不需要每次都依赖用main()方式测试   
  98. *首先需要继承junit.frameword.TestCase类,方法名以"test"开头,必须为public void,方法不能有参数   
  99. *assertEquals(),断言方法实现测试,setUp()在类初始化的时候执行,tearDown()方法在类消亡之前调用   
  100.   
  101. --session接口的基本用法和该接口实现类生命周期   
  102. *通常情况下让session和事务的生命周期一致是比较好的方式   
  103. *实例分析一   
  104.    User user=new User();   
  105.    session1.save(user);//生成主键ID,如果是需要数据库生成则发语句,否则不发语句,并将user纳入session管理,放入insert这个map结构中(成为persistent状态)   
  106.    user.setName("xxx");//将状态放入session的数据快照中   
  107.   //实际上这里也可以显示的调用session.update(user),但没有任何作用   
  108.    session1.getTranaction().commit();//检查脏数据,从insert机构中构造出insert语句,数据快照对比构造出update语句,并发出语句   
  109.    session1.close();   
  110.    user.setName("xxx")//user现在是离线状态,它的修改不修改session里面任何东西   
  111.    session2.update(user);//发出update语句,并将user再次纳入session管理   
  112.    session2.getTransaction().commit();   
  113.    session2.close();   
  114. *实例分析二   
  115.    User user=session.get(User.class,"存在的ID");   
  116.     发出sql语句,并返回User对象的引用   
  117.    User user=session.load(User.class,"存在的ID");   
  118.     不发出sql语句,返回User的继承类(cglib帮忙实现的),注意JDK的动态代理需要目标对象实现接口,而cglib不需要,它是用生成继承类的方式实现代理的   
  119.     当第一次使用到该代理的getXXX()方法的时候,代理类会检查成员变量target是否为空,如果为空则发出sql语句,填充数据   
  120.    User user=session.get(User.class,"不存在的ID");   
  121.     发出sql语句,返回null  
  122.    User user=session.load(User.class,"不存在的ID");   
  123.     不发出sql语句,返回User的继承类(cglib帮忙实现的)   
  124.     当第一次使用到该代理的getXXX()方法的时候,代理类会检查成员变量target是否为空,如果为空则发出sql语句,如果从数据库中没有找到对象则抛出ObjectNotFoundException   
  125.     就算class上的lazy=false也会抛出该异常   

  1. --Query接口的简单使用   
  2. *前面的get,load只能通过主键来取一条记录,如果需要取多条记录的话就需要使用Query接口了   
  3. Query query=session.createQuery("HQL");//只能用HQL,session.createSQLQuery("支持普通sql")   
  4. query.setFirstResult(2);//从第三条开始取,   
  5. quety.setMaxResults(2);//取两条数据出来   
  6. List list=query.list();//返回List集合   
  7.   
  8. --hbm.xml中标签的常用基础属性   
  9. <hibernate-mapping   
  10.    package="xxx.xxx"//定义全局的package,可以简化子标签   
  11.     auto-import="true/false"//默认为true,比如在HQL中能直接只用("from User"),就是该属性的作用,如果为false则必须写全类的路径(包名+类名)   
  12.     >   
  13.    <class  
  14.     name="对应的类名"  
  15.     table="生成的表的名称"  
  16.     discriminator-value="鉴别值"//和继承映射有关,增加的鉴别列的值是什么,使用在一棵继承树映射成一张表,常用在<sub-class>标签里面,不常用在<class>标签里面   
  17.     dynamic -update="true/false"//默认为false,如果设为true,那么只有修改的属性才生成update语句(比如我只setName (),它会生成只修改name的sql语句,但是这样不能复用SQL语句了),但是能节约网络流量,需要则中考虑   
  18.     dynamic-insert="true/false"//默认为false,和update一致,如果为true,那么空属性不会添加到insert语句中   
  19.     betch-size="缓存相关"//它指示每次查询多少条记录,性能优化的时候注意使用   
  20.     optimistic-lock=""悲观锁和乐观锁,后期补上,设置了这种锁模式,那么get或者load的时候,不需要指定锁模式,都能应用锁模式   
  21.     lazy="true/false"//延迟加载,默认支持lazy,基本上所有的lazy特性的都是true,只有property属性上的lazy默认为false   
  22.     >   
  23.     <id   
  24.      name="属性名"  
  25.      column="生成的列名"  
  26.      type ="string"使用自定义的数据转换实现方式,,假定该属性类型为String,那么默认转换是(string------> varchar),但是只要type="long"则(string----->long),一般使用默认转换机制就行了   
  27.      lentgh="长度",默认为255  
  28.     >   
  29.      <generator class="生成策略">//常用的生成策略有   
  30.             1.increment:依赖本机java虚拟机生成标识,但是只保证自己的机器上不重复   
  31.             2.identity:依赖数据库的生成策略   
  32.             3.sequence:orical的序列主键生成方式   
  33.             4.uuid:hibernate生成的32为字符串   
  34.             5.native:根据数据库只能选择是identity还是sequence等等   
  35.             6.assigned:程序员手动分配,字符串类型(varchar)   
  36.             7.foregin:一对一主键关联的时候用,到时候补充上,就是用其他表的主键的值   
  37.              其中uuid的生成效率最高,但是字符串的查找比数字慢,没什么性能上的权衡   
  38.         
  39.      </generator>   
  40.     </id>   
  41.     <property   
  42.      name="属性名"  
  43.      column="自定义的列名"  
  44.      type="xxx"//修改默认的转换机制,一般都是用默认值,和ID的type属性一样   
  45.      update="true/false"//默认为true,是否出现在update语句中,如果设成true了,那么相当于只读属性了   
  46.      insert="true/false"//默认为true,是否出现在insert语句中,如果设成true那该属性永远都是null,或者初始化的值   
  47.      lazy="true/false"//晚加载,使用类加强工具来实现lazy特性,一般用在数据量比较大的列上,默认为false   
  48.      unique="true/false"//是否唯一,就是指定它是否自动添加唯一键约束   
  49.      not-null="true/false"//是否为非空   
  50.      length="长度"//修改默认生成长度   
  51.     />   
  52.    </class>   
  53. </hibernate-mapping>   
  54.   
  55.   
  56. --实体类的设计原则   
  57. *必须要有一个无参的构造方法,因为hibernate会用到   
  58. *使用非final,如果为final那么cglib怎么继承它呐?   
  59. *提供get,set方法,因为hibernate对调用它。   
  60.   
  61. --多对一关联映射   
  62. *用户的组的关系就是多对一   
  63. *从多方能够找到一方的引用   
  64.    <many-to-one name="group" column="groupid"/>在本身的一方增加"groupid"外键列,引用Group表的主键   
  65. *保存   
  66.    一的一方必须要是持久状态才能在多的一方持有一的一方的引用,注意这个持久状态是可以手动构造出来的   
  67.    可以使用casecode来级联save,那么在持久化多方之前会先持久化一的一方   
  68. *删除多方的一条记录的时候如果有cascade="delete",会将一方的数据一同删掉,会出问题   
  69. *读取   
  70.    <many-to-one>的lazy默认为true,注意理解该lazy是作用于user中的group的   
  71.     lazy为默认值true的时候   
  72.      get(user)立即发送sql语句返回的user对象,当不调用user.getGroup()的时候,不会发出查询group的语句,只有用到group的时候才发出   
  73.      load(user)返回user代理对象,当调用user的普通属性的时候发出查询普通属性的sql,但也不会发出查询group的语句,只有用到group的时候才发出   
  74.     lazy为false的时候   
  75.      get(user)立即发出查询普通属性和group的所有语句   
  76.      load(user)什么都不发出,但是一旦访问任意普通属性,都将发送查找group的语句   
  77. --一对一关联(主键,单向)   
  78. *将数据拆分成两张表一般运用一对一关联映射   
  79. *人和省份证就是一对一   
  80. *也是一样:一方需要持有另一方的引用,   
  81. *原理:其中一个表的主键又作为外键参照另一个表的主键,主键生成策略为foreign,然后指定关联的引用对象是什么<one-to-one>,意思就是用什么来维持这样一对一的关系   
  82.     比如用户持有省份证对象的引用   
  83.     第一步:配置生成策略   
  84.     <id name="id">   
  85.      <generator class="foreign">//表示本ID依赖另一张表的逐渐   
  86.      //主键来源于哪里呢?   
  87.       <param name="property">idCard(表示主键来源于那个对象的主键)</param>//其中"property"表示属性   
  88.      //整个的意思这样理解,本表的主键来源于idCard对象的主键   
  89.      </generator>   
  90.     </id>   
  91.     第二步:配置关联关系   
  92.     <one-to-one name="idCard" constrained="true"/>//这样才能完成的加上外键约束,就是用什么来加载它的关联对象,如果不配的话,那表的完整性就不够了   
  93.      <one-to-one>默认使用主键加载   
  94. *<one-to-one>默认cascade="all",意思就是说不设定cascade并且没有先保存另一个对象,也不会发生TransientObjectException异常   
  95. --一对一关联(主键,双向)   
  96. *其中一对一主键单向关联已经将所有的关系建立好了,   
  97. 作为双向只需要在另一端持有引用,然后指示hibernate怎样加载就行了。   
  98. 所以在另一方只需要加上   
  99. <one-to-one name="维护关系的对象"/>当然不能再有constrained="true",参照关系已经完全建立起来了,不需要再关系上再考虑,只修改对象模型,关系模型不需要任何修改   
  100. 一对一的逐渐关联的另一方的<one-to-one>的抓取策略为join,那本生的一端的抓取策略是什么呐?还是select没有任何影响,   
  101. *<one-to-one>中没有inverse属性,所以还是规规矩矩的从维护主逻辑的那边插入数据咯   
  102. --一对一关联(外键,单向)   
  103. *多出一个外键列来维持关系   
  104. *思路,使用<many-to-one>标签增加外键参照对方的主键,但让该外键列不能重复   
  105.    <many-to-one name="关联属性" column="添加的外键列名" unique="true">   
  106. --一对一关联(外键,双向)   
  107. *在单向的基础之上,关系模型没有任何变化,对象模型增加一个引用   
  108. *然后在另一方使用<one-to-one>但是他默认指向对方的主键,怎么办呢<one-to-one name="xxx" property-ref="对方生成的外键列"/>OK!   
  109.    这种形式,从另外一端加载也是默认采用的join抓取策略,注意了这样的共性,如果<one-to-one>使用在非主逻辑的一方,它的抓取策略都是join   
  110. *<many-to-one>和<one-to-one>都没有inverse属性,所以不要想利用这种机制,只有集合上有inverse属性   
  111.   
  112. --cascade只对存储有作用,对加载无任何效果   
  113.   
  114. --session.flush()   
  115. *在事务提交之前默认实行,或者显式的调用session.flush()方法   
  116. *作用:数据检查,执行SQL(但是还没有提交)   
  117. 代码分析一(借助hibernate的主键生成策略)   
  118.    User user=new User();   
  119.    session.save(user);   
  120.   //由于是hibernate自身的主键生成策略,不会发出SQL语句,此时将user纳入session的缓存中,并且该缓存中的existInDatabase=false,因为没有发sql语句嘛,insert队列中加入该对象  
  121.    session.flush();   
  122.   //数据检查,清理缓存,发现insert队列中有数据,构造出insert语句,发出语句后清空该队列,并且将缓存中existInDatabase=true   
  123.   //此时只是发出SQL语句,但是事务没有提交,视数据库隔离级别可能在数据库中能看到该数据  
  124.    session.getTransaction().commit();   
  125.   //正式提交事务,事务一旦提交无法回滚   
  126. 代码分析二(借助数据库的主键生成策略)   
  127.    User user=new User();   
  128.    session.save(user);   
  129.   //由于依赖于数据库生成策略,发出sql语句,相当于hibernate实现的主键生成策略的save并加上flush方法;   
  130.    session.flush();   
  131.   //检查数据,检查insert等队列什么也没有,也就是任何操作都不会做   
  132.    session.getTransaction().commit();   
  133.   //事务提交   
  134. 代码分析三(借助hibernate的主键生成策略)   
  135.    User user=new User();   
  136.    session.save(user);   
  137.    session.evict(user);   
  138.   //将user从缓存中清除但是insert集合中有数据   
  139.    session.flush();   
  140.   //检查数据发现insert集合中有数据,形成insert语句,清除insert集合,并试图将缓存中的existInDatabase=true,但是这时该缓存已经不存在,所以抛出“线程不安全异常”   
  141.    session.getTransaction().commit();   
  142. 那么怎样解决分析三中的问题呢?看代码分析四的解决方案   
  143. 代码分析四(解决三种的问题)   
  144.    User user=new User();   
  145.    session.save(user);   
  146.    session.flush();   
  147.   //执行了flush之后insert临时集合数据没有,下面再调用commit的时候当然不会试图在去修改existInDatabase了,当然不会出现异常咯   
  148.    session.evict(user);   
  149. 代码分析五   
  150.    User user=new User();   
  151.    session.save(user);   
  152.    user.setName("xxx");   
  153.    User user2=new User();   
  154.    session.save(user2);   
  155.   //发出的语句顺序是insert,insert,update,可以和意图不一致,那么在update的时候显示的调用一下flush就行了,注意这个小细节   
  156. --数据库隔离级别   
  157.   
  158. 隔离级别     是否存在脏读   是否存在不可重复读   是否存在幻读   
  159. -----------------------------------------------------------------------------------------   
  160. read uncommited   YES     YES      YES   
  161. -----------------------------------------------------------------------------------------   
  162. read commited   NO     YES      YES     Oracle默认   
  163. -----------------------------------------------------------------------------------------   
  164. repeatable read   NO     NO      YES     MySql默认   
  165. -----------------------------------------------------------------------------------------   
  166. synchronized read   NO     NO      NO   
  167. -----------------------------------------------------------------------------------------

  1. 名词解释   
  2.    *脏读,事务还没有提交就能读出来数据,这一动作叫脏读   
  3.    *不可重复读,比如本次读出的姓名为张三,刷新后变成李四,由于查询出来的数据没有被锁定,这种情况其他用户可以修改数据,也就出现了脏读的现象,一般发生于被修改   
  4.    *幻读,比如本次读出5条记录,刷新后为10条,感觉是幻觉一样,一般存在于数据的增加或删除   
  5.   
  6. --一对多单向   
  7. *注意<one-to-many>这个标签是嵌入到set或者bag标签中的,   
  8. *关系模型和多对一是一样,只不过我要从一的一方去加载多的一个集合   
  9. *set和bag分别使用set和list两种保存数据的结构区别而已,bag有序可重复,set无序不能重复   
  10. *在对象模型中要用Set或者List接口类型,而不能用HashSet,或ArrayList之类的,因为hibernate也对集合实现了延迟加载,它生成的代理的原理是实现List和Set接口,从而扩展功能,如果你使用HashSet它怎样去实现了,特别注意了   
  11. *标签解释   
  12.    <set name="students">   
  13.     <key column="classid"></key>//在多的一方加入classid列,作为外键指向本对象的主键,但是"students"的类型是set,我怎么知道多的一方是什么呐,通过下面的<one-to-many>标签表示   
  14.     <one-to-many class="xxx.Student"/>//指定多的一方的类型   
  15.    </set>   
  16. *保存   
  17.    *同样的班级的学生的问题   
  18.    *set的lazy默认为true,不管是get还是load如果不使用到集合中的数据则不会发出语句   
  19.    *同样注意TransientObjectException问题,所以先存学生再存班级才正确,但是存学生的时候还不知道只那个班的,所以学生中指向班级的外键列为空,   
  20.     当存班级的时候会update该外键列,因为是班级这方维护关系的嘛(这是hibernate的实现机制),这样会造成一定的问题,和数据库操作过多,怎样解决呢?   
  21.     上面的问题就算是在set上设置了cascade也不能防止udate语句的发生啊,它只不过自动先给调用了save学生的方法而已嘛   
  22.     所以在一的一端来维护这样的关系不是很推荐,还是在多的一端来维护更好些   
  23.     使用了inverse=true,那么一的一方不管关系了,虽然不发update语句,但是关系无法维护啊,因为一的一端就是通过update来维护关系的,又怎么办呢?   
  24.     所以还是没有办法,只有从多的一方存,其实有一种方案可以解决的,结合cascade,但是没多大意义,这里就不深究了,就从多的一方来存吧   
  25.     所以一般inverse不是用在一对多双向中,而是用在多对多双向里面的,在一对多双向里面注意使用cascade就够了,但是也可以用inverse,但是意义不大奥   
  26.     并且一的一方<set>加入inverse=true,多的一方<many-to-one>中加入cascode="all"  
  27. *加载   
  28. 一对多双向的就是为了在多的一段维护关系才需要搞成双向的,注意他存在的意图   
  29.   
  30. --标签优化对比   
  31. ---------------------------------------------------------------------------------------   
  32. 标签     是否支持lazy   是否支持cascade   是否支持inverse   
  33. ---------------------------------------------------------------------------------------   
  34. <one-to-many>   NO     NO      NO   
  35. ---------------------------------------------------------------------------------------   
  36. <class>     YES     NO      NO   
  37. ---------------------------------------------------------------------------------------   
  38. <many-to-many>   NO     NO      NO   
  39. ---------------------------------------------------------------------------------------   
  40. <many-to-one>   YES     YES      NO   
  41. ---------------------------------------------------------------------------------------   
  42. <one-to-one>   YES     YES      NO   
  43. ---------------------------------------------------------------------------------------   
  44. <set|bag>    YES     YES      YES   
  45. ---------------------------------------------------------------------------------------   
  46. 其中<one-to-many>和<many-to-many>都是<set>或<bag>的子标签   
  47. inverse只能用在set或者bag标签中,只对存数据有关联,和删除,修改都无效果   
  48. ---------------------------------------------------------------------------------------------------------------------------------------   
  49. lazy特性详解   
  50.    *hibernate的lazy只有在session开启的情况下才有效,如果session关闭的时候,会发生代理不能初始化异常,这在web开发中很容易出现   
  51.     也可以说lazy的生命周期和session是一致的,一般可以让session开着,或者关闭lazy属性,让它返回本省的对象,不要让它返回代理对象   
  52.     get本省就返回真实对象,但不影响他属性(实体对象类型)的lazy特性,而load返回代理对象,当然也不影响他属性的lazy特性了   
  53.    四中标签上的lazy特性   
  54.     *<class>(默认打开,可选true/false)也就是对象的lazy:该对象在被加载上来的时候的lazy特性   
  55.     *<property>(默认为关闭,可选true/false)属性上,使用类加强工具来实现lazy,也就是说用到该属性的时候才执行SQL,用的很少,可以不用掌握   
  56.      这种情况就像是我在C#实现的lazy特性,数据量很大的属性可以设置该lazy特性,设置为true之后,那么该属性只有用到的时候才从数据库查   
  57.     *<set>(默认打开,可选true/false/extra)也就是集合的lazy:该集合在被加载上来的时候的lazy特性   
  58.      集合的lazy也是用代理实现的,它的实现和类不一样,它是通过实现set等集合接口来加强它的功能,这是hibernate的扩展,而不是cglib干的了   
  59.      extra:智能,比如调用集合.size()只会发select count(*),而如果是true的话会将所有的集合元素都查询上来   
  60.      所以推荐使用extra   
  61.     *单端关联(默认proxy,可选false/proxy(使用代理实现lazy)/noproxy(使用类增强工具实现lazy))   
  62.      什么是单端关联,就是对方是one(one-to-one,many-to-one),因为”多端关联“标签就使用set上的lazy特性,再给这样的属性的话就多余了嘛   
  63.      默认的proxy和集合是完全一样的   
  64.      但是noproxy为什么会出现呢?只是另一种实现机制而已   
  65. --多对多单向   
  66. *通常使用中间表来维护关系   
  67. *中间表为复合主键   
  68. *标签   
  69.    <set name="set集合属性名" table="要生成的第三方表名">   
  70.     <key column="在第三方表生生成的列,作为外键参照本表的主键"/>   
  71.     <many-to-many class="对方的类">   
  72.      <column name="该对方的类在第三方表生成的列,作为外键惨遭对方表的主键"/>   
  73.     </many-to-many>   
  74.    </set>   
  75. --多对多双向   
  76. *inverse用在多对多的双向中才有它的意义,能不免不必要的多余的sql语句   
  77. *很简单,理解了单向就理解了双向   
  78. --自连接映射(很简单)   
  79. <class name="Node">   
  80.    <id name="id">   
  81.     <generator class="identity"/>   
  82.    </id>   
  83.    <set name="children">   
  84.     <key column="parentId"/>   
  85.     <one-to-many class="Node"/>   
  86.    </set>   
  87.    <many-to-one name="parent" column="parentId"/>   
  88. </class>   
  89. --基础映射总结   
  90. *一对多中对一中set中元素的删除,只会update多的东西,不会删除   
  91. *多对多中对一方set中元素的删除,会删除中间表的数据,   
  92. --继承映射(一颗继承树映射成一张表)   
  93. 关系模型,整个整成一张表,表里有一个列用来鉴别是那种类型   
  94. 映射配置   
  95.    <class name="Animal(父类)" table="t_Animal">   
  96.    <id name="id">   
  97.     <generator class="identity"/>   
  98.    </id>   
  99.    <discriminator column="type(加入的鉴别列名)" type="string(鉴别值的类型,是varchar还是int等)"/>   
  100.    <property name="name"/>//父类的属性   
  101.    <subclass name="Bird(子类)" discriminator-value="B(鉴别值是什么)">   
  102.     <property name="weight(子类中加入的属性)"></property>   
  103.    </subclass>   
  104.    <subclass name="Pig(子类)" discriminator-value="P(鉴别值是什么)">   
  105.     <property name="hight(子类中加入的属性)"></property>   
  106.    </subclass>   
  107. </class>   
  108. *Animal al=load(Animal.class,1);   
  109. 注意该al的instanceof是生成的代理类型,而代理又是Animal的子类   
  110. 但是使用get(或者load方式,但是class上lazy设为false)就能返回具体的类型,也就是说是Pig啊还是Bird啊,也就是说它支持多态查询,也就是说虽然你查的是Animal.Class,但是他因该返回实际的子类类型   
  111. 使用HQL返回的LIST中式具体的类型,注意不会返回代理,如"from Animal".list()返回具体的类型,所以可以通过"from java.lang.Object".list()返回数据库的所有对象   
  112.   
  113. ********************list()不会返回对象代理,而iterator()会返回对象的代理********************   
  114.   
  115. --继承映射(每个类存为不同的表,包括父类)   
  116. *Animal,Pig,Bird分别才能三张表   
  117. *关系模型,每个子类表有一个PID作为外键参照Animal的主键OK   
  118. <class name="Animal(父类)" table="t_Animal">   
  119.    <id name="id">   
  120.     <generator class="identity"/>   
  121.    </id>   
  122.    <property name="name"/>   
  123.    <joined-subclass name="Pig" table="t_pig">   
  124.     <key column="pid(增加该列作为外键参照Animal的主键)"/>   
  125.     <property name="weight(子类增加的属性)"/>   
  126.    </joined-subclass>   
  127.    <joined-subclass name="Bird" table="t_bird">   
  128.     <key column="bid(增加该列作为外键参照Animal的主键)"/>   
  129.     <property name="height(子类增加的属性)"/>   
  130.    </joined-subclass>   
  131. </class>   
  132. *这种方式的多态查询和第一种一致   
  133. --继承映射(每个子类存为不同的表,不存父类)   
  134. 关系模型,每个子类该有什么字段就有什么字段   
  135. 配置方式,注意第一不要生成父类,让他为抽象,第二不能使用自增   
  136. <class name="Animal(父类)" abstract="true"><!-- (让父类不生成表) -->   
  137.    <id name="id">   
  138.     <generator class="assigned,或者uuid"/><!-- 不能在使用identity,因为每个子类都为单独的表,自增特性会加到子类,那么会重复,重复了又怎样加载呐 -->   
  139.    </id>   
  140.    <property name="name"/>   
  141.    <union-subclass name="Pig" table="t_pig">   
  142.     <property name="hight(子类增加的属性)"/>   
  143.    </union-subclass>   
  144.    <union-subclass name="Bird" table="t_bird">   
  145.     <property name="weight(子类增加的属性)"/>   
  146.    </union-subclass>   
  147. </class>   
  148. 和前两种的多态查询机制一致   
  149. --三种继承方式比较(综合考虑使用那种)   
  150. 第一种,效率会高,但是有冗余字段   
  151. 第二种,表多,效率低,但是关系很清晰   
  152. 第三种,则中,但是不是用自增主键生成策略   

  1. --组合映射   
  2. 对象模型中,不是关联关系,而是聚集关系,也就是说没有OID对象为组件的部分   
  3. 对象模型,组件对象,和需要使用的组建对象   
  4. 映射方式,很简单,使用<component>标签搞定   
  5. <class name="Person">   
  6.    <id name="id">   
  7.     <generator class="identity"/>   
  8.    </id>   
  9.    <property name="name"/>   
  10.    <component name="body(组件类型)">   
  11.     <property name="手"/>   
  12.     <property name="脚"/>   
  13.    </component>   
  14. </class>   
  15. 关系模型:会生成一张表,在对象模型里面能将组件取出来单独使用   
  16. 在存的时候,不需要先save组件,也不能save组建,因为他不是pojo实体,没有oid,什么是实体(java类加上映射文件就是实体)   
  17. --联合主键映射,可以看成组建映射的特例,主键类可以复用   
  18. 对象模型   
  19.    将主键属性单独封装到一个类中,该类实现序列化接口,并且需要给予联合主键的属性生成复写equals,和hashcode方法   
  20.    需要实现联合主键的类持有该类引用   
  21. 关系模型,生成一张表   
  22. 映射配置,很简单   
  23. <class name="Person">   
  24.    <composite-id name="持有的联合主键类的名称">   
  25.      <key-property name="联合主键类的属性一"/>   
  26.      <key-property name="联合主键类的属性二"/>   
  27.    </composite-id>   
  28. </class>   
  29.   
  30. --普通集合的映射(很简单)   
  31. 不再是关联映射,也就是说对象模型只有一个对象,集合是对象的一个子集而已,没有对应的对象模型   
  32. 关系模型,每个集合会单独创建一张表来保存数据,之间用主外键的形式关联   
  33. <set name="setValue" table="set_value(生成一张表来存集合数据)">   
  34.    <key column="set_id"/>   
  35.    <element type="string(集合里的对象存为什么类型)" column="值放在setValue的那个列中"/>   
  36. </set>   
  37. <list name="listValue" table="list_value"><!-- 和数组(<array>标签)用法一致 -->   
  38.    <key column="list_id"/>   
  39.    <list-index column="lisi_index(存索引的列名)"></list-index>   
  40.    <element type="string(集合里的对象存为什么类型)" column="值放在setValue的那个列中"/>   
  41. </list>   
  42. <map name="mapValue" table="map_value(生成一张表来存集合数据))">   
  43.    <key column="map_id"/>   
  44.    <map-key type="string" column="key存在什么列中"></map-key>   
  45.    <element type="string(集合里的对象存为什么类型)" column="value存在什么列中"/>   
  46. </map>   
  47.   
  48. --悲观锁   
  49. 在read commited数据库隔离级别下面实现悲观锁,就等同于将数据库隔离级别升级到repeatable read,因为我不让其他人改,当然就实现了可重复读咯   
  50. 悲观锁,锁定的输入其他任何用户都不能"查看",更不能修改,注意查看都是不允许的哦,由于这种特性,最好用在短事务,而不要使用长事务   
  51. hibernate对悲观锁的支持,当查询出来之后锁定,具体怎么样支持的呢?   
  52.    load(xxx.class,1001,LockMode.UPGRADE);生成select ..... for update;行级别锁,OK!   
  53.    注意使用了锁模式,load的lazy失效,马上发sql语句,并且返回实际的对象,而不是代理   
  54.    其他用户会阻塞,等待第一个用户commit或者rollback事务之后才继续执行   
  55. --乐观锁   
  56. 锁定之后其他用户能查看也能修改,那它又是怎么解决更新丢失问题的呢?   
  57. 严格意义上它不是一种锁,只不过是一种更新检测手段而已   
  58. 原理,数据库中加入版本等级列,来记录每条数据的版本,更新一次版本加一,当试图在读取出来的旧版本上更新数据时,无法更新,只有版本和数据库版本一致才能更新   
  59. 那么hibernate的实现细节是什么呢?   
  60.    在配置文件中加入<version name="生成的记录版本号的列名"/>   
  61.    ok,其他什么都不用做,也不需要在加载数据的时候给锁模式,因为他本生就不是锁嘛,在更新的时候hibernate会自动判断   
  62. 由于乐观锁并发性比较高,所以一般都是用乐观锁   
  63.   
  64. --HQL(hibernate还有对象化查询,但是不成熟,所以可以不用掌握)   
  65. 它和任何数据库都没有关系,它会通过方言来翻译成对应的数据库的sql语言   
  66. HQL中用"."导航类的属性,如"from User user where user.group.name like '%xxx'"  
  67. 在HQL中关键字不区分大小写,但类名,属性名需要区分   
  68. HQL也可以使用别名,和SQL一样,可以使用直接给别名,也可以使用"as"关键字   
  69. HQL可以使用数据库的特定函数,但是这样移植性就会有问题   
  70. *简单属性查询(不能忽略select)   
  71. 查询单一属性的话,返回该属性类型的list集合,查询多个属性的话,返回object数据,没什么,如果是我来实现hibernate也会这样做   
  72. 但是如果我想将查询某些属性,但是我需要以类型集合方式返回list怎么办呢?呵呵,hibernate当然想到了这些,使用下面的HQL:   
  73.   "select new User(id,name) from User",前提条件User要有User(int id,String name)这样的构造函数   
  74. *实体对象查询(可以忽略select)   
  75. 使用select 查询实体对象必须采用别名如:"select user from User as user",而没有*之类的概念,只有函数里面才能使用"*"  
  76. Query.list()返回List接口,并将所有的数据放入List集合中,当调用该方法时,发出查询所有数据的SQL语句   
  77. Query.iterator()返回Iterator迭代接口,当调用该方法时只返回id的集合,并不是所有的数据,而调用该迭代器去取得其中元素的时候,首先去session(一级缓存中找),如果没有找到则发出查询该条记录的SQL语句,如果找到直接使用   
  78.    那么这可能会出现多次发出sql语句的问题,这就是N+1问题,注意避免   
  79. 如果首先执行了list将数据放入session中那个缓存集合里面,再使用迭代查询就不会出现N+1问题了,因为他在session的缓存中能找到记录,(但是获取迭代接口的时候也会发查询id的语句)   
  80. 结论   
  81.    迭代接口使用缓存,但是每次都会发送查询id的语句   
  82.    而(默认情况下)list接口不适用缓存,每次他都会发sql语句,它只往缓存写数据,而不从缓存中用数据   
  83.     那么在那种情况下才使用缓存呢?后面再说,配合查询缓存就不会发了,前提是第二次使用list它能从缓存里通过ID找到缓存的对象   
  84. *条件查询   
  85. 可以用参数占位传参方式:   
  86. Query query=session.createQuery("from User user where user.name like ?");   
  87. List list=query.setParameter(0,"%张").list();注意从0开始索引,而JDBC是从1开始索引的,并注意方法链的支持   
  88. 可以用参数命名传参方式:   
  89. Query query=session.createQuery("from User user where user.name like :name");   
  90. List list=query.setParameter("name","%张").list();注意从0开始索引,而JDBC是从1开始索引的,并注意方法链的支持   
  91. 可以用参数命名集合传参方式   
  92. Query query=session.createQuery("from User user where user.name in (:names)");   
  93. List list=query.setParameterList("names",new Object{"张三","李四"}).list();   
  94. *原生的SQL语句(使用createSQLQuery)   
  95. Query query=session.createSQLQuery("select * from t_user");不能在给类名了,   
  96. query.list()返回object数组   
  97. 所以在批量更新的时候就最好使用原生sql   
  98. *外置命名查询   
  99. 就是把HQL放在配置文件里面   
  100. 在hbm.xml中的<hibernate-mapping>下,而不是<class>下,因为他不属于某个实体嘛,加上   
  101. <query name="searchStudent">   
  102.    <![CDATA[   
  103.     from Student(这里写的语句和xml本生的符号不冲突)   
  104.    ]]>   
  105. </query>   
  106. 读取方式   
  107. Query query=session.getNamedRuery("searchStudent");   
  108. *查询过滤器   
  109. 原理,面向切面的编程   
  110. 配置   
  111. <hibernate-mapping package="entity">   
  112.    <class name="Student">   
  113.     <id name="id">   
  114.      <generator class="identity"/>   
  115.     </id>   
  116.     <filter name="idFilter" condition="id &lt; :myid"/>   
  117.    </class>   
  118.    <filter-def name="idFilter">   
  119.     <filter-param name="myid" type="integer"/><!-- 使用hibernate的类型 -->   
  120.    </filter-def>   
  121. </hibernate-mapping>   
  122. 如何启用   
  123. session.enableFilter("idFilter").setParameter("id",10);只对当前设置了过滤器中session的HQL查询有效   
  124.   
  125. --分页查询   
  126. 设置两个属性OK   
  127.   
  128. --连接查询   
  129. 内连接 "select u.name,g.name from User u join u.Group g "不需要写on因为,映射文件里已经有这个关系了----->生成inner join on ...语句   
  130. 外连接 也是left join和right join,没什么   
  131.   
  132. --统计查询   
  133. Query query=session.createQuery("select count(*) from User");   
  134. query.list().get(0)为long数据类型,看更好的方法   
  135. query.uniqueResult()返回object,里面的类型为long---->返回首行首列,返回对象而不是list接口引用   
  136. HQL中也能使用group by,和集合函数一起使用   
  137.   
  138. --在HQL中可以使用DML语句   
  139. DML(Data Manipulation Language)数据操作语言,就是修改,删除,插入   
  140. DDL(Data Definition Language)数据定义语言   
  141. 在HQL中最好不要使用DML,比如数据已经被存入session的缓存中,然后执行了DML中的删除,HQL中的DML是不会和session缓存同步不,就会造成脏数据的问题   
  142. 为什么他不同步session的缓存呢?性能考虑,如果我批量修改很大的数据,同时修改数据库的同时在修改大量的缓存,这对性能的影响是非常恐怖的,基于这一个考虑,所有的基于ORM的框架都没有实现同步   
  143. 所以ORM框架都不擅长做聚集性操作,因为如果和缓存不同步,那就失去了框架的意义了

  1. --缓存   
  2. 缓存和池的区别,首先他们都是为了提高效率而出现的技术   
  3.    缓存中放变化不大的对象才有意义   
  4. *一级缓存   
  5.    一级缓存的生命周期是和session一致的,被session所管理,所以也叫session级的缓存,或者叫事务级的缓存   
  6.    get和load都会使用缓存,他们在取数据的时候首先回去session中找,如果找到了就不会再发出sql语句,没有找到发sql语句,并纳入session管理   
  7.    ----------迭代器问题----------------   
  8.    *迭代器查询对象,首先会发出查询id的sql语句,当对象用到的时候发查询对象的语句(前提,该对象lazy=true),如果class上的lazy=false,那么当调用iterator方法的时候会先把第一条数据加载上来放入session,   
  9.     然后第一次调用iterator.next()时候,发出查询第二条数据的sql,就这样先加载下一个然后在缓存取当前的   
  10.     也就是说迭代器每次都只发出查询一条数据的sql,并且如果缓存里有对象了,迭代器不会在发出sql语句,而是使用缓存,并且迭代出来的对象也会自动放入到缓存中去   
  11.    *迭代器查询普通属性,当调用iterator()方法的时候立即发出查询具体属性的sql(而不会先发出查ID的SQL),并且该对象是无法放在session里面的啊,因为他返回的不是一个实体,所以就算是查询同一个对象的属性它每次都会发sql   
  12.     也就是说迭代出来的普通属性,由于他不能放在session里面,所以他无法重用,也就是说不适用缓存   
  13.     也可以说session缓存只能放实体对象,而不会放其他的对象   
  14.    *不同的session不能共享一级缓存,因为分别维护不同的缓存队列嘛   
  15.    *大批量的插入也不适合使用hibernate因为他要将数据加到缓存里面,可能会照成内存溢出   
  16.     如果更要用hibernate最好的解决方案是,插入一点就flush()一次强制持久化,clear()一次清空缓存,这样相对不会照成缓存里数据溢出的问题,因为一级缓存没有失效期   
  17.    使用一级缓存的有   
  18.     get,load,iterator,注意list()只往一级缓存里写,但是他不用一级缓存,除非配合查询缓存   
  19.    一级缓存没有缓存策略,比如没有失效期等,是一种比较简单的缓存实现   
  20. *二级缓存   
  21.    需要继承第三方缓存产品,并且也是只缓存实体对象   
  22.    二级缓存也叫进程级的缓存,也可以叫sessionFactory级的缓存   
  23.    配置和使用   
  24.     使用EHCache,本生提供了ehcache这个jar包,可以通过里面的xml配置文件配置相关的缓存策略,不过使用默认值就行了   
  25.     拷贝ehcache.xml文件到src,hibernate模版提供了的,在里面也可以配置缓存策略,可以精确到每一个类的缓存(是只策略的运用,而不是是否启用缓存),但是一般让其对所有实体类有效,使用默认值就行了   
  26.     启用二级缓存(在hibernate.cfg.xml加入属性)   
  27.      <property name="hibernate.cache.use_second_level_cache">true</property>   
  28.     指定缓存产品提供商(在hibernate.cfg.xml加入属性)这里使用ehcache   
  29.      <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>   
  30.     指定实体类使用二级缓存(在xxx.hbm.xml中加入属性)   
  31.      注意一般变化不快的实体类才使用二级缓存   
  32.      在class中加入子标签<cache usage="   
  33.      read-only-->当修改数据库中数据时候缓存中数据不会改变,但这比较常用,也不会出现很大问题,因为二级缓存有过期时间啊,所以不会存在很大的数据不一致问题   
  34.      read-write-->当修改数据库中数据的时候缓存中数据会随之改变   
  35.      "/>   
  36.      也可以在hibernate.cfg.xml中加入<class-cache class="xxx.xxx" usage="read-only"/>来指定那些类使用二级缓存,这样比较直观   
  37.     那些方法支持二级缓存呢?   
  38.      首先去一级缓存找,然后去二级缓存里找   
  39.      get(),load(),iterator()都是用二级缓存   
  40.     二级缓存的管理,使用sessionFactory对象管理   
  41.      sessionFactory.evict(User.class);//清除二级缓存队列里面所有的User实例   
  42.      sessionFactory.evict(User.class,1);//清楚二级缓存里面的特定的User实例   
  43.     控制session的CacheMode   
  44.      默认是CacheMode.NORMAL;//能存也能取   
  45.      session.setCacheMode(CacheMode.GET);//让session在加载的时候只取而不存   
  46.      session.setCacheMode(CacheMode.PUT);//让session在加载的时候只存而不取   
  47. *查询缓存   
  48.    缓存普通结果,而不再局限于实体对象,并且能缓存实体中的ID   
  49.    一级缓存和session生命周期一致   
  50.    二级缓存和sessionFactory的生命周期一致   
  51.    查询缓存的生命周期是不一定的,当前关联的表发生修改,查询缓存的生命周期结束,它的生命周期不可控制   
  52.    配置和使用(查询缓存默认是关闭的)   
  53.     在hibernate.cfg.xml中修改属性<property name="hibernate.cache.use_query_cache">true</property>   
  54.     query.setCacheable(true);//开启查询缓存,从这里可以看出查询缓存是作用于query接口的方法中的,也就是和list方法和iterator有关联   
  55.      但是虽然是配置query上的,但是查询缓存对迭代接口不起作用,只对list方法有作用   
  56.    比如两个用query.list()来查询普通属性,如果开启了查询缓存则第二次不会发sql语句了   
  57.    而query.iterator,就算开启了查询缓存,每次都会发   
  58.    session和查询缓存没有关系,不同的session会共享一份查询缓存的   
  59.      
  60.    ----严重的问题----   
  61.    开启查询缓存,调用两次list查询”实体对象“(注意是实体对象而不是普通属性)   
  62.    第一次将实体对象的ID,缓存   
  63.    第二次它从查询缓存找到了ID,它会用用该缓存,用ID去一二级缓存找有没有对应的东西,如果有则用,如果没有则发N条语句   
  64.    。。怎样解决这个问题呢?由于他会通过ID去找一二级缓存,所以如果一二级缓存里有对象则第二次list一条语句也不会发,所以并不是所有情况下list都会发语句的   
  65.    结论:查询缓存和迭代没有任何关系   
  66.     当用list查普通属性的时候,会被放入缓存   
  67.     当用list查对象的时候,会将对象的ID放入缓存   
  68.       
  69. --抓取策略   
  70. 抓取什么,抓取一个类的关联的对象(所以class标签上时没有抓取策略的,因为他配置的对象怎样被加载),比如说<one-to-one>标签的轻量级一端(一对一双向,一对多双向)默认使用的join抓取策略   
  71. 抓取策略只是对get.load方法有影响,但是其中只有一种情况对HQL有影响   
  72. *单端关联上的抓取策略(为什么没有多端关联的抓取策略呢,因为多端关联默认使用集合上配置的抓取策略)   
  73.    提供两个可配置的值(select和join默认为select)   
  74.    在get或者load方法中,如果抓取策略为join的时候那么关联对象的lazy特性失效   
  75. *集合上的抓取策略   
  76.    提供三个可配置的值(select,join.subselect默认为select)   
  77.    集合也是当使用join的时候,所关联的集合对象的lazy也失效   
  78.    subselect(子查询抓取策略),这种抓取策略只对HQL查询有效,   
  79.     例子,班级和学生的抓取HQL"select class from Class class where class.id in (1,2,3)";   
  80.     默认情况下,首先发查询班级的sql,每次用到一个班级的学生时候发送这个班级对应的学生的sql,   
  81.     设置的subselect之后,首先发查询班级的sql,当用到某个班级的学生的时候将这三个半的学生全部查询出来,   
  82. --class或者set标签上的betch-size属性是干什么的,它指示每次查询多少条记录,如果没有设置的话每次查询一条(比较智能,可以不用考虑原理)   
  83.   
  84. --批量更新和查询   
  85. 在hibernate上的配置需要依赖数据库是否支持,这种配置是指挥数据库的,对程序是透明的   
  86. <property name="hibernate.jdbc.batch_size">50</property>50条为一个单位,更新   
  87. <property name="hibernate.jdbc.fetch_size">20</property>20条为一个单位,查询,取得嘛   
  88.   
  89. mySql部分支持,oracle完全支持,sqlServer完全支持   
  90.   
  91. --HQL中的fetch   
  92. 仅从使用的角度来看,预先抓取和立即检索的效果一样,只不过预先抓取可以减少sql语句的条数。 因为他预先将数据填充的缓存中,下次不需要在发出sql语句   
  93.   
  94. --ThreadLocal已经和hibernate使用维护session的开启状态   
  95. ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。   
  96. 每次个线程在从ThreadLocal取得对象的时候,该变量和当前线程绑定,是一份对象的副本   
  97. 看看filter的实现   
  98. public class HibernateUtil implements Filter {   
  99. private static ThreadLocal<Session> threadLocal=new ThreadLocal<Session>();   
  100. private static SessionFactory factory=null;   
  101. public void destroy() {   
  102. }   
  103. public void doFilter(ServletRequest request, ServletResponse response,   
  104.     FilterChain chain) throws IOException, ServletException {   
  105.    try{   
  106.      chain.doFilter(request, response);//该方法是阻塞行的,在方法之前,截取请求可以做一定的事情,方式执行之后是所有将html发送回到客户端的时候才执行   
  107.     //所以在这个方法执行后,关闭session是最合适的,这样保证每次请求完成之后session被关闭   
  108.     }finally{//保证肯定能被关闭,和将TreadLocal清空   
  109.      Session session=threadLocal.get();   
  110.     if(session!=null){   
  111.      if(session.isOpen()){   
  112.        session.close();   
  113.        threadLocal.remove();   
  114.       }   
  115.      }   
  116.     }   
  117. }   
  118. public void init(FilterConfig arg0) throws ServletException {//tomcat启动会实例化过滤器,并执行该方法,并且整个生命周期只执行一次   
  119.   //由于sessionFactory是重量级的,所以只让它被创建一次,写在过滤器的init方法中式再好不过的了  
  120.   try {   
  121.     Configuration cfg=new Configuration().configure();   
  122.     factory=cfg.buildSessionFactory();   
  123.    } catch (Exception e) {   
  124.     e.printStackTrace();   
  125.    throw new ServletException(e);   
  126.    }   
  127. }   
  128. //对外提供获取session的方法,每个线程获取的session都和线程实现了绑定   
  129. public static Session getSession(){   
  130.    Session session=threadLocal.get();   
  131.   if(session==null){   
  132.     session=factory.openSession();   
  133.     threadLocal.set(session);   
  134.    }   
  135.   return session;   
  136. }   
  137. }  
 

posted @ 2010-09-11 17:00  kelin1314  阅读(1674)  评论(0编辑  收藏  举报