Hiernate 笔记

目录

1.框架好处: 1
2.三大框架 1
3.Hibernate 简介: 1
4.Hibernate详细: 1
5.使用Hibernate流程,五步 1
6. 使用Hibernate操作数据库七步: 1
7. Hibernate里的[异常]认识 2
8. javabean映射文件里配置时的 主键生成策略 3
9. Hibernate关于对象的三种状态(javabean实例对象的三种状态) 3
10. 增、删、改操作 3
11. 通过id查询 (get与load方法的区别) 3
12. 多表关联的分类 4
13. 实现多表关联步骤 4
14. 配置两张表之间的关联关系 4
15. 级联(cascade)操作的实现 5
16. 映射文件里的关联关系的一些属性inverse、cascade、lazy、fetch、batch-size、property-ref… 5
17. Hibernate里的三种查询(HQL、SQL、条件查询) 6
1. HQL(Hibernate Query Language) :可实现分页 6
3. SQL查询(Structs Query Language):查的是表 7
3.条件查询(criteria:标准,规范) 8
4. 条件查询——示例查询:QBE(Query By Example) 9
5. 条件查询——统计、分组 9
18.命名SQL调用存储过程(用得少) 10
19.Hibernate里的缓存 11
1. 缓存有三种: 11
2. 缓存的范围【递增】 11
3. 一级缓存的体现 11
4 二级缓存 11
5 . 使用查询缓存的步骤 12
20. 逆向工程,参照Hibernate逆向工程文档 12
21. Hibernate+servlet实现Web工程访问操作 12
22.注解:详解参考Hibernate注解 12

1.框架好处:

安全、稳定、写业务逻辑代码容易、提高了开发效率

2.三大框架

a) Hibernate:针对数据库
b) Structs:针对servlet
c) Spring:它是一个容器,管理框架

3.Hibernate 简介:

作者:Gavin King 2003年9月加入JBoss进行全职开发
定义: 对象(类的实例)关系映射框架(Object Relation Mapping),也叫ORM框架。Hibernate就是一种流行的 ORM框架。
jdbc开发效率低,代码冗余,重复工作多;Hibernate解决了该缺陷。
它可对jdbc进行轻量级封装,将javaBean对象和数据库的表建立对应关系

4.Hibernate详细:

1) 将数据库连接的信息,放到它自己的配置文件里去
2) 它有一个或多个映射文件,就是为了将javabean与数据库的表对应起来(表中列与javabean里的属性一一对应)
3) Hibernate所在dao层,也称持久层,可将数据保存到数据库中(硬盘中)
4) 使用Hibernate的基本流程是:配置Configuration对象、产生SessionFactory、创建session对象,启动事务,完成CRUD操作,提交事务,关闭session。
5) 使用Hibernate时,先要配置hibernate.cfg.xml文件,其中配置数据库连接信息和方言等,还要为每个实体配置相应的hbm.xml文件,hibernate.cfg.xml文件中需要登记每个hbm.xml文件。
6) 在应用Hibernate时,重点要了解Session的缓存原理,级联,延迟加载和hql查询。

5.使用Hibernate流程,五步

a) 创建一个Web工程,将jar包放到工程里去:WebRoot的WEB_INF的lib里
b) 配置总配置文件 :hibernate.cfg.xml文件,一般放在src目录下。配置相关数据库连接信息。cfg: configuration 配置
c) 写JavaBean,再写针对javabean与表的映射文件,命名:对象名.hbm.xml。一般放在与javabean同级的目录里。注:在映射文件里配置表的字段时,配置顺序必须与表的字段的顺序一致。hbm: hibernate mapping 映射

<class name="com.model.Employee" table="employee">
    <!-- 1.配置主键  <id name="id" 中name值对应的是javaBean的属性-->
    <id name="id" type="java.lang.Integer">
        <!-- column标签里配置的是对应表里的id列 -->
        <column name="id" />   
        <!— 主键生成策略之一:increment :查到主键的最大值,然后自增1 -->              
        <generator class="increment"/>      
    </id>
    <!-- 2.配主键以外的字段-->
    <!-- 这里是javabean的属性:name值与属性对应 -->
    <property name="name" type="java.lang.String" >
        <!-- 这里是表里的字段:name值与字段对应 -->
        <column name="name" length="20"  />
    </property>
