hibernate--初识

配置文件的详解
    映射文件
        名称:自定义 格式为xml     建议: 类名.hbm.xml
        路径:自定义 建议放在domain下
        导入约束
            <!DOCTYPE hibernate-mapping PUBLIC 
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        内容:
            类和表的映射关系
                class标签
                    name属性:类的全限定名
                    table属性:表名(若表名和类名同样的话,table属性能够省略不写)
            属性和主键字段的映射关系
                id标签
                    name属性:属性名称
                    column属性:主键字段名称(若列名和属性名一致的话,column属性能够省略不写)
                    主键生成策略:目前使用native
            属性和普通字段的映射关系
                property标签
                    name属性:
                    column属性:
    /////////////////////////////////////////////////
    核心配置文件
            名称: 建议使用 hibernate.cfg.xml     也可使用hibernate.properties(不建议)
            路径: 建议放在 src目录下
            导入约束:
                <!DOCTYPE hibernate-configuration PUBLIC
                    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
            配置内容:
                数据库链接4个基本信息    : 参考\project\etc\hibernate.properties property标签
                
                hibernate的属性配置 方言,是否显示sql,是否格式化sql... property标签
                    <!-- 
                        是否由hibernate来生成表的定义语句及如何生成
                            常见值:
                                update:使用表的使用,先判断表是否存在,若不存在自动建立表.
                                    若存在,
                                        再判断配置文件和表是否对应上,
                                            若对应不上,更新表结构
                                            若对应上,直接使用表
                                        
                                
                            了解值:
                                create:每次使用表的时候,都从新建立一张表,若以前表存在则删除
                                create-drop:每次使用表的时候,都从新建立一张表,若以前表存在则删除,当此次执行完全完成的时候,删除此表.
                                validate:每次使用表的时候,须要校验表和映射文件中的配置是否同样,若一致则使用,若不同呢则抛异常
                     -->
        <property name="hibernate.hbm2ddl.auto">validate</property>
            映射文件的路径    mapping标签
            <mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
