闲来无事,复习复习以前的东西---hibernate查询细节资料

来源:互联网 发布:怎样网络销售 编辑:程序博客网 时间:2024/06/08 04:01

加载hibernate配置文件  Configuration cfg = new Configuration().configure("hibernate.cfg.xml");  --也可以用无参的configure()方法,不过此时hibernate配置文件必须放在src下。

批量更新 缓存同步 hibernate使用效率很低

一、代理:
  JDK动态代理:只能对实现了接口的类进行代理。
  cglib:对类进行代理。
  
二、lazy可用的地方:
 1、class标签上(影响普通属性)
 2、property标签上(影响当前属性)
 3、集合上(影响集合)
 4、<one-to-one>、<many-to-one>等标签上(影响关联对象)
 
 lazy概念:只有真正使用该对象时,才会创建该对象,对于Hibernate而言,真正使用的时候才会发出sql
    当我们查找集合时(默认为延迟加载)不会发sql,只有使用集合中的对象或集合中的对象的属性时才发sql
    
三、悲观锁和乐观锁:
  悲观锁的实现:通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改
 
  使用悲观锁时:load的lazy就会失效,使用方法为在代码中 load(EntryName.class,id,LockMode.UPGRADE)
 
  使用乐观所时:要在对象bean中加一个int类型的versions属性(自定义属性),并且要在影射文件中开启对乐观锁的支持,即在<class>标签中加入<class optimistic-lock="version">一告诉Hibernate该对象要使用乐观锁,并且必须要在<id>标签后使用<version>标签配置版本号
      即:<id name="id">
        <generator class="native" />
       </id>
       <version name="versions" />
      
      大多数基于数据版本记录机制(version)实现,一般是在数据库表中加入一个version字段
      读取数据时将版本一同读出,之后更新数据时版本号加一,如果提交数据时版本号小于或等于数据表中的版本号,则认为数据是过期的,否则给予更新。
       
  数据库隔离级别中的“可重复读”就是使用了“悲观锁”。
 
四、HQL查询
 1、以对象为基础的查询语言,查询的是对象(类),不是某个表。
 2、在Hql中关键字不区分大小写,但是属性和类名区分大小写。
 3、查询语句:
  
  简单属性查询:
  
  List students = session.createQuery("select name from Student").list();  list是一个string类型的name属性集合
  
  List students = session.createQuery("select id,name from Student").list();  List是一个Object[]类型的对象数组集合
  
  List students = session.createQuery("select new Student(id,name) from Student").list();  List是一个Student类型的对象集合
  
  List students = session.createQuery("select s.id,s.name from Student as s").list();  List是一个Object[]类型的对象数组集合,使用别名(as可用可不用)
  
  实体对象查询:
  
  List students = session.createQuery("from Student as s").list();  List是一个Student类型的集合(as可用可不用)
  
  List students = session.createQuery("select s from Student as s").list(); List是一个Student类型的集合(如果用select查询实体时,一定要加别名)
  
  使用query中的list()接口时,发出一条语句,查出对象,返回一个List,list会向缓存中放入数据,而不利用缓存中的数据。
  使用query中的iterator()接口时,发出N+1条语句,第一条语句查出所有记录的id,后根据N个id查出N个对象,返回一个Iterator,iterator接口默认情况下会利用缓存数据,但如果缓存中不存在数据有可能出现N+1问题。
  
五、条件查询
 
  1、拼字符串查询
  List students = session.createQuery("select s.id,s.name from Student s where s.name like '%李%'").list();  别名可有可无
  
  2、使用占位符查询
  Query query = session.createQuery("select s.id,s.name from Student s where s.name like ?");
  query.setParameter(0,"%李%");  参数索引从0开始
  List students = query.list();
  
  或使用基于方法连的编程(也是使用了占位符查询)
  
  List students = session.createQuery("select s.id,s.name from Student s where s.name like ?")
        .setParameter(0,"%李%")
        .list();
        
  3、使用参数命名方式查询
  List studnets = session.createQuery("select s.id,s.name from Student s where s.name like :userName")
        .setParameter("userName","%李%")
        .list();
        
  List studnets = session.createQuery("select s.id,s.name from Student s where s.name like :userName and s.id=:userId")
        .setParameter("userName","%李%")
        .setParameter("userId",12)
        .list();
        
  List studnets = session.createQuery("select s.id,s.name from Student s where s.id in(?,?,?)")
        .setParameter(0,100)
        .setParameter(1,101)
        .setParameter(2,102)
        .list();
        
  List studnets = session.createQuery("select s.id,s.name from Student s where s.id in(:userIds)")
        .setParameterList("userIds",new Object[]{1,2,3,5})
        .list();
        
  List studnets = session.createQuery("select s.id,s.name from Student s where date_format(s.birthday,'%Y-%m')")  在hql中可以使用数据库的函数,如:date_format
        .setParameter(0,"2008-08")
        .list();
        