<!-- 有多个字段时,配置的property顺序得与表中字段一致 -->
</class>

d) 将javabean对应的映射文件配置到hibernate.cfg.xml总配置文件里去:包名+文件名(带.hbm.xml后缀),多个包之间用/隔开。即在总配置文件最后加下面一行代码:

e) 通过hibernate的相关类(当前是Test类)使用javabean,最终操作数据库。

6. 使用Hibernate操作数据库七步:

1. 读取并解析配置文件
Configuration conf = new Configuration().configure();
2. 读取映射信息,创建SessionFactory(session工厂里可建多个同样session)
SessionFactory sessionFactory = conf.buildSessionFactory();
3. 打开Session
Session session = sessionFactory.openSession();
4. 打开一个事务Transaction
Transaction tx = session.beginTransaction();
5. 在事务里面对数据库进行增删改查
Student stu=new Student();
stu.setSname(“李小龙”);
stu.setSid(8);
session.save(stu); //增
6. 提交或回滚事务
tx.commit();
注:Hibernate是在提交事务时将数据持久化的,不提交的话,都不走Hibernate里封装的sql语句,所以不会持久化。有了Spring以后,就用新的事务了,就不用Transaction
tx.rollback;放在catch里,如果出现问题就回滚撤销之前的操作。
7. 关闭Session(释放资源)
session.close(); //关闭session
sessionFactory.close();//关闭session工厂

7. Hibernate里的 [异常 ] 认识

  1. session的空针针问题:没有打开服务:services.msc
  2. 在调用hibernate的save()方法时,主键没插入值
    org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.zrgk.model.Student
    新单词:Identifier 鉴定人 ,说明主键id有问题
  3. 该异常是因为jdk版本有问题java.lang.UnsupportedClassVersionError: com/test/Test : Unsupported major.minor version 51.0
  4. 主键是null值,需要手动给主键赋值
    org.hibernate.TransientObjectException: The given object has a null identifier: com.zrgk.model.Student
    新单词:manually assigned 手动指定
  5. org.hibernate.HibernateException: ‘hibernate.dialect’ must be set when no Connection avalable
    少写了个configure()也会导致上述错误,数据库连接不正常好像也会出现此异常6。dialect是方言的意思,方言指定的是连的那个数据库。
  6. 下面异常主要是与数据库没有连接上
    Exception in thread “main” org.hibernate.exception.GenericJDBCException: Cannot open connection

8. javabean映射文件里配置时的 主键生成策略

1) assigned : 指定的(手动插入主键)
2) increment : 找到主键的最大值后增1
3) identity : 一致,由数据库给值,前提是主键设成自增(orac le里主键不能设为自增,最多序列化)。一般用在mysql数据库中
4) native: 根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式,灵活性很强。如果能支持identity则使用identity,如果支持sequence则使用sequence。
5) sequence : 序列化,前提是要在Oracle里创建序列,与其他生成策略不同的是,还需多配置一个序列名

<generator class="sequence">
<param name="sequence">seq_student_id</param>
</generator>

上面的seq_student_id是在Oracle里创建的序列的名字

9. Hibernate关于对象的三种状态(javabean实例对象的三种状态)

  1. 瞬时状态(transicent:’trænʃns /’trænzɪəns):刚用new创建时的状态,这时数据没有持久化(未入库),并且此时对象并没有放到session缓存里去
  2. 持久状态(persistent):已经被持久化,且加入到了session缓存里【提交事务后】
  3. 游离状态(detached:de’tached):已经被持久化(在内存中),但不在session缓存中【关闭session后】

10. 增、删、改操作

1. 添加 数据到数据库

用session调用 save()方法 或 saveOrUpdate()方法
saveOrUpdate()方法分情况
1) 主键生成策略是assigned
当表中已有插入主键值时,则先查询再修改
当表中没有插入主键值时,则先查询再插入
2) 主键生成策略是sequence
当表中已有插入主键值时,则执行修改
当表中没有插入主键值时,则执行插入

2. 删除

1) 若不指定主键,不报错,但什么也没删除
2) 如果 只指定主键,而其他字段都不指定,当映射文件里配置某字段如name时,后面加了not-null=”true”属性时,则会报错。

<property name="name" type="java.lang.String" not-null="true" >
            <column name="name" length="20"  />
</property>

3) 若不指定主键,但指定了另外一个字段,也删不了,是因为删除只能通过主键删除