==================================
api的详解
    Configuration:类 配置对象
        做用:
            ★1.加载核心配置文件
                (了解)new Configuration():默认加载src目录下的名称为 hibernate.properties的配置文件(不能配置映射文件的路径)
                ★new Configuration().configure():默认加载src目录下的名称为 hibernate.cfg.xml的配置文件
                
                (了解)new Configuration().configure(String 配置文件的路径):加载指定路径下的配置文件
                    new Configuration().configure("config/a.xml"):加载src目录下config目录下的a.xml
            ★2.建立sessionFactory
                    buildSessionFactory()
            (了解)3.加载映射文件
                addResource(string );
    -----------------------------------
    SessionFactory:接口 session工厂
        SessionFactory并非轻量级的,由于通常状况下,一个项目一般只须要一个SessionFactory就够
        做用:
            1.初始化Hibernate。
            2.它充当数据存储源的代理(底层维护了一个链接池)
            ★3.并负责建立Session对象    
                openSession();
        ---------------------
        抽取一个工具类    
            HibernateUtils
                提供一个获取session的方法
        ---------------------
        整合c3p0
            步骤:
                1.导入jar包 hibernate解压目录下/lib/optional/c3p0/*.jar
                2.在核心配置文件中配置c3p0提供商
                    <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    Session:接口,至关于链接 
        Session对象是有生命周期的,它以Transaction对象的事务开始和结束边界
        线程不安全,轻量级,session不要做为成员变量.
        ★做用:
            1.开启事务
                beginTransaction()
            2.和数据库进行交互
                Serializable save(Object obj); 返回值为此记录的id
                update(Object ob);
                delete(Object ob);
                
                OID查询    
                    T get(Class<T> clazz,Serializable id);经过id获取一个记录,转成相应的对象
                    T load(Class<T> clazz,Serializable id);经过id获取一个记录,转成相应的对象
                区别:
                    (★)get:当即发送sql语句,返回值为对象自己
                    load:不会当即发送sql语句,当使用该对象的非oid属性的时候才发送sql.返回的是代理对象
                        延迟加载:使用的时候才发送sql.
    Transaction:接口 管理事务
        commit();
        rollback();
        
    *-*-*-*-*-*-*-*-*-*-*-**-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-java

持久化类
    javabean+映射文件 
    规范:
        这个类必须是一个公共的具体的类(public class)
        字段私有,必须提供公共的访问方法
        必须提供一个无参构造器
        必须提供一个属性(OID)和主键对应
        尽可能使用包装类修饰属性
        尽可能不要使用final修饰持久化类(若使用final修饰了load和get方法同样了)
///////////////////////////////////////
主键的生成策略
    主键的分类:
        代理主键:给对象额外添加一个字段,没有具体的业务,只是做为主键存在.推荐使用
        天然主键:使用对象自己一个具备业务意义的字段做为主键(例如:身份证号)
    hibernate中的主键生成策略
        常见的值:
            increment:使用的是hibernate的自增,有问题,数据类型必须为 int short long,不推荐使用
            ★identity:使用的数据库底层的自增策略,数据类型必须为 int short long,表明:mysql
            ★sequence:使用的数据库底层的序列策略,数据类型必须为 int short long,表明:oracle
            ★★native:使用的数据库自己的策略,能够简单认为判断数据库支持自增仍是序列.
            ★uuid:使用的随机的字符串
            assigned:放弃hibernate维护主键,咱们本身维护.

持久化对象三种状态(持久态★)
    瞬时态:对象没有oid值,也没有和session关联
    持久态★:对象有oid值,也和session关联
    脱管态:对象有oid值,可是没有和session关联
    
    注意:
        持久态:能够自动更新数据库
    为什么持久态对象能自动更新数据库?底层依赖的是hibernate的一级缓存.

一级缓存
    缓存:
        介于程序和硬件之间的一种介质.
    做用:
        读取数据的时候,先从缓存中查询一下,若缓存中有,直接返回数据.若缓存中没有,再去硬件中查询;
    hibernate是对jdbc进行的封装.效率其实并不高,因而hibernate提供了一系列的优化策略(例如:缓存,延迟加载,抓取策略...)来提供hibernate的运行效率.
    hibernate中的缓存:
        *一级缓存:是hibernate自带的,必须使用的.不能卸载.它的生命周期和session同样.因此有人也称之为session级别的缓存.
        (了解)二级缓存:不是hibernate自带的,要想使用必须先导入jar包,在编写配置文件才可使用(ehcache).通常使用redis替代.
            它的生命周期和sessionFactory同样,因此有人也称之为sessionFactory级别的缓存
    hibernate中的一级缓存工做原理:
        底层就是一系列的java集合.
            读取数据的时候,优先从缓存中查询,若缓存中有直接用;若缓存中没有,在去数据库中查询,且会将查询的结果放入缓存中一份
            保存或者更新数据,一样也会讲保存或者更新过的数据放入缓存中一份.
        
        其实将一级缓存分红了两块区域(缓存区和快照区)
            将数据放入了缓存区一份和快照区中一份.咱们修改数据的时候,只修改缓存区中的数据
            当事务提交的时候,判断缓存区和快照区中的数据是否一致;
                若一致:啥也不干
                若不一致:发送sql语句,更新数据库
        
        先来证实一下一级缓存的存在.
            1.对一条记录查询两次
            2.先保存一条记录在查询这条记录.

事务
    事务的概念
    事务的特性:
        ACID
        原子性
        一致性
        隔离性
        持久性
    若不考虑隔离性会产生那些读问题:
        脏读
        不可重复读
        虚读
    经过设置数据库的隔离级别就能够避免上面的一些问题
        1    read uncommitted
        2    read committed    (oracle)
        4    repeatable read (mysql)
        8    serializable
    java中应该在service层进行事务控制
        如何保证service和dao使用的是同一个事务?
            只须要保证他们使用的是同一个链接
                如何保证service和dao使用的是同一个链接?
                    方式1:向下传递链接
                    *方式2:ThreadLocal
                    
    hibernate中的设置隔离级别:
        只须要在核心配置文件中配置 hibernate.connection.isolation 属性
            <!-- 设置事务的隔离级别 -->
            <property name="hibernate.connection.isolation">4</property>
            
    *hibernate其实对ThreadLocal进行封装了
        步骤:
            1.先在核心配置文件中配置 hibernate.current_session_context_class 属性  值为:thread
                <!-- 开启与线程绑定的session -->
                <property name="hibernate.current_session_context_class">thread</property>
            2.获取session的时候,经过factory.getCurrentSession();
        注意:
            若使用getCurrentSession()获取的session,不须要咱们手动关闭了
////////////////////////////////////    
查询的api(*)
    hibernate中提供了5中常见的查询方式
        oid查询(get和load)
        对象导航查询(明天讲)
        sql查询(直接写sql语句)
        hql查询
        qbc查询(条件查询的)
/////////////////////    
hql查询
    先获取Query对象
        session.createQuery(String hql语句)
    hql语句,几乎和sql语句同样.是一个面向对象的查询语句.
        hql语句须要讲sql中的表名和字段名使用类名和属性名替代.    
    查询全部
        hql:
            from Customer
        方法:
            list()
            uniqueResult() :返回惟一值
    排序查询
        hql:
            from Customer order by ....
    统计查询
        hql:
            select count(*) from  Customer ....
    分页查询
        不要在hql中体现分页信息
        方法:
            setFirstResult(int 开始的索引)
            setMaxResults(int 每页显示的大小)
    条件查询
        hql:
            from Customer where 属性1 = ? and 属性2 = ?
        方法:
            setParameter(int 问号索引,Object 值);
    投影查询(查询部分属性)
        返回的是 Object[]
        
    //投影查询(部分属性) 将查询的结果封装到对象中
    /**
     * 1.须要在持久化类中提供相应的构造器
     * 2.改写hql语句
     *         select new 类名(属性1,属性2) from 类
     */