六、使用原生SQL查询
 
  List student = session.createSQLQuery("select * from t_student").list();  使用createSQLQuery直接查询表
  
七、外置命名查询(将HQL语句放在配置文件中,使得与代码的耦合度很低)

 在.xml影射文件中<class>标签以外使用<query>标签来写sql语句:(<query>可以写在任何一个映射文件中,只要name值不重复就可以了)
  <query name="searchStudents">        由于Hql语句中可能有"<"或">"符号与xml冲突,所以使用转移字符或将语句直接写入CDATA中
   <![CDATA[
    select s from Student s where s.id < ?
   ]]>
  </query>
  
 在程序中引入:
  List students = session.getNameQuery("searchStudents")  getNameQuery()从映射文件中得到查询串
    .setParameter(0,10)
    .list();
    
八、查询过滤器(在当前session中起作用,filter是hibernate的filter)

 在.xml影射文件中<class>标签以外加入以下配置内容
  <filter-def name="filtertest">
   < filter-param name="myId" type="integer" />
  </filter-def>
 
 并且在需要使用此条件的对象影射文件<class>标签中加入如下内容:
  <filter name="filtertest" condition="id &lt :myId" />
  
 所以在我们查询“用户”对象时,就会在hql语句后自动加上 id < ?
 
 如:(查询id小于10的用户)
  在代码中:
   session.enableFilter("filtertest")
     .setParamter("myId",10);
     
 hibernate生成的sql语句:select * from t_user where userId < ?
 
九、对象导航查询(使用.导航查询)

 List students = session.createQuery("select s.name from Student s where s.classes.name like '%李%'").list();
 
十、连接查询
 内连接
 外连接(左连接、右连接)
 
 List students = session.createQuery("select c.name,s.name from Student s inner join s.classes c").list();  //不用写on...条件了,因为条件在影射文件中已经有了,我们已经配置了对象之间的关系,inner可以省略。
 
 List students = session.createQuery("select c.name,s.name from Classes c left join c.students s").list();  //查出所有的班级,即以班级为准查询
 
 List students = session.createQuery("select c.name,s.name from Classes c right join c.students s").list();  //查出所有的学生,即以学生为准查询
 
十一、统计查询
 
 Long count (Long)session.createQuery("select count(*) from Student").uniqueResult(); //uniqueResult接口返回单一值
 
 List students = session.createQuery("select c.name,count(s) from Student s join s.classes c group by c.name order by c.id").list();  //以班级分组,统计每个班级内的人数
 
十二、DML风格的操作(尽量少用,因为和缓存不同步)

 session.createQuery("update Student s set s.name=? where s.id < ?")
   .setParameter(0,"李四")
   .setParameter(1,5)
   .executeUpdate();
   
十三、抓取(fetch)

 抓取:是抓取他的关联对象。
 
 连接抓取(Join fetching):Hibernate通过在select语句使用outer join(外连接)来获得对象的关联实例或者关联集合。
 查询抓取(Select fetching):另外发送一条select语句抓取当前的关联实体或集合。除非你显式的指定lazy="false"禁止延迟抓取,否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
 
 <many-to-one>中有一个fetch属性,默认为select
 
 fetch="select",另外发送一条select语句抓取与当前对象关联的实体或集合。
 fetch="join",hibernate会通过select语句使用外连接来加载其关联的实体或集合,此时lazy失效。
 
 集合上的抓取:(取值:select、join、subselect)
    fetch的默认值为select。
    
 子查询抓取(subselect fetching)另外发送一条selct语句抓取在前面查询到(或抓取到的)的所有实体对象的关联集合(实质上就是一个子查询)。除非你显式的指定lazy="false"禁止延迟抓取,否则只有当你真正访问关联关系的时候,才会执行第二条select语句,会影响hql语句。
 
 fetch="select":与上相同
 fetch="join":与上相同
 fetch="subselect":与fetch="select"结果相同。但是会影响hql,他形成的sql是一个子查询,比如
 
  List classesList = session.createQuery(select c from Classes c where c.id in(1,2,3)).list();
  
   行程的sql为:
  
  select u.userId,u.userName t_user as u where u.id in (select classId from t_classes where classId in(1,2,3));
  
<class>标签内有一个batch-size属性,表示一条sql查多少对象。也可以用在集合标签上<set>
 
 batch-size属性:可以批量加载实体类,以达到减少sql的目的
 
 
 hibernate.jdbc fetch size:每次取多少数据,需要JDBC和底层数据库的支持。不会一次性把全部数据读入内存,而是按照一定的数量来批量读取相应的数据。建议值50
 
 hibernate.jdbc batch size:批量更新,建议值30 
 