3. 改:用session调用update()方法,,

11. 通过id查询 (get与load方法的区别),只能是Id

//使用session调用get()方法
Employee employee=(Employee) session.get(Employee.class,1);//sesssion得回的值是Object类型,需要强转,1表示id
//get里第一个参数是Class类型的,所以需要转。Class表示类的类,数据库的反射里有讲到
System.out.println(employee.getName()+"||"+employee.getSalary());
//使用session调用load()方法,load的延迟是针对本表
Employee empl=(Employee) session.load(Employee.class, 3);
System.out.println(empl.getName()+"--"+empl.getSalary());

两方法的区别:【面试题】
使用get时,没查回数据时返回null,而使用load没有查回数据报org.hibernate.ObjectNotFoundException异常。
get方法比较谨慎,它先从数据库中查询有没有该数据,有再从缓冲查询,没有则不查找,所以不会报错。
load方法认为该数据一定存在数据库中,所以可以放心使用代理来延迟加载(即在用到对象的属性数据时才进缓存里查询,所以说,load抛出的异常是在使用该对象的数据时才抛出的),当从load认为数据库有数据而直接从缓存里查时,由于实际数据库中没有该数据,最后会导致异常。
load方法的延迟是只针对本表的,至于另一张表是否延迟,取决于配置本表与另一表的关联关系时的lazy属性

12. 多表关联的分类

多表关联好处:可以操作一张表时可对其他相关进行相关操作
1. 按种类分:
1) 一对多、多对一
2) 多对多(有中间表)
3) 一对一(用得少,因为这种情况可以直接将数据放进一张表)
2. 按方向分:
1) 单向关联
2) 双向关联

13. 实现多表关联步骤

  1. 把相关的多张表在数据库中建完整
  2. 写相关表的javabean以及对应的映射文件(外键不能配进property属性里)
  3. 配置多表之间的关联关系(在映射文件里配置)
    1) 在javabean里写存另一表对象信息的属性,若要存多个时用Set集合存放
    2) 在操作表的javabean对应的映射文件里配置关联关系,双向时,都要配:
<set name="employees" ><!-- employees对应的是部门的javabean里的存员工信息的属性 -->
            <key column="deptnum" ></key><!-- deptnum是员工表的部门外键 -->
            <one-to-many class="com.model.Employee"/><!-- 获得员工表路径 -->
</set>

4.把相关的映射文件加入到Hibernate的总配置文件里去

14. 配置两张表之间的关联关系

  1. 配置一对多的关联关系[不管一对多,还是多对一,都需要配两表之间设定的那个外键]
<!-- 配置部门与员工的一对多的关联关系 -->
<set name="employees" > <!-- name值employees是部门javabean存员工信息的属性 -->
    <key column="deptnum" ></key>   <!-- deptnum是员工表的部门外键 -->
    <one-to-many class="com.model.Employee"/>   <!-- 获得员工javabean路径 -->
</set>
  1. 配置多对一的关联关系[不管一对多,还是多对一,都需要配两表之间设定的那个外键]
<!-- 配置员工与部门 多对一 的关联关系 -->
<many-to-one name="dep" column="deptnum" class="com.model.Dept" cascade="all"></many-to-one>
 <!-- dep是员工javabean里的存部门信息的属性,deptnum是员工表的部门外键,class里值是部门javabean的路径  cascade是级联操作-->

因为多对一时,外键是主表的属性,所以不需要 key 标签配外键,直接一行搞定

  1. 配置多对多的关联关系
<!-- 配置员工与项目的 多对多 的关联关系 -->
<set name="projects" table="ep" cascade="all"><!-- projects是员工表存项目信息的属性,ep是中间表,cascade是级联操作 -->
    <key column="eid"></key><!-- 中间表 对应的员工外键 -->
    <many-to-many column="pid" class="com.model.Project" ></many-to-many>
<!--pid是中间表 对应的项目外键 -->
</set>   
  1. 配置 一对一 的关联关系
<!-- 配置员工表与妻子表 一对一 的关联关系 -->
 <one-to-one name="wife" class="com.model.Wife" property-ref="employee"></one-to-one>
<!-- wife是员工表存妻子信息的属性, class是妻子javabean的路径,property-ref属性表示参照的是妻子表的employe属性 -->