//////////////////////////
qbc查询
    query by criteria:更加面向对象的查询方式.全是api
    先获取查询对象 Criteria
        session.createCrieria(Class clazz)
    查询全部
        list()
        uniqueResult()
    排序查询
        addOrder(Order.asc|desc(属性名称))
    分页查询
        setFirstResult(int 开始的索引)
        setMaxResults(int 每页显示的大小)
    统计查询
        setProjection(Projections.sum|min|max|avg|count("属性名"))
        setProjection(Projections.rowCount())
        
    条件查询
        add(Restrictions.like|eq|lt|gt(属性名,值...))
        
    离线查询(多条件+分页)
        脱离session使用的查询方式.
        获取离线对象的方式
            DetachedCriteria dc = DetachedCriteria.forClass(Class clazz);
        他的api几乎和criteria的api一致
        
        咱们在web层使用离线查询对象,
            用它来判断参数和封装参数 
        
        咱们最后须要在dao获取一个能够执行的查询对象便可
                Criertia cc = dc.getExecutableCriteria(session);
sql查询
    SqlQuery ss = session.createSqlQuery(String sql语句);
    
    方法:
        list
        uniqueResult
        
        setFirstResult
        setMaxResults
        
        setParameter
    返回值都是:
        object[]
    
    若想要将结果封装成某个对象
        addEnity(Class clazz)mysql

*-*-*--*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*web

多表操做:
    常见的关系:
        一对多
        多对多

实体之间的关系:
    一对多:用户和订单,分类和商品,订单和订单项,客户和联系人
    多对多:学生和选课,订单和商品,角色和用户
    一对一:公司和注册地,合法夫妻,居民和身份证号
数据库中表的设计:
    一对多:根据须要在多表中添加一个外键,指向一表的键(通常是主键)
    多对多:引入一张中间表,里面须要存放两位两张表的主键.
    一对一:
        解决的方案:
            1.合二为一
            2.惟一外键对应(就是把他们当作是一个特殊的一对多,在其中的一张表中添加外键,且给这个外键提供惟一约束)
            3.主键对应
java中的实体设计:
    一对多:
        客户和联系人
            根据须要
                在一的一方添加多的一方的集合
                在多的一方添加一个一方的对象
    多对多:
        放入一个对方的集合便可
    一对一:
        放入一个对方的对象便可
案例1:一对多
    客户和联系人
    1.建立数据库
        
    2.建立对应的类
        根据须要
            在一的一方添加多的一方的集合
            在多的一方添加一个一方的对象
    3.建立映射文件
        在多的一方配置many-to-one标签
            name属性:一的一方在多的一方中的对象属性名称
            class属性:一的一方的全限定名
            column属性:外键的字段名称
        在一的一方配置set标签
            name属性:多的一方在一的一方中集合的属性名称
            key标签:
                column属性:外键的字段名称
            one-to-many标签
                class属性:多的一方的全限定名
                
        别忘记去核心配置文件中加载两个映射文件
    4.测试代码
        设计两个客户:大雄 老金
        设计三个联系人:
            大雄:熊大和熊二
            老金:金三胖
        有一个小小的问题:
            保存的时候还发送几条update语句?(一会讲)
            
        没有添加任何配置,能不能只保存客户,将他关联的联系人也进行保存呢?瞬时对象异常
        
    --------------------------
    级联操做:
        级联:操做主体的时候,将其关联的对象也进行相同的操做.
            级联具备方向性
        级联保存更新操做:
            ★保存客户,将他关联的联系人也进行保存
                客户是主体,就须要在主体的一方配置级联保存更新,在映射文件中set标签上配置 cascade属性 值为:save-update
            保存联系人,将他关联的客户也进行保存
                    联系人是主体,就须要在主体的一方配置级联保存更新,在映射文件中many-to-one标签上配置 cascade属性 值为:save-update
        级联删除操做:
            ★删除客户的时候,将他关联的联系人也进行删除
                客户是主体,就须要在主体的一方配置级联删除,在映射文件中set标签上配置 cascade属性 值为:delete   若还有其余的级联操做,用","隔开
            删除联系人的时候,将他关联的客户也进行删除
                联系人是主体,就须要在主体的一方配置级联删除,在映射文件中many-to-one标签上配置 cascade属性 值为:delete   若还有其余的级联操做,用","隔开
    -------------------------
    ★默认删除
        删除一的一方的时候:(必须先查询再删除)
            若咱们使用web阶段的只是直接删一的一方的会报错;
            hibernate中会先将从表中的对应数据的外键置为null,而后再删除主表中的数据.
            
            
    冗余sql(多余sql)
        咱们保存数据的时候 先保存了客户,而后保存了联系人,发现除了insert语句以外,还发送几条update语句
        这个操做不影响结果
        缘由:
            双方都维护外键 且 双方进行了关联操做
        解决方案:
            方案1:让其中的一方放弃外键维护
            方案2:单向关联
        咱们在开发中使用让其中的一方放弃外键维护,谁放弃呢?
            必须是一的一方放弃.
            只须要在一的一方的映射文件中set标签上配置 inverse="true"
            
    cascade决定的是 操做主体的时候 是否 也操做关联方
    inverse决定的是 保存一的一方的的时候 多表中是否有外键
    开发中:
        通常都会在一的一方添加inverse 且设置cascade=save-update