十四、hibernate缓存
 
 一级缓存很短和session的生命周期一致,一级缓存也叫 session 级的缓存或事务级缓存。
 
 一级缓存无法取消,但可以管理,如:
  session.clear()(清除缓存中的所有对象),session.evict(Object o)(清除缓存中的某个对象)。
  
 session 间不能共享一级缓存。
 
 session.flush(),flush()作用:执行sql语句,强制session将数据持久化。
 session.clear(),clear()作用:清理缓存中的数据。
 
 避免一次性大量的实体数据入库导致内存溢出:
  * 先 flush,再 clear
  
 二级缓存和一级缓存一样,只缓存对象,不缓存结果集对象。
 
 二级缓存可以被所有的 session 共享。
 
 
十五、二级缓存的配置和使用:

 1、导入EHchech 的 jar 包
 
 2、在hibernate发布包的 etc 目录下将 ehcache.xml 文件 拷贝到 src 下,classpath 能搜索到的地方。
 
 3、ehcache.xml 文件中的默认配置解释:
  <defaultCache
   maxElementsInMemory="10000"   //缓存中可以存放10000个对象。
   eternal="false"      //表示可以失效。
   timeToIdleSeconds="120"    //空闲时间,即:距第一次访问,间隔多长时间没有再访问就失效了。
   timeToLiveSeconds="120"    //别缓存的对象在内存中存活的时间,单位是s(秒)。
   overflowToDisk="true"    //当发生溢出时,是否保存到磁盘上,磁盘目录为:
   />
   
   <diskStore path="java.io.tempdir" />  //这个磁盘目录是一个操作我们开发的系统的临时目录,这个目录可以自定义。
 
 4、在hibernate.cfg.xml中配置缓存
 
  <property name="hibernate.cache.use_second_level_cache">true</property>  //开启二级缓存,其实默认就是开启的,这里我们显式的开启。
  
 5、指定缓存产品提供商
  
  <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
  
 6.1、指定那个对象使用二级缓存(第一种方式)
 
  在映像文件中的<id>标签前面使用<cache>标签
  
  <cache usage="read-only" />   //只读缓存(即:当数据库中的数据发生变化时,不会更新缓存中的东西) read-write:表示当数据库中的数据发生变化时,同时更新缓存中的东西(效率低,因为更新时要使用到锁)。
  
 6.2指定那个对象使用二级缓存(第二种方式)(推荐)
 
  在hibernate.cfg.xml中指定
  
  <class-cache class="com.lixinmin.test.User" usage="read-only" />
  
 查询的时候,先查看一级缓存中是否有信息,后查看二级缓存。
 
 
 使用二级缓存时在代码中使用一下方式(在查询之前设置session):      //此项可选可不选
  session.setCacheMode(CacheMode.GET);  //只从二级缓存中读数据,而不写入
       CacheMode.PUT  //只向二级缓存中写入数据,而不从二级缓存中读数据
       CacheMOde.NORMAL //从二级缓存中可读可写数据(默认值)
       
  
十六、查询缓存
 
 缓存普通属性结果集,和实体ID
 
 1、启用查询缓存
  
  在hibernate.cfg.xml中开启,如下:
  
  <property name="hibernate.cache.use_query_cache">true</property>  //默认是关闭的
  
 2、在配置文件中开启后还必须在程序中开启,如下:
  
  Query query = session.createQuery("select s.name from Student s");
  query.setCacheable(true);
  List names = query.list();
  
十七、hibernate数据更新

 托管状态的对象,只要我们发update它就又可以变成持久状态,是因为数据库中存在有和这个对象主键值相同的记录,因为主键所以才能联系起来。
 
 我们更新一条记录时建议先将其加载上来再更新,这样只有我们更新的的字段才会改变,没有更新的字段查出来什么值发update时还是把原值给保存回去,
如果我们自己构造一个托管状态的对象(即:new一个对象,再把对象的主键值改成和我们要修改的记录的主键值相同的值),此时改变的字段会保存到数据库中
没有改变的字段,因为我们构造的托管状态的对象的属性默认都是空,所以发update时那些没有改变的字段值都会变成null

十八、hibernate表结构修改

 若将hibernate.hbm2ddl.auto属性的值改为update,这时如果我们将映射文件中的某些属性的property的name值改变成另外一个名字,那么在数据库中就会
新增加一些和改后名字相同的字段,而之前的字段保留,但不再用了,插入数据时都将其值赋为null

原创粉丝点击