<!-- 配置妻子表与员工表的一对一关联关系,也可以用many-to-one来实现 ,它的性能要优于one-to-one-->
  <many-to-one name="employee" column="empId" class="com.model.Employee" cascade="all" unique="true"></many-to-one>
  <!-- employee是妻子表存员工信息的属性, empId是妻子表的员工外键,class值是员工类的路径               unique="true",unique=“mpId”表示唯一   -->

注:在一对一的关联关系里,则不需要使关联的主键生成策略设成:assigned,但在测试类里面,必须在两个javabean里声明存对方实例化对象的属性,这样才能使外键值自动插入

15. 级联(cascade)操作的实现

配了它,说明能对对象进行级联操作:比如插入时,能同时插入相关联的表,已有则更新;它有4个属性:
1. save-update : 对新增或修改进行级联
2. delete : 对删除操作进行级联
3. all : 对所有操作(增删改)进行级联
4. none : 对所有操作都不级联
将cascade配置在主表(测试时,调用像save方法的操作时,括号里传的对象所对应的表就是主表)对应的映射文件里,如下面配置员工与部门的关联关系(多对一):

<many-to-one name="dep" column="deptnum" class="com.model.Dept" cascade="all"></many-to-one>
<!-- dep是员工javabean里的存部门的属性,deptnum是员工表存的部门主键id字段,class里值是部门javabean的路径 , cascade是级联操作-->

要实现级联操作,还需将主表a级联的表b对应的javabean对应的映射文件里的主键生成策略设置为:assigned。
之所以要设成assigned,是因为如果是像increment这种生成策略,如果执行的级联操作里的主键在b表中存在,则会执行更新操作;但是,如果级联操作里的主键值是b表中没有的,则不会执行插入操作了。

<id name="did" type="java.lang.Integer">
     <column name="did" />
    <generator class="assigned"/>               
</id>

注:在一对一的关联关系里,则不需要使关联的主键生成策略设成:assigned, 在测试类里面,必须在两个javabean里声明存对方实例化对象的属性,这样才能使外键值自动插入

16. 映射文件里的关联关系的一些属性inverse、cascade、lazy、fetch、batch-size、property-ref…

  1. 控制反转(invserse):该属性指定了关联的方向性问题,谁有主动权,那么其他数据就依据它而变动。如,学生表为主动表且有班级外键cid,如果我们操作学生表插入数据时,新增学生,新增班级,但就是不写学生表外键,学生和班级插入成功后,却会发现班级外键没有插入值(照理说,新班级与新学生同时插入的,那么新增学生的外键应该有值)。这是是因为学生表和班级表配置关联关系时,没有设置控制反转属性,就默认为inverse=”false”,即默认都是主动表,这就导致了上面插入时,外键不跟着插入,两张表都有主动权
  2. 级联操作(cascade):使得操作一张表时,另一张表也跟着操作。如,在向学生表插入数据时,也同时向班级表里插入数据,要执行成功,则主表(这儿是学生表)里配置学生与班级的关联关系时必须有cascade属性,且还有个前提就是,级联表(班级表)的主键生成策略必须是assigned.
  3. 延迟加载(lazy): 需要用到某数据时,才从缓存里去取,取不到就报错。
    a) lazy=”true” : 延迟加载,默认为true,当session关闭后(缓冲区不存在了)就取不到值了
    b) lazy=”false” : 不延迟加载,直接从数据库里取
    c) lazy=“ture” 这个延迟加载是针对关联表的,主表是否延迟加载,取决于用的是load方法还是get方法;load方法的延迟针对主表,不能影响到关联表。
  4. fetch: 译为:拿来。都是左外连接。默认都为join,即一个sql语句
    a) fetch=”join” :查询回来时只有一个sql语句
    b) fetch=”select ” :有多个sql语句
    c) fetch=”subselect” : 有多个sql语句
  5. 批处理(batch-size):规定一次处理的条数据,默认1条。这样可以提高效率。合理值为:2-10,batch-size=”2”
    要区分开的是,总配置文件里的批处理,指的是整个容器里的批处理,即整个容器一次性能处理多少条数据
  6. 属性参考(property-ref):用于多对一和一对一的关联关系里,不能用于多对多。表示引用关联表的javabean属性
    如在学生表映射文件里有学生与学生证的关系配置:
<one-to-one name="card" class="com.zrgk.model.Card" property-ref="student"></one-to-one>

