• 基础
    • 优点
      • 完全面向对象编程思想,无sql
      • 减少代码
      • 控制数据库访问,降低访问数据库的频率(第一次访问后,数据存储在内存的缓存中),提升效率
      • hibernate具有独立性(访问层随时可以更换)
    • 特性
      • 不写hbm.xml映射文件,而是基于注解的验证
      • 对象、集合、属性的延迟加载
        • dao层之外使用延迟对象时,由于连接已关闭, 会报Nosession异常
    • 目录
      • . # hibernate程序包
      • documentation # 文档
      • lib # 所有依赖包
      • project # 源码文件
    • 加载顺序
      • 后面的覆盖前面的
      • hibernate.properties中的配置被覆盖
        • 因为该文件中的配置在new Configuration() 的时候就加载,而之后的xml配置文件是调用configuration.addResource()的方法加载的,新加载的配置覆盖了原来的配置 hibernate3.6之后可以基于注解对javaBean的数据进行验证(jsr303标准)
    • 开发流程
      • 加载配置: jdbc参数,数据库方言,hbm映射
      • 创建SessionFactory # 内有连接池
      • 创建session
      • 事务处理
      • 关闭session
      • 关闭连接池
    • 对象状态
      • 𣊬时态 # 没有OID(持久化标识), 没有关联session
      • 持久态 # 有OID, 与session关联, 事务未提交
      • 脱管态 # 有OID, 没有关联session
    • 缓存机制
      • 一级缓存(session)
        • 事务级,事务结束缓存失效 # 请求同一对象,取得同一实例
        • 总是打开
      • 二级缓存
        • SessionFactory级别,session共享
        • 缓存散装持久化实例, 有不同缓存策略
        • 先设置策略,再设置过期时间与cache提供器
      • 优点
        • 提高速度、减小压力
        • 缓存失效时,不立即查找,而是合并sql查找
    • 查询方式
      • HQL
      • QBC(命名查询)
      • SQL
    • get与load
      • get立即加载,load延时加载
      • get先查一级缓存,再查二级缓存,再查数据库, load查一级缓存,没有时创建代理对象,需要时再查二级缓存和数据库
        • 代理对象只存id
      • get没有时返回null, load抛异常
    • 检索策略 # 取关联对象
      • 立即检索 # 一次全加载, select多
      • 延迟检索 # 访问游离状态代理类,需要在持久化状态时已被初始化
      • 迫切左外连接检索 # 用外连接取代select,全加载
  • 优化
    • 数据库设计调整
    • HQL优化
    • api正确使用
    • 配置参数 # 日志、查询缓存,fetch_size, batch_size等
    • 映射文件优化 # id生成策略,二级缓存,延迟加载,关联优化
    • 一级缓存管理, 二级缓存策略
    • 事务控制策略
  • 基本概念
    • o hibernate 相当于dao层,层次划分中是访问层,解决增、删、改、查、批处理五个问题
    • o hibernate实现orm(对象关系映射标准,完全面向对象编程思想)
      • DBUtils与i/mybatis 与hibernate 是同样的,同样实现的是orm标准
      • 它们的区别在于
        • hibernate中不写sql语句
        • ibatis中写少量sql语句
        • DBUtils中写sql语句
      • 它们的另一个相同点是
        • 底层全都是jdbc
    • o 结构对应 javabean中的 类,对象,属性
      • 数据库中的 表,记录,字段
    • o hql hibernate query language,hibernate自己的sql语言,需要使用antlr jar包中的方法内部转换成sql语言才能使用
    • o 正向工程:JavaBean生成表,反向工程:表生成JavaBean
  • 使用
    • 1.导入核心包(10 + 1个)
      • hibernate3.jar # 核心包
      • c3p0-0.9.1.jar
      • antlr-2.7.6.jar # 转换hql到sql
      • commons-collections-3.1.jar # apache的集合增强包
      • dom4j-1.6.1.jar
      • javassist-3.9.0.GA.jar # 动态代理
      • jta-1.1.jar # java transaction api 处理事务用
      • slf4j-api-1.5.8.jar
      • log4j.jar
      • slf4j-log4j12.jar # 三个日志
      • mysql-connector-java-5.1.7.bin.jar
    • 2.建立目录
      • hibernate.dao
        • demo.java
      • hibernate.db
        • xx.sql
      • hibernate.domain
        • xx.java
      • hibernate.util
        • HibernateUtil.java
    • 3.创建映射文件
      • xx.java文件的同目录下,创建
        • xx.hbm.xml
    • 4.创建配置文件
      • src/hibernate.cfg.xml (可变)
      • src/hibernate.properties
    • 5.写提供hibernate session的工具类
      • HibernateUtil
    • 6.demo中用hibernate session创建事务进行数据库操作
      • demo.java
  • session
    • 查询不需要事务,其它都需要事务
    • 流程
      • Session session = HibernateUtil.getSession();
      • Transaction t = session.getTransaction();
      • t.begin();
      • session.update(hero);
      • session.delete(hero);
      • t.comment();
    • 批量
      • t.begin();
      • session.save(hero);
      • t.commit();
      • session.clear();
      • 查询
      • Query query = session.createQuery(hql);
      • List heroList = query.list();
      • 查询2
      • Query query = session.createQuery(hql);
      • query.setString(0,name); // hql中参数从0开始
      • query.setString(1,des);
      • Hero hero = (Hero) query.uniqueResult(); // 只有一个结果时使用
      • 修改
      • Query query = session.createQuery(hql);
      • int i = query.executeUpdate();
    • 结尾
      • }catch(Exception e){
        • e.printStackTrace();
        • t.rollback();
      • }finally{
        • HibernateUtil.closeSession(); // session.close();
      • }
    • session
      • 元素的状态
        • oid: object id,hibernate 的id值唯一并且与表中的数据一一对应
        • hibernate中分辨数据只看oid

        • 临时(new),无oid,不在session中.生成sql语句
          • 持久化(persistence object):session.save(hero),有oid,在session中;(saveOrUpdate(hero))
          • 游离:session.evict(hero),有oid,不在session中,session.update(hero)重新持久化
          • 删除:sesssion.delete(hero),有oid,不在session中,不可恢复,提交后可修改数据库
            • 隐含将po对象转成持久化状态,并生成delete语句。提交后成delete状态,执行语句
            • 临时、持久、游离都可以调用
            • 临时调用delete时会删除数据库中相应id的值 ,危险
      • 函数
        • get 与 load
          • session.get(hero.class,1),从数据库得到持久状态对象
            • 与数据库交互
            • 查到时返回po
            • 查不到时返回null
          • session.load(hero.class,1)
            • 不与数据库交互,返回自己创建的po(只有id)
          • 访问非id值的时候,与数据库交互
        • session.clear() # session中的引用变量清空
        • session.close() # clear() + 关闭session对象,回收资源,但session非空
        • session.isOpen()
        • session.flush() # 对session中的更改部分生成相应的sql语句,只在session中,不访问数据库
        • session.update() # 只是将游离重新持久化,不产生sql语句。(执行更新语句时加上它增加可读性)
          • update()方法执行时会检验一级缓存(session)中是否有 oid相同的po
          • ,同时会连接数据库,查询一级缓存中po与数据库中记录的一一对应关系
        • session.commit() # flush() + 提交事务
  • hibernate.cfg.xml
    • 必要性
      • 必须配置
    • 目录与文件名
      • 任意,建议 src/hibernate.cfg.xml
    • 源码中的案例文件:
      • \project\tutorials\web\src\main\resources\hibernate.cfg.xml
      • \project\etc\hibernate.cfg.xml
    • 约束文件位置
      • hibernate3.jar/org/hibernate/hibernate-configuration-3.0.dtd
    • 数据库连接属性与方言属性的属性名和值可以查找
      • \project\etc\hibernate.properties # 由于xml文件中配置要覆盖的是hibernate.properties文件中的属性
        • 所以属性内容从hibernate.properties文件的属性中查找
      • 方言类的位置是:hibernate3.jar/org.hibernate/dialect/中查找到相应的类,
        • 这是最终的路径,(oracle的通用方言类的类路径 可以用这种方法找到,hibernate.properties配置文件中没有写)
    • 加载
      • 该配置文件属于纯人为配置,需要在Configuration类的实例中调用addResource("")方法加载
      • addResource()方法中的参数是本配置文件相对于src/目录的全限定名
    • 作用
      • 1.映射数据库
      • 2.配置 类-表映射 资源xml文件的路径
    • 内容
    • <?xml version=“1.0” encoding=“UTF-8”?> - <!DOCTYPE hibernate-configuration PUBLIC - ”-//Hibernate/Hibernate Configuration DTD 3.0//EN”
    • <hibernate-configuration> - <session-factory> - <!— 配置访问数据库需要的属性 - <property name=“connection.driver_class”>oracle.jdbc.driver.OracleDriver</property> - <property name=“connection.url”>jdbc:oracle:thin:@localhost:1521:orcl</property> - <property name=“connection.username”>scott</property> - <property name=“connection.password”>tiger</property> - <!— 配置方言 通知hibernate访问哪种数据库的语法结构 - <property name=“dialect”>org.hibernate.dialect.OracleDialect</property> - <!— 类表映射文件 - <mapping resource=“hibernate/domain/Hero.hbm.xml”/> - </session-factory> - </hibernate-configuration>- hibernate.properties
    • 必要性
      • 不必须配置
    • 位置:
      • 该文件的位置在src/目录下是不可以改变的,是hibernate加载配置的入口
    • 源码中的参考文件:
      • /project/etc/hibernate.properties
        • oracle的通用驱动可以从hibernate3.jar/org.hibernate/dialect包中查找
    • 作用
      • 1.配置连接的数据库,更换数据库只需要更改配置文件即可
      • 2.配置数据库方言
      • 3.其它控制开关
    • 方言的作用
      • 更换数据库访问形式,实现通用性
    • 内容
      • hibernate.dialect org.hibernate.dialect.MySQLDialect
      • hibernate.connection.driver_class com.mysql.jdbc.Driver
      • hibernate.connection.url jdbc:mysql:///outrun
      • hibernate.connection.username outrun
      • hibernate.connection.password pwd
      • hibernate.show_sql true # 开关:显示实际操作数据库的sql语句
    • 自动创建表
      • hibernate.hbm2ddl.auto=create # 每次都创建
      • hibernate.hbm2ddl.auto=update # 没有时再创建(有但是结构不同时会按照酌情增加列字段)
        • 当更新或插入记录不满足条件时会出错
    • 缓存
      • hibernate.cache.provider_class # 开启二级缓存中的普通区
      • hibernate.cache.use_query_cache # 开启二级缓存中的查询区
  • HibernateUtil
    • 目的
      • 对SessionFactory返回Session的方式进行了重构,通过调用该静态工具方法
      • 实现只有一个SessionFactory实例,由它产生和销毁很多Session的工厂机制。
    • 缓存
      • SessionFactory 是二级缓存
      • Session 是一级缓存
        • 查询时,先在二级缓存中查找,没有数据时查找一级缓存,最后查询数据库
        • 缓存中的数据会用镜像联系着数据库,如果数据库有更新,缓存中的数据会自动更新
    • SessionFactory对象与Session对象
      • SessionFactory:只创建一次,重量级对象,线程安全,可以共享,实例变量,开始时创建
      • Session:创建多次,轻量级对象,线程不安全,不可以共享,局部变量,临时创建
    • 实现代码
    • /**
    • 提供hibernate session
    • 并且用threadLocal跟踪实现无参删除
    • @author Administrator
    • /
    • public final class HibernateUtil {
      • // 单例的SessionFactory工厂
      • private static SessionFactory sessionFactory;
      • // 单例的ThreadLocal实例,但是每个调用者都有自己独有的方法?
      • private static ThreadLocal threadLocal;
      • /**
      • 解析配置文件(properties,xml)到hibernate 的配置JavaBean,常驻内存
      • /
      • static{
        • // 在这里加载了hibernate.properties配置文件(这里可以配置数据库),执行其它配置
        • // 相当于jdbc中的DriverManager类(如果配置了数据库,相当于也注册了连接数据库的类文件 【Class.forName(“..Driver”)语句 ..Driver 新建实例的时候自动向DriverManager注册自己】)
        • Configuration config = new Configuration();
        • // 这里写xml配置文件对于src/目录的相对路径,加载映射用xml文件
        • config.addResource(“hibernate.hbm.xml”);
        • // 加载src/目录下的hibernate.cfg.xml配置文件
        • config.configure(); # configure(“classpath:hibernate.cfg.xml”);
          • 1.configure方法中可以加路径
          • 2.classpath:代表src/目录
        • // 导入org.hibernate.SessionFactory类而非org.hibernate.classic.SessionFactory类
        • sessionFactory = config.buildSessionFactory();
      • }
      • /**
      • 从单例工厂中得到被跟踪定位(每个调用者)的Session对象,没有就创建
      • @return
      • /
      • public static Session getSession(){
        • /* 根据不同的调用者返回跟踪的不同的Session对象,如果是第一次调用,就创建新的session,绑定到单例的ThreadLocal对象中记录,返回给调用者
        • 如果不是第一次调用 ,也能返回让其得到原来为它创建的Session对象
        • /
        • Session session = threadLocal.get();
        • if(session == null){
          • session = sessionFactory.openSession();
          • threadLocal.set(session);
        • }
        • return session;
      • }
      • /**
      • 删除调用者在ThreadLocal实例中的跟踪记录,并且关闭该Session实例
      • /
      • public static void closeSession(){
        • Session session = threadLocal.get();
        • if(session != null){
          • session.close();
          • threadLocal.remove();
        • }
      • }
    • }
  • hql
    • hql特性
      • 1.hql是hibernate专用,有专用的技术转换hql到sql,但降低效率
      • 2.hql完全面向对象,只出现类,属性,操作符和关键字,例如sum(),order by
        • 而sql是面向关系的语言
    • 使用语句
      • Query query = session.createQuery(hql);
      • Customer c = (Customer)query.uniqueResult(); # 只返回一条结果
      • List list = query.list(); # 返回多条结果
    • 常用 api
      • session.createQuery()
      • session.getNamedQuery() # 从映射文件中加载标签配置的与标签同级的hql语句
      • query.setString("","")
      • Object o = query.uniqueResult();
      • List list = query.list();
      • 分页
        • query.setFirstResult(0); # 开始标号
        • setMaxResults(3); # 最多显示的条数
    • query语句 习惯用别名替代类名
      • from后面出现的是类名,where中比较的是对象属性(已经在映射文件中映射到了表名与字段名)
      • 占位符
        • 冒号占位符
          • “from Customer c where c.name = :cname”
          • query.setString(“cname”,“司马懿”);
        • 问号占位符
          • “from Customer c where c.name = ?”
          • query.setString(0,“司马懿”);
      • 映射文件中分离hql语句
        • <query>标签与<class>标签同级 - <Query name=“findCustomerByAge”> - <![CDATA[ - from Customer c where c.age < ?
      • ]]>
      • Query query = session.getNamedQuery(“findCustomerByAge”);
      • query.setInteger(0,60);
      • 查询
        • “from Customer where id = 1”
        • “from Customer as c where c.name = ‘司马懿’ ”
        • “from java.lang.Object” # 映射中没有,写类的全称。查找 src/hibernate.cfg.xml中加载到内存中的映射的类对应的表中的所有记录
        • “from Order o order by o.price desc”
          • 投影查询
            • 1.”select c.name,c.age from Customer c ”
            • List<Object[]> list = query.list(); # Object[]中存储的是查询的select 语句中的数值
            • for(Object [] o : list){
          • System.out.println(o[0]);
          • System.out.println(o[1]);
        • }
        • 2.”select count(o), sum(o.price),min(o.price) from Order o” # count()中的是表类名,统计实例数,查询Order表记录对象的个数
        • 3.”select o.customer.id from Order o”
    • 用到过的hql
      • 级联抓取
        • FROM Role r LEFT JOIN FETCH r.privilegeSet WHERE r.id = :id
      • 级联抓取顶级权限表(去重复)
        • SELECT DISTINCT p FROM Privilege p LEFT JOIN FETCH p.childrenSet WHERE p.parent IS NULL
      • 级联抓取角色
        • FROM Account a LEFT JOIN FETCH a.roleSet WHERE a.id = :id
      • 三级级联抓取 # 对抓取的集合也可以直接抓取下一层
        • FROM Account a LEFT JOIN FETCH a.roleSet r LEFT JOIN FETCH r.privilegeSet WHERE a.login = :login AND a.pass = :pass
  • 案例
    • 编码
      • hibernate用用户操作系统的编码作为自己的编码
      • mysql5.5中设置编码:根目录下my文件 default-character-set=gbk
  • 查询
    • hibernate的查询方式
      • 1.session.get(字节码,1)
      • 2.session.load(字节码,1)
      • 3.HQL查询session.createQuery() session.getNamedQuery() # 后面是从配置文件中载入hql语句
      • 4.对象导航,如多表映射中
        • 以对象的形式操作数据库中的表,如
          • p是person表的一个对象,c是card(身份证表)表的一个对象,p通过配置外键时定义的属性card得到自己的身份证表对象
          • 1.从表对象中:Card c = p.getCard();
          • 2.从hql语句中:select o.customer.id,o.customer.name,sum(o.price) from Order o group by o.customer.id
        • 5.createSQLQuery原生sql语句查询: # 不要用,用了以后 hibernate跨平台的特性就没有了
          • String sql = “select {a.*} from sysgroup {a} where department regexp ?”;
          • Query query = session.createSQLQuery(sql).addEntity(“a”,SysGroup.class);
            • addEntity将表的别名与类字节码关联起来(否则返回的表字段数据是Object类型,jsp页面读取时会出错)
    • 连接查询的hql语法
      • 只能连接有外键关系的表类,用表类中的关系类来表示第二张表,不能用笛卡尔积查询
      • 也就是说只能查一个表类
      • 注意
        • hql连接查询的语法中用where替代了sql语法中的on
        • 外连接与 sql不同,只能查询与一个表类有关系的外连接表(from语句后面不能写两个表类)
      • 内连接
        • from Customer c join c.orderSet o where c.id = o.customer.id
      • 外连接 # 这里与 sql不同,只能查询与一个表类有关系的外连接表
        • select c.name,count(o.orderno) from Customer c left join c.orderSet o group by c.name;
      • 自连接
        • select a.name, b.name from emp a, emp b where a.mgr=b.id;
  • 多表映射
    • 主控方 # 就是只有主控方的操作成立,非主控方的改变忽略
      • inverse=“true”
        • false:主表管理,主表插入成功后,再发送n条更新语句来更新外键
      • true:从表管理,自己插入时加上:自己javabean中存放的外键关联
        • 所以购物项中要关联购物车,由于购物车中已经一对多购物项,所以形成了双向关联
      • 有该属性的标签
        • <set> - 缺少主控方出现的问题
        • 双向一对多中
          • 1.hibernate生成的sql语句产生重复
          • 2.主键冲突 # 插入操作时,由于“一”表级联插入“多”表,“多”表也要插入自己,它们的主键是相同的,会引起主键冲突
    • 级联 # 数据库只有级联删除
      • cascade=“save-update” # 插入和更新
        • 一般使用save-update,因为表一般软删除,(更新也没有,因为主键不更新,但是hibernate没有单save)
      • cascade=“delete”; # 删除订单,级联删上层客户
      • cascade=“none” # 什么都不做(默认)
      • cascade=“all” # save-update + delete
        • 有级联属性的标签
          • class标签下的
            • <set> - <one-to-one> - <many-to-one> - 注意
          • 级联插入的子表的id内容要为空,否则会变成级联更新 # 这里和单个数据插入时设置对象的id属性不起作用【只有hibernate的主键增长策略起作用】是不同的
    • 单向一对多 # 集合映射的一种
      • “一”的类中
        • private Set orderSet = new LinkedHashSet();
      • 映射xml文件中
        • <!— set标签用于映射单向一对多 - name表示单方的关联属性
          • table表示多方对应表的名字
          • key-column表示多方对应表的外健
          • one-to-many-class表示单方关联属性中的每个元素的类型
        • <set name=“orderSet” table=“ORDERS” cascade=“all”> - <key column=“CUSTOMERS_ID”/> - <one-to-many class=“Order”/> - </set> - 单向多对一 # 常用
      • 映射xml文件中
        • <!— - many-to-one映射多方的关联属性
        • name表示多方的关联属性名
        • column表示多方对应表的外健(存储关联类对应表的主键)
        • cascade 级联
        • lazy表示“一”的类数据是否在一开始的时候就查询 # 如果lazy=“proxy”【相当于懒加载】,action类中加载“一”方数据时会出错,因为调用service类结束后线程中的session销毁,延迟加载找不到session会失败
        • fetch表示抓取策略
          • 这里产生了hibernate的n+1问题:一条查询语句查出”一”的集合,n条查询语句查出集合中每个元素的一
          • join代表用join语句查询(一条语句),但是hibernate在多对一的时候不支持fetch=“join”
          • 默认是select,每次查询用一条select语句(多条语句)
            • 解决:自己写新的查询方法查询,执行hql如:FROM Category c LEFT JOIN FETCH c.account
        • <many-to-one - name=“customer”
          • column=“CUSTOMERS_ID”
          • cascade=“all”
        • />
    • 双向一对多 # 双向映射就存在主控方的问题
      •  主表从表(外键【可以为空】)
      • 集合映射的应用
      • 1.同时配置单向一对多与单向多对一
      • 2.在”一”表中配置inverse=“true”,反转权力,“多”表为主控方
    • 双向一对一 # 主表从表(从表id既是主键又是外键)
      • 双方都是主控方
      • 1.两表都配置
      • 2.主表配置cascade
        • 3.从表中constrained=true属性(主键是否同时为外键约束)
    • 多对多(单向左到右,单向右到左,双向) # 集合映射的应用
      • 多对多关系中一定要有主控方,否则主键冲突问题
      • 1.创建中间表
        • 中间表可以没有自己的JavaBean类文件对应,这时默认有联合主键(联合主键分别是保存的两个外键)
        • students_id
        • teachers_id
          • student_id 与 teachers_id为联合主键

        • sql语句是primary key(student_id,teacher_id);

          • 创建中间表原因:
            • 之所以中间表是因为两边的表中主键唯一,所以不能在一个记录中对对应另一个表的多个记录
            • 中间表相当于把多对多分成两个一对多。
      • 2.表对象类中都有对方表的set集合
      • 3.映射xml中 # 可以用inverse,cascade
        • cascade=“none”时,middle表中的记录也会被删除

        • 不配置主控方的话一边更新另一边,另一边也更新自己,会出错

      • <set table=“MIDDLES” name=“teacherSet”> - <key columnet=“STUDENTS_ID”/> - <many-to-many class=“Teacher” column=“TEACHERS_ID”/> - 4.dao中
        • 在cascade=“all”的配置下实现只删除老师与middle表中的教学关系 # 手工解除关系
          • 不手工解除关系的话, 表记录对象:Teacher t1

            • ,t1删除时,级联删除middle表中数据,middle表中对应了学生的外键
            • ,由于多对一级联,会删除学生,由于该学生的主键可能会被middle表中的其它记录作为外键引用,所以不能删除,删除时会出错。
        • 查询1号老师对应的学生,并解除关系
          • Teacher t1
          • for(Student s: t1.getStudentSet()){
            • s.getTeacherSet().remove(t1);
          • }
          • 1号老师解除关系
          • t1.setStudentSet(null);
          • session.delete(t1);
  • 缓存

    • 缓存
      • 1.一级缓存(session)中的数据是独享的,二级缓存(sessionFactory)中的数据是共享的
      • 2.一级缓存中的数据改变时会更新二级缓存(如果二级缓存设置为read-only时,会更新出错)
      • 3.二级缓存默认不能存po(持久化对象) ,只存放连接数据库的信息和映射文件
        • 这时查询数据时的顺序是 一级缓存 数据库

    • 启用二级缓存 # 开启的二级缓存中可以保存po
      • 二级缓存的两个空间:普通缓存区(get、load)、查询缓存区(query对象查询)

      • 普通缓存区
      • hibernate.properties文件中配置
        • hibernate.cache.provider_class
          • org.hibernate.cache.HashtableCacheProvider # 只能内存缓存
          • org.hibernate.cache.EhCacheProvider # 也能磁盘缓存ehcache的jar包中ehcache-failsafe.xml配置文件中可以查到默认缓存配置
            • 可以在hibernate的中文官方教程中查到缓存策略提供商的类

            • hibernate3.2之前缓存类jar包是集成的,默认是EhCache

            • hibernate3.2之后缓存类jar包要自己导入

            • …Provider类并不是实现类,而是桥接类

        • cache.use_second_level_cache
          • true # 开启二级缓存(默认是true,但是没有配置缓存提供商之前不开启)
      • hibernate.cfg.xml文件中配置使用二级缓存的类 # 可以设置的标签
        • 设置时,set对应表类的也要设置标签

        • <class-cache usage=“read-write” class=“pojo.Goods” /> - usage属性
          • read-only:二级缓存只读(只是不能进行修改,但是从表中读取数据时一级缓存可以向二级缓存中放入数据)
          • read-write:可读写
      • 查询缓存区(hql语句):默认不开启
        • 因为hql命中率低(要求hql语句相同才行,模糊查询每次基本不同),每次查找会到缓存,找不到再到数据库,查询完数据再存入缓存,效率低

        • 不配置的话查询还会存到缓存,但只提供get使用,hql自己不用

          • 1.首先开启普通缓存区(设置了表类可以缓存)
          • 2.在query对象中开启查询缓存区
            • query.setCacheable(true);
      • 查询顺序:一级缓存 二级缓存 数据库
    • 缓存提供商配置
      • ehcache缓存提供商
        • 创建src/ehcache.xml配置文件,使用ehcache缓存时会自动加载其中的配置
          • <diskStore path=“java.io.tmpdir”/> # 设置缓存目录,java.io.tmpdir指操作系统的临时目录 - diskPersistent
          • diskExpiryThreadIntervalSeconds # 这两个集群中使用,上面是是否集群持久化,下面是设置持久化时间
          • maxElementsInMemory # 内存支持最大对象数目(溢出的对象会存到硬盘中)
          • overflowToDisk # 内在到最大数目时是否缓存到硬盘
          • eternal # 缓存是否永久有效,如果为true,则timeToIdleSeconds与timeToLiveSeconds不起作用
          • timeToLiveSeconds # 内存中缓存最大存活时间,服务器启动的时间加入其中
          • timeToIdleSeconds # 缓存不被访问时最大存活时间
          • memoryStoreEvictionPolicy # 内存中对象的替换算法FIFO(先进先出first in first out)
            • LRU(最近最未使用算法,最久没有被访问的对象踢出)

            • LFU(最少未被使用算法,考虑了对象的访问频率,踢出最近最少被访问的对象)

            • 是windows自己的替换算法

    • 清空缓存
      • 一级缓存:session.clear();
      • 二级缓存:sessionFactory.close();
  • 集合映射

    • 作用
      • 集合包含于表类中,对应其一个属性,相当于该类对应表的一个子表
      • 每种集合对应一张表,内容对应记录。
      • 把java类中经常使用的数据结构对应到表中
    • 使用
      • javaBean(User)中
        • private Set telSet = new LinkedHashSet();
        • private List cityList = new ArrayList();
        • private Map<String,String> telCityMap = new LinkedHashMap<String,String>();
      • xml文件中
        • <set name=“telSet” table=“TELS”> - <key column=“USERS_ID”/> # 外键列:集合所创建的表的外键列名 - <element column=“TEL” type=“string”/> # 内容列:这里必需要有type - # set中也可以把标签换成标签来对应JaveBean作为值,这就是一对多的映射
      • <list name table> - <key column/> - <list-index column=“IDX”/> # 索引列:表中的索引号列(对应在list中的索引) - <element column type/> - <map name table> - <key> - <map-key type column> # map对应key的列 - <element column type> - dao中使用
        • user.getTelSet().add(“131”);
  • 检索策略

    • hibernate检索的两种类型
      • 立刻检索:session.get,query.list 标签中类的检索策略,get方法与list都不遵循
      • 延迟检索:session.load # 初始时是代理对象,使用时查询 只有load方法遵循标签中类的检索策略
        • 检索方法是load时
          • lazy属性出现在标签中,两个标签中lazy属性的含义是不同的,两个lazy属性都是对load方法执行时是否查询数据库进行设置。
            • 标签中lazy的含义是执行load方法时是否懒于查询数据库中除了set集合之外的所有属性

            • 标签中lazy的含义是执行load方法时是否懒于查询数据库中set集合的数据

            • 中默认lazy属性的值为true

            • 中默认lazy属性的值为true

          • true true 时 查类时没有查集合
          • false true 时 查类时没有查集合
          • false false 时 查类时查集合
          • true false 时 查类时没有查集合
  • 经验

    • 删除的两种方法
      • session.delete(session.get(Category.class,id)); # 先查询再删除,效率低
      • session.createQuery(“delete Categroy c where c.id=:id”).setInteger(“id”,id).executeUpdate();
        • 执行hql语句,效率高

    • hibernate注解
      • hibernate3.6支持注解
        • javaee5不支持,默认关闭
        • javaee6支持,默认开启,此时不加载注解配置文件会报错,所以要关掉
          • hibernate.cfg.xml中
          • <property name=“javax.persistence.validation.mode”>none</property> - DB Browser反射编译表的生成映射文件和类的时候,会生成项目目录下hibernate.reveng.xml的临时配置文件,可以删掉
    • 映射文件class属性
      • dynamic-update=“true” # 动态更新,只有对相同的session有效,而且性能不好
        • 用字段设置中的update=“false”(对象中有字段值时更新,没有时不更新)属性来设置动态更新

    • 映射文件set标签属性
      • Order-by=“id” # set中级联对象按照”id”属性进行排序
  • c3p0

    • c3p0并不是hibernate默认的连接池(默认的是hibernate自带的连接池算法)
      • 配置c3p0以后自动关闭Hibernate自带的连接池,而使用c3p0连接池
    • hibernate.cfg.xml文件中
      • <!— 最大连接数 - <property name=“hibernate.c3p0.max_size”>20</property> - <!— 最小连接数 - <property name=“hibernate.c3p0.min_size”>5</property> - <!— 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 - <property name=“hibernate.c3p0.timeout”>120</property> - <!— 最大的PreparedStatement的数量 - <property name=“hibernate.c3p0.max_statements”>100</property> - <!— 每隔120秒检查连接池里的空闲连接 ,单位是秒 - <property name=“hibernate.c3p0.idle_test_period”>120</property> - <!— 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 - <property name=“hibernate.c3p0.acquire_increment”>2</property> - <!— 每次都验证连接是否可用 - <property name=“hibernate.c3p0.validate”>true</property> - hibernate.properties文件中
      • hibernate.c3p0.min_size=5
      • hibernate.c3p0.max_size=20
      • hibernate.c3p0.timeout=1800
      • hibernate.c3p0.max_statements=50
  • 映射

    • hbm.xml
      • 位置与名称:
        • domain.xx.java 文件同级目录 xx.hbm.xml
      • 约束文件位置
        • hibernate3.jar/org/hibernate/hibernate-mapping-3.0.dtd
        • 从其中复制约束头
      • 源码中的案例文件
        • \project\tutorials\中搜索 hbm.xml
      • 类-表映射的特点
        • 1.映射JavaBean到表字段(动态占位符),可以使用面向对象的hql语名生成sql语句
        • 2.session中保存类对象,缓存查询过的表的内容
        • 3.在映射关系的xml文件中可以设置主键的改变方式(这样以后dao类中设置的主键内容被配置文件中的设置覆盖)
      • 主键
        • 表中的主键
          • 自然主键:有业务逻辑含义的字段(如name)(多个自然主键:联合主键)
          • 代理主键
        • hibernate中id的增加类型
          • increment 整型,不依赖数据库自增,多线程不安全
          • uuid 缺点:占空间
          • identity 整型,依赖数据库自增,线程安全
          • sequence 专用于oracle数据库,要用特定名字的序列,create sequence hibernate_sequence;线程安全
          • native(重点) 根据情况判断是identity或sequence
          • assigned 自然主键:,线程不安全
          • composite-id 多个自然主键,表的javaBean必须实现序列化(1.对象序列化到硬盘、数据库【其它JavaBean有id属性,hibernate自动实现序列化】2.线程间传递数据)
            • <composite-id><key-property name=“firstname” column=“firstname”/><key-property name=“firstname” column=“lastname”/> - 持久化对象的两种类型
        • 实体型:具有id属性的类,映射成一条含有id主键的完整记录
        • 值类型或组件:与上面相反(被实体型包含),如
          • 包含以后会把组件的属性添加到实体类属性的后面,一起当作一张表,仅此而已

        • Address

          • province
          • city
          • area
        • 映射组件型属性
        • 1.类中引用组件:private Address address
        • 2.映射
        • 3.dao中 star.setAdrress(address);
      • 内容
      • <?xml version=“1.0” encoding=“UTF-8”?> - <!DOCTYPE hibernate-mapping PUBLIC - ”-//Hibernate/Hibernate Mapping DTD 3.0//EN”
      • <hibernate-mapping package=“hibernate.domain”> - <class name=“Hero” table=“heros” dynamic-insert=“true”> - # 设置动态插入为true:如果是null的值,不再插入 - 如果不设定动态插入,会插入数据库null值,数据库中设定的默认值不会起作用 - <!— hibernate通过自己内部的类型type="",来转换java类型与sql类型之间的转换,一般不必写,自动反射 - <!— id 是指主键,property是属性 - <id name=“id” column=“id”> - <!— hibernate内部的主键生成器 - <generator class=“increment”/> - </id> - <property name=“name” column=“name”></property> - <property name=“gender” column=“gender”></property> - <property name=“age” column=“age”></property> - <property name=“birthday” column=“birthday”></property> - <property name=“des” column=“des”></property> - </class> - </hibernate-mapping> - javaBean
      • 实现序列化接口
        • 在有名为id属性的JavaBean中,hibernate会自动实现序列化接口
        • 没有名为id属性的JavaBean中,需要我们自己实现序列化接口
      • public class Hero implements java.io.Serializable{
        • private Integer id;
        • private String name;
        • private String gender;
        • private Integer age;
        • private Date birthday;
        • private String des;
      • }