案例2:多对多    
    用户和角色

            
    1.建立实体类
        放入一个对方的集合
    2.建立映射文件
        set标签
            name属性:对方在本身中的集合属性名称
            table属性:中间表表名
            key标签
                column属性:本身在中间表的外键信息
            many-to-many标签
                class属性:对方的全限定名
                column属性:对方在中间表中的外键信息
        
        在核心配置文件中加载映射文件
        
    3.测试代码
        让其中的一方放弃外键维护
        开发中 通常让被动方放弃

    级联保存或更新(了解中理解)
        保存用户的时候,将其关联的角色也进行相同的操做
            用户是主体,须要在用户的映射文件中配置级联保存更新 set标签上配置 
    
    
    级联删除:(了解中的了解)
        删除用户的时候,将其关联的角色也进行相同的操做
            用户是主体,须要在用户的映射文件中配置级联删除 set标签上配置 
        
    ★默认删除:(★)
        先删除中间表中的相应的记录,而后再删除对应表中的记录.

其余的操做:
    例如:
        给一个用户添加角色
            查询用户
            查询某个角色
            给用户的roles中添加角色便可
        给一个用户删除角色
        给一个用户切换角色
            
    注意:
        hibernate是一个orm框架.查询到的数据都是持久态数据.

扩展:
    一对一:(使用惟一外键对应)
        放入对方的对象
        映射文件
            使用one-to-one标签 且在外键上添加一个 constrained
      
延迟加载和对象导航查询
    
需求:
    想知道客户1的联系人个数
        Customer c = session.get(Customer.class,1L);
        c.getLinkmans().size();
    
    想知道联系人1的客户名称
        Linkman l = session.get(Linkman.class,1L);
        l.getCustomer().getCust_name();
        
延迟加载:
    使用的时候采起发送sql查询
        客户1的联系人个数
            由一的一方查询多的一方默认使用的延迟加载.(开发中咱们也是这样作的)
                
                能不能查询客户的时候立马把联系人也查询出来.(了解)
                    在客户的映射文件中的set标签上设置一个属性(lazy属性) 值为false便可
        联系人1的客户名称
            有多的一方查询一的一方的时候默认使用的也是延迟加载
            开发中咱们经过多的一方查询一的一方通常使用的是当即加载. (★)
                在联系人的映射文件中 many-to-one标签,上设置一个属性(lazy属性) 值为false便可
        
    在set标签上lazy属性的常见值有
        true:使用延迟加载 (默认值) ★
        false:使用当即加载
        
    在many-to-one标签上lazy属性的经常使用值为 false
        *-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-redis

注解方式(JPA)
    jpa是规范(接口),hibernate是其中的一套实现类而已