card是学生表里存学生证信息的属性,class写学生证javabean的路径,student表示学生证类里存学生信息的属性
有了property-ref就不需要外键了

17. Hibernate里的三种查询(HQL、SQL、条件查询)

1. HQL(Hibernate Query Language) :可实现分页

Sql查询与Hql查询大同小异,主要的区别是Sql查的是表,而Hql查的是表对应的javabean类,都可实现分页
1. 它是根据javabean来查询数据的,关键字也不区分大小写,但是类名及属性名区分大小写
2. 使用步骤:
a) 得到session:与之前一样
b) 写HQL语句: String hql=” from com.zrgk.model.Student “;
c) 创建Query对象:Query query=session.createQuery(hql);
d) 执行查询: List list=query.list();
e) 处理查询结果:用迭代器遍历 ( 没有泛型时,不知道类型,只能用迭代器),泛了型也可用迭代器
3) 写HQL语句时,用到的那个类最好写全路径:
HQL语句可简化:String hql=” from com.zrgk.model.Student “;
不写全路径就简化为:String hql=” from Student “;
/注意了:当用的是select的sql语句时,不能有号,在遍历时,且只能用Object[]强转,
* 如果是直接用的from的查询sql语句,则在遍历时,只能用Employee强转
* */
1) 有占位符 ? 时
String hql=”select sid,sname from com.zrgk.model.Student where sname=? “;
Query query=session.createQuery(hql);
query.setString(0, “韦小宝”);//绑定问号,占位符下标是从0开始的
//执行查询
List list=query.list();//后面操作一样

2 hibernate里的 分页

query.setFirstResult(0);//从第几条开始取: 0代表是第一条数据
query.setMaxResults(5);//取5条
数据多时,则从第几条开始取是动态的,需要当前页这个变量得出:(currenPage-1)*5

3. SQL查询(Structs Query Language):查的是表

Sql查询与Hql查询大同小异,主要的区别是Sql查的是表,而Hql查的是表对应的javabean类,都可实现分页

public static void main(String[] args) {
    Session session = null;
    Transaction tx = null;
    try {
        //1.通过Hibernateo的静态方法得到session
        session = HibernateUtil.getSession();
        tx = session.beginTransaction();
        /* //2.写sql语句
         * String sql="select * from student";
         * 
         * //3.创建 Query对象 query
         * query=session.createSQLQuery(sql).addEntity(Student.class);
         * addEntity()方法将数据封装进Student的实体对象里 Entity:实体,实质

        查的多表有多个表的字段时,就不能这样用了哟。要么重新建个JavaBean或者在List里存Map
         * //4.执行查询 
         * List list=query.list();//由于前面的封闭,所以list存的是对象
         *  
         * //5.处理查询结果       
         * Iterator it=list.iterator();
         *  while(it.hasNext()){
         *    Student s=(Student)it.next(); 
         *    System.out.println("学生姓名:"+s.getSname()); 
         *  }
         */

        /**hibernate里多表连查时的处理*/
        String sql = "select s.sname,c.cname from student s,cla c where s.cid=c.cid";

        // 创建 Query对象   
        Query query = session.createSQLQuery(sql);
        //由于是多表联查,所以查回的数据不能封装进一个javabean对象里,放进数组里
//可以重建一个JavaBean,或是用List里存Map里的方法。

        List list = query.list();//存的是数组

        // 处理查询结果:由于list没有泛型,所有用迭代器遍历
        Iterator it = list.iterator();
        while (it.hasNext()) {
            //因为返回的两个表的两个字段,所以用object[]数组来接收再处理
            Object[] obj=(Object[])it.next();
            System.out.println(obj[0]);
            System.out.println(obj[1]);
        }

        // 6.提交事务
        tx.commit();// 提交的时候才是真正把数据持久化到数据库中 对象处于持久状态
        System.out.println("执行成功");
    } catch (HibernateException e) {
        tx.rollback();
        e.printStackTrace();
    } finally {
        // 7.关闭session
        session.close(); // 对象处于游离状态
    }
}

3.条件查询(criteria:标准,规范)

1)都在注释里:也可实现分页

public static void main(String[] args) {
    Session session=null;
    Transaction tx=null;
    try{
        session=HibernateUtil.getSession(); //得到session
        tx=session.beginTransaction();      //打开事务

        //1.创建条件查询对象
        Criteria cri=session.createCriteria(Employee.class);
        //2.Criteria里的add方法可以追加查询条件。Restrictions:限制,Criteria:标准
        cri.add(Restrictions.le("salary",3457.0));//less:小于3457.0【salary既可是属性名,也可是表的字段名】
        //3.Criteria里的addOrder方法用来排序:默认升序asc
        cri.addOrder(Order.desc("salary")); //添加排序条件,先按工资降序排
        cri.addOrder(Order.desc("id"));     //添加排序备件,再按id降序排
        //4.查询所有,组装成的list集合
        List list=cri.list();               
        //5.前面list没有泛型,所以必须用迭代器处理查回结果,泛型后也可以用
        Iterator em=list.iterator();
        while(em.hasNext()){
            Employee employee=(Employee) em.next();
            System.out.println(employee.getName()+"-"+employee.getSalary());
        }
        tx.commit();
    }catch (Exception e) {
        tx.rollback();
        e.printStackTrace();
    }finally{
        session.close();
    }
}

2)Restrictions的几个方法。还有in,表查询范围,里面传的是集合或数组

//用Criteria里的add方法可以追加查询条件。Restrictions:限制
    cri.add(Restrictions.ge("money", 16000.00)); //大于等于:ge
    cri.add(Restrictions.eq("sname","刘德华"));   //等于:eq
    cri.add(Restrictions.gt("money", 16000.00)); //大于:gt
    cri.add(Restrictions.le("money", 16000.00)); //小于:le    less thans
    cri.add(Restrictions.like("sname", "%韦%")); //模糊查询,与之前一样用%
    cri.add(Restrictions.between("money", 10000.00,17000.00));//两者之间

4. 条件查询——示例查询:QBE(Query By Example)

public static void main(String[] args) {
    Session session=null;
    Transaction tx=null;
    try{
        session=HibernateUtil.getSession(); //得到session
        tx=session.beginTransaction();      //得到事务

        //创建条件查询对象
        Criteria cri=session.createCriteria(Employee.class);

        Employee em=new Employee();
        em.setName("张三丰");//有这个则是 "按名字查询",没有的话则走查询所有
        /*需要【注意】的是,在示例查询里,需要将所有javabean的属性的类型写成封装类,如,将int写成Integer类。如果就写成int型,那么示例查询将认为给javabean属性赋了默认值0,它会按0去查询,而实际上是没有0的,这样就会查不到数据。char对应的封类是Character,double对应的是Double*/
        cri.add(Example.create(em)); //执行示例查询
        //分页
        cri.setFirstResults(0); 
        cri.setMaxResults(6);
        //按id排序
        cri.addOrder(Order.asc("id"));

        List list=cri.list();//数据放进list里

        //前面list没有泛型,所以必须用迭代器,泛型后也可以迭代器
        Iterator<Employee> e=list.iterator();
        while(e.hasNext()){
            Employee employee=e.next();
            System.out.println(employee.getName()+"-"+employee.getSalary());
        }

        tx.commit();
    }catch (Exception e) {
        tx.rollback();
        e.printStackTrace();
    }finally{
        session.close();
    }
}

5. 条件查询——统计、分组:查回的是一行一列

分组要注意如:select name,sex from employee group by name ,sex ,查询的字段与分组的字段必须一致,顺序可以颠倒。

/**统计,也属性于条件查询。Projections:映射*/
    session=HibernateUtil.getSession(); //得到session
    tx=session.beginTransaction();      //打开事务

    //创建条件查询对象
    Criteria cri=session.createCriteria(Employee.class);
    /**属性名不能写外键,且区分大小写.Projections:映射*/
    //cri.setProjection(Projections.rowCount());    //调用count方法查数据条数
    //cri.setProjection(Projections.countDistinct("sex"));//去重条数,空也算,所以返回3条
    //cri.setProjection(Projections.rowCount());    //统计Student类里的总条数
    //cri.setProjection(Projections.avg("money"));  //求平均值
    //cri.setProjection(Projections.max("salary")); //求最大值
    //cri.setProjection(Projections.min("sid"));    //求最小值
    //cri.setProjection(Projections.count("sex"));  //根据一个属性来求去掉null后的总条数
    //cri.setProjection(Projections.sum("money"));  //求和
    /**分组*/
    cri.setProjection(Projections.groupProperty("sex"));

    Employee em=new Employee();
    //em.setName("张三丰");//有这个则是 "按名字查询",没有的话则走查询所有

    cri.add(Example.create(em));//执行示例查询

    List list=cri.list();//数据放进list里

    //前面list没有泛型,所以必须用迭代器,泛型后也可以迭代器
    Iterator<Employee> e=list.iterator();
    /**聚合函数返顺的值只有一行一列,所以直接打印*/
    while(e.hasNext()){             
        System.out.println(e.next());
    }

    tx.commit();