JPA:
单表操做:
    环境搭建:
        1.导入jar包
            如果纯jpa操做.须要在以前包的基础之上额外导入一个 entitymanager.jar   jar报目录:解压目录/lib/jpa/hibernate-entitymanager-5.0.7.Final.jar
        2.编写核心配置文件(和以前hibernate.cfg.xml中内容大体相同)
            名称:persistence.xml
            路径:src/META-INF
            导入约束:
                <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                            http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
                    version="2.0">
                </persistence>
            内容:
                数据库的单元
                    规范的实现提供商.(省略)
                    注解类的路径(省略)
                    
                    数据库的链接信息.
                    hibernate的配置
                    导入c3p0配置
                    
                    不用导入(隔离级别,事务session绑定线程配置)
            注意:
                最后修改一下 transaction-type="RESOURCE_LOCAL" 使用数据库本地事务
                
                
        3.抽取工具类(相似于以前的hibernateUtils) JPAUtils
            以前提供了一个私有的静态sessionfactory对象,今天提供一个 entityManagerFactory
            以前还提供了一个获取session的方法,今天提供一个获取 EntityManager的方法
        4.建立持久化类
            类上的注解
                @Entity //声明本身是一个持久化类
                @Table(name="cst_customer") //声明对应的表
            oid属性上的注解
                @Id //声明它是oid
                @Column(name="cust_id")//声明对应的字段名称 若字段名称属性名称一致的话name能够省略不写 或者Column注解直接不写
                @GeneratedValue(strategy=GenerationType.IDENTITY)//声明主键生成策略
            普通属性上的注解
                @Column(name="cust_name")//声明对应的字段名称 若字段名称属性名称一致的话name能够省略不写 或者Column注解直接不写
        5.入门代码
            //开启事务
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            
            //保存
            persist(obj);
            

    经常使用的api
        保存: persist(Object obj)
        查询:
            find(Class clazz,Object id); 当即查询
            getReference(Class clazz,Object id); 延迟加载
            
        更新:
            方式1:快照方式
            方式2:强制更新,将脱管态数据强制更新到数据库中 merge(Object obj)
        删除:
            remove();
            
        查询的api:
            jpql查询:Java持久化查询语言
            获取查询对象
                em.createQuery(jpql语句)
            查询全部
                getResultList()
                getSingleResult()
            分页查询
                同样
            排序查询
                语句 + order by
            统计查询
                同样 
            条件查询
                问号占位符
                api
                    setParameter(int 第几个问号,Object obj)
            投影查询
                同样

多表的操做:
    一对多
        注意:属性名称尽可能使用驼峰式 尽可能不要出现"_"
        
        1.建立持久化类
            多的一方
                /**
                 * 配置多对一 @ManyToOne
                 *         targetEntity属性:一的一方的字节码对象,若在对方中已经配置过,能够省略不写.
                 * 
                 * 配置外键字段信息@JoinColumn
                 *         name属性:外键的字段名称
                 *         referencedColumnName属性:指向的主表的键名称(通常是主键,如果主键的话能够省略不写的)
                 * 
                 * 注意:
                 *     @JoinColumn 和  mappedBy 互斥    
                 */
                 @ManyToOne(targetEntity=Customer.class)
                 @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
                 private Customer customer;
            一的一方
                /**
                 * @OneToMany 配置一对多
                 *         targetEntity属性:多的一方的字节码对象
                 *         mappedBy属性:本身在多的一方中的属性名称(至关于放弃外键维护权)
                 *             如果双方都配置映射关系的话必须在放弃的一方使用.
                 */
                @OneToMany(targetEntity=Linkman.class,mappedBy="customer")
                private Set<Linkman> linkmans = new HashSet<Linkman>();
        2.测试保存
            
        ---------------
        级联操做
            在@OneToMany或者@ManyToOne标签上配置 cascade={CasCadeType.Persist | merge | all  | remove}
            
        默认删除:
            就会报错.
            咱们能够模拟一下模拟删除,具体状况看代码.
    ///////////////////////    
    多对多
        建立持久化类
            被动方
                @ManyToMany
                    targetEntity属性:对方的字节码对象
                    mappedBy属性:本身在对方中的属性名称,放弃外键维护权
                例如:
                    @ManyToMany(targetEntity=User.class,mappedBy="roles")
                    private Set<User> users = new HashSet<User>();
            主动方
                @ManyToMany
                    targetEntity属性:对方的字节码对象
                    
                @JoinTable :添加一张中间表
                    name属性:中间表表名
                    JoinColumns属性:本身在中间表中的外键信息 使用@JoinColumn 
                    InverseJoinColumns属性:对方在中间表中的外键信息
                
                例如:
                    @ManyToMany
                    @JoinTable(name="sys_user_role",
                                joinColumns={
                                            @JoinColumn(name="user_num",referencedColumnName="user_id")
                                        },
                                inverseJoinColumns={
                                            @JoinColumn(name="role_num",referencedColumnName="role_id")
                                        }
                                )
                    private Set<Role> roles=new HashSet<Role>();
            
 sql

相关文章
相关标签/搜索