18.命名SQL调用存储过程(用得少)

它是在映射文件里的class标签外面写的命名sql,然后在测试类里调用命名sql的形式。

1. 在配置文件里的命名sql

<sql-query name="insertStudent">
      insert into student(id,sname,sex) values(?,?,?) 这儿写sql语句,不能写分号 
      <!-- 因为命名sql写在class标签外面,所以与class里配置的主键生成策略无关,
所以,这里必须手动插入主键id -->
</sql-query>

insertStudent是后面调用时的关键字
如果sql语句写在了数据库的存储过程里,则只需在里面调用存储过程即可,如下:

<!--调用插入记录的存储过程-->
    <sql-query name="loginInsert">
{call login_insert(?,?,?)} 
<!-- 调用数据库里插入的存储过程:login_insert。这在讲Oracle调用存储过程时的代码里有讲 -->
    </sql-query>

2. 在测试类里的代码

{
session = HibernateUtil.getSession();// 得到session
    tx = session.beginTransaction();        //打开事务

//通过insertStudent调用配置文件里的命名sql 
    Query query=session.getNamedQuery("loginInsert ");  query.setInteger(0, 77);        //给第一个?赋值
    query.setString(1, "萧敬腾");  //给第二个?赋值
    query.setCharacter(2, '1'); //给第三个?赋值
    query.executeUpdate();      //执行sql语句

    tx.commit();// 提交事务
}

19.Hibernate里的缓存

cache [kæʃ]
n. 贮藏所; 贮藏物; 快速缓冲贮存区

1. 缓存有三种:

  1. 一级缓存: session缓存,它是Hibernate必须带的
  2. 二级缓存: sessionFactory的缓冲,它是可配置的,空间比session大,sessionFactory是管理session的工厂
  3. 查询缓存: 与二级存类似,它依托二级缓存

2. 缓存的范围【递增】

  1. 事务 范围内的缓存,即session缓存
  2. 进程 范围内的缓存
  3. 集群 范围内的缓存,像多个TomCat组成的群就是集群

3. 一级缓存的体现

当两次取学生信息时,第一次执行sql后,从数据库里取回数据后存进session的缓存里(当然也打印显示),当后面还有查询语句,用的同一个session时,则不会再走sql语句了,它是直接从session缓存里取的值

4 二级缓存

二级缓存能够被所有session所共有,它有以下几种缓存插件:
a.第一种缓存插件:EHCache 来源于:org.hibernate.cache.EhCacheProvider 支持查询缓存 | 进程范围内的缓存
b.第二种缓存插件:OSCache 来源于: org.hibernate.cache.OSCacheProvider 支持查询缓存 | 进程范围内的缓存
c.第三种缓存插件:SwarmCache 来源于:org.hibernate.cache.SwarmCacheProvider 不支持查询缓存 | 集群范围内的缓存
d.第四种缓存插件:JBossCache 来源于:org.hibernate.cache.TreeCacheProvider 支持查询缓存 | 集群范围内的缓存

使用二级缓存步骤:

1. 选择合适的缓存插件,配置它自带的配置文件信息
1) 在需要二级缓存的javabean类的映射文件里配置如下代 码:

<!-- 读/写缓存:可以只配read,即只能读 -->
<cache usage="read-write"/><!--标明可以对Student进行读写 -->

2) 在总配置文件hibernate.cfg.xml里开启二级缓存,并配置来源类

<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">
true
</property>     
<!—配置来源类 -->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>

2. 选择需要使用二级缓存的持久化类(javabean类),并设置它的二级缓存的一些信息

<!-- 配置 student使用二级缓存,配在EHCache插件(在src下的ehcache.xml文件)里 -->
 <cache name="com.pb.hibernate.po.Student"<!—Student的javabean路径 -->
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
/>

使用二级缓存的情景:

  1. 很少被修改的数据,像常量
  2. 不是很重要的数据,允许偶出现并发问题的数据
    并发问题:如同一张票被多人抢到

5 . 使用查询缓存的步骤

查询缓存依托二级缓存,所以先得配好二级缓存。由于查询缓存依托二级缓存,所以前面关掉session1后,查同样的数据时,不会走sql,用session2时,能直接从二级缓存里取到数据
1) 在总配置文件里开启查询缓存 hibernate.cache.use_query_cache
true
2) 在程序(测试调用类)中手动启动查询缓存 query.setCacheable(true);
//手动开启查询缓存:setCacheable(true),然后把查询到的结果集放到查询缓存 里去
List stus= query.setCacheable(true).list();

20. 逆向工程,参照Hibernate逆向工程文档

逆向工程,是根据数据库的表,自动生成,总配置文件,javabean类,以及映射文件,生成实体类和文件可能会有些问题,自己修改下即可。以后尽量自己配置,这样生的总会有这样那样的问题,知道怎么用就行。具体见详解链接

21. Hibernate+servlet实现Web工程访问操作

和以前一样建servlet和页面及其他,只是多了个Hibernate。多个总配置文件,以及javabean的映射文件,还有就是在实现类里,用的是Hibernate的操作调用数据库(session….Query…..等)。

22.注解:详解参考Hibernate注解

1. 注解:用于减少Hibernate的映射文件,把映射文件合并到javabean里去[实现javabean与数据库表的关联]

优点:减少配置
缺点:分层相当而言不是特别明显,代码可能会显得混乱。
a) 如果持久化类的属性没有规定注解,则只要名字一样,则会自动映射过去。持久化类javabean类名与表名一致,这样就自动映射。
b) 如果javabean类名与表名不一样,则用:@Table(name=”user”)映射
如果属性列名与表列名不一致,则用:@Column(name=”password”)映射

@Entity
@Table(name="user")//javabean类名与表名不一致的处理
public class User {
            @Id
            @Column(name="id")
            @GeneratedValue(strategy=GenerationType.AUTO) //主键生成策略:自动增长
            @SequenceGenerator(name="sequence的名字")//引用sequence
            private int uid;//主键    自增  

            @Column(name="username",length=100)
            private String username;//用户名

            @Column(name="password",length=100)
            private String password;//密码

            @Column(name="group_id")
            private String groupId;

            public int getUid() {
                return uid;
            }

            public void setUid(int uid) {
                this.uid = uid;
}

c) 当javabean类里的某个属性a在表里不存在对应的字段时,则必须在get方法上加忽略注解:@Transient
这是因为,如果不忽略,则在查询所有时,系统会按属性a去数据库查询,由于数据库没有该字段,所以会报错-Unknown cloumn

2. 使用格式:@+注解关键词

3. 在hibernate里使用注解的步骤:

1) 添加hibernate-annotations.jar包
2) 使用注解配置持久化类及对象的属性信息及关联关系
3) 使用AannoationiConfiguration建立工厂
4) 在hibernate.cfg.xml配置文件里配持久化类

4. 持久化类:跟Hibernate关联上的javabean类

5. Hibernate相关注解类介绍:具体点链接

1) @Entity 相当于将一个类声明为一个实体bean(即生成一个持久化类 POJO类) entity:实体
2) @Id 声明了该实体bean的标识属性(相当于数据库表的主键处理)
3) @GeneratedValue 定义主键的生成策略
4) @Table 为实体bean映射表
5) @UniqueConstraint 定义表中唯一约束
6) @Lob 表示属性将持久化为Blob或者Clob类型
7) @Column 将属性映射到表中的列
8) @Transient 将忽略这个属性 不用持久化到数据库中去
9) @NamedQuery 配置命名查询
10) @OneToOne 建立实体bean之间的一对一的关联关系
11) @OneToMany 配置一对多的关系
12) @ManyToMany 配置多对多的关系
13) @ManyToOne 配置多对一的关系

6. 使用注解的测试类里得到session时,需要用AnnotationConfiguration工厂类

//使用注解工厂的类
AnnotationConfiguration annotationConfiguration=
new AnnotationConfiguration();
SessionFactory sessionFactory=
annotationConfiguration.configure().buildSessionFactory();

Session session=sessionFactory.openSession();//得到session

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值