Hibernate复习(二)

来源:互联网 发布:js判断所有radio选中 编辑:程序博客网 时间:2024/06/14 08:18

一、多表设计
①一对多

public class Customer {    private Integer cid;    private String cname;    //一对多:一个客户(当前客户) 拥有 【多个订单】    // * 需要容器存放多个值,一般建议Set (不重复、无序)    // * 参考集合:List、Map、Array等     // ** 建议实例化--使用方便    private Set<Order> orderSet = new HashSet<Order>();

配置文件

<class name="com.itheima.b_onetomany.Customer" table="t_customer">        <id name="cid">            <generator class="native"></generator>        </id>        <property name="cname"></property>        <!-- 一对多:一个客户(当前客户) 拥有 【多个订单】            1 确定容器  set <set>            2 name确定对象属性名            3 确定从表外键的名称            4 确定关系,及另一个对象的类型            注意:                在hibernate中可以只进行单向配置                每一个配置项都可以完整的描述彼此关系。                一般情况采用双向配置,双方都可以完成描述表与表之间关系。         -->        <!-- 一对多:一个客户(当前客户) 拥有 【多个订单】 -->        <set name="orderSet" cascade="delete-orphan">            <key column="customer_id"></key>            <one-to-many class="com.itheima.b_onetomany.Order"/>        </set>    </class>

②多对一

public class Order {    private Integer xid;    private String price;    //多对一:多个订单属于【一个客户】    private Customer customer;

配置文件

<class name="com.itheima.b_onetomany.Order" table="t_order">        <id name="xid">            <generator class="native"></generator>        </id>        <property name="price"></property>        <!-- 多对一:多个订单属于【一个客户】             * name 确定属性名称            * class 确定自定义类型            * column 确定从表的外键名称        -->        <many-to-one name="customer" class="com.itheima.b_onetomany.Customer" column="customer_id"></many-to-one></class>

③多对多

Student:public class Student {    private Integer sid;    private String sname;    // 学生选择多门课程.    private Set<Course> courses = new HashSet<Course>();...}Course:public class Course {    private Integer cid;    private String cname;    // 课程可以被多个学生选择:    private Set<Student> students = new HashSet<Student>();...}

配置文件

Student.hbm.xml<hibernate-mapping>    <class name="cn.itcast.demo3.Student" table="student">        <id name="sid" column="sid">            <generator class="native"/>        </id>        <property name="sname" column="sname"/>        <!-- 配置多对多关联关系 -->        <set name="courses" table="stu_cour">            <key column="sno"/>            <many-to-many class="cn.itcast. demo3.Course" column="cno"/>        </set>    </class></hibernate-mapping>Course.hbm.xml<hibernate-mapping>    <class name="cn.itcast. demo3.Course" table="course">        <id name="cid" column="cid">            <generator class="native"/>        </id>        <property name="cname" column="cname"/>        <!-- 配置多对多关联关系映射 -->        <set name="students" table="stu_cour">            <key column="cno"/>            <many-to-many class="cn.itcast. demo3.Student" column="sno"/>        </set>    </class></hibernate-mapping>

二、级联操作
save-update:A保存,同时保存B
delete:删除A,同时删除B,AB都不存在
delete-orphan:孤儿删除,解除关系,同时将B删除,A存在的。
如果需要配置多项,使用逗号分隔。

all : save-update 和 delete 整合
all-delete-orphan : 三个整合

三、抓取策略(优化)

1.检索方式:
1.1 立即检索(get):立即查询,在执行查询语句时,立即查询所有的数据
1.2 延迟查询(load):延迟查询,在执行查询语句之后,在需要时在查询(懒加载)

 <class  lazy="true | false">

lazy 默认值true,表示延迟检索,如果设置false表示立即检索

2.检索策略
2.1 类级别检索:当前的类的属性获取是否需要延迟。
2.2 关联级别的检索:当前类 关联 另一个类是否需要延迟。

3.关联级别检索
①一对多或多对多:

3.1 容器 提供两个属性:fetch、lazy
fetch:确定使用sql格式
lazy:关联对象是否延迟。

3.2 fetch:join、select、subselect
join:底层使用迫切左外连接

fetch="join" ,lazy无效。底层使用迫切左外连接,使用一条select将所有内容全部查询。

select:使用多个select语句(默认值)

   当前对象 和 关联对象 使用多条select语句查询。   lazy="false" , 立即,先查询客户select,立即查询订单select   lazy="true",延迟,先查询客户select,需要订单时,再查询订单select   lazy="extra",极其懒惰(延迟),先查询客户select, 如果只需要订单数,使用聚合函数(不查询详情)

subselect:使用子查询

   将使用子查询。注意:必须使用Query否则看不到效果。   lazy= 同上

3.3 lazy:false、true、extra
false:立即
true:延迟(默认值)
extra:极其懒惰

②多对一:
3.5介绍:
<many-to-one fetch="" lazy=""> (<one-to-one>)
 fetch取值:join、select
join:底层使用迫切左外连接
select:多条select语句
 lazy取值:false、proxy、no-proxy
false:立即
proxy:采用关联对象 类级别检索的策略。
订单 关联 客户 (多对一)
订单 立即获得 客户,需要在客户Customer.hbm.xml
订单 延迟获得 客户,需要在客户Customer.hbm.xml

四、HQL语句
HQL语句:描述对象操作的一种查询语句,Hibernate特有。(关键字不区分大小写,但类名和属性名区分大小写)

public void demo01(){/*查询所有*/        //1 查询所有        Session session = factory.openSession();        session.beginTransaction();        //1  使用简单类名 , 存在自动导包        // * Customer.hbm.xml <hibernate-mapping auto-import="true">                Query query = session.createQuery("from Customer");        //2 使用全限定类名        Query query = session.createQuery("from com.itheima.a_init.Customer");/*选择查询*/        //1 指定数据,cid OID名称//      Query query = session.createQuery("from Customer where cid = 1");        //2 如果使用id,也可以(了解)//      Query query = session.createQuery("from Customer where id = 1");        //3 对象别名 ,格式: 类 [as] 别名//      Query query = session.createQuery("from Customer as c where c.cid = 1");        //4 查询所有项,mysql--> select * from...        Query query = session.createQuery("select c from Customer as c where c.cid = 1");/*投影查询*///1 默认        //如果单列 ,select c.cname from,需要List<Object>        //如果多列,select c.cid,c.cname from ,需要List<Object[]>  ,list存放每行,Object[]多列//      Query query = session.createQuery("select c.cid,c.cname from Customer c");        //2 将查询部分数据,设置Customer对象中        // * 格式:new Customer(c.cid,c.cname)        // * 注意:Customer必须提供相应的构造方法。        // * 如果投影使用oid,结果脱管态对象。        Query query = session.createQuery("select new Customer(c.cid,c.cname) from Customer c");/*排序*/Query query = session.createQuery("from Customer order by cid desc");/*分页*/Query query = session.createQuery("from Customer");        // * 开始索引 , startIndex 算法: startIndex = (pageNum - 1) * pageSize;        // *** pageNum 当前页(之前的 pageCode)        query.setFirstResult(0);        // * 每页显示个数 , pageSize        query.setMaxResults(2);/*绑定参数*/Integer cid = 1;        //方式1//      Query query = session.createQuery("from Customer where cid = ?");//      query.setInteger(0, cid);        //方式2        Query query = session.createQuery("from Customer where cid = :xxx");//      query.setInteger("xxx", cid);        query.setParameter("xxx", cid);/*聚合函数和分组*///1 //      Query query = session.createQuery("select count(*) from Customer");        //2 别名//      Query query = session.createQuery("select count(c) from Customer c");        //3 oid        Query query = session.createQuery("select count(cid) from Customer");        Long numLong = (Long) query.uniqueResult();/*连接查询*//*1.交叉连接 ,等效 sql 笛卡尔积2.隐式内连接,等效 sql 隐式内连接3.内连接,等效sql内连接4.迫切内连接,hibernate底层使用 内连接。5.左外连接,等效sql左外连接6.迫切左外连接,hibernate底层使用 左外连接7.右外连接,等效sql右外连接*///左外连接//      List list = session.createQuery("from Customer c left outer join c.orderSet ").list();        //迫切左外链接 (默认数据重复)//      List list = session.createQuery("from Customer c left outer join fetch c.orderSet ").list();        //迫切左外链接 (去重复)        List list = session.createQuery("select distinct c from Customer c left outer join fetch c.orderSet ").list();/*命名查询*///全局        //List list = session.getNamedQuery("findAll").list();        //局部        List list = session.getNamedQuery("com.itheima.a_init.Customer.findAll").list();        session.getTransaction().commit();        session.close();    }

五、常见配置
5.1事务

   事务:一组业务操作,要么全部成功,要么全部不成功。   特性:ACID原子性:整体一致性:数据隔离性:并发持久性:结果   隔离问题:脏读:一个事务读到另一个事务未提交的内容不可重复读:一个事务读到另一个事务已提交的内容(insert)虚读(幻读):一个事务读到另一个事务已提交的内容(update)   隔离级别--解决问题read uncommittd,读未提交。存在3个问题。read committed,读已提交。解决:脏读。存在2个问题。repeatable read ,可重复读。解决:脏读、不可重复读。存在1个问题。serializable,串行化。单事务。没有问题

5.2Hibernate设置隔离区级别

<property name="hibernate.connection.isolation">4</property>

5.3丢失更新

   悲观锁:丢失更新肯定会发生。采用数据库锁机制。读锁:共享锁。    select .... from  ... lock in share mode;写锁:排他锁。(独占)    select ... from  ....  for update   乐观锁:丢失更新肯定不会发生在表中提供一个字段(版本字段),用于标识记录。如果版本不一致,不允许操作。

六、二级缓存
①定义:

   hibernate 提供缓存机制:一级缓存、二级缓存一级缓存:session级别缓存,在一次请求中共享数据。二级缓存:sessionFactory级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存。   SessionFactory的缓存两部分:       1.内置缓存:使用一个Map,用于存放配置信息,预定义HQL语句等,提供给Hibernate框架自己使用,对外只读的。不能操作。    2.外置缓存:使用另一个Map,用于存放用户自定义数据。默认不开启。外置缓存hibernate只提供规范(接口),需要第三方实现类。外置缓存有成为二级缓存。

②构成:

   类级别缓存   集合级别缓存   时间戳缓存   查询缓存(二级缓存的第2大部分,三级缓存)

③应用场景:

   适合放入二级缓存中的数据:很少被修改不是很重要的数据, 允许出现偶尔的并发问题   不适合放入二级缓存中的数据:经常被修改财务数据, 绝对不允许出现并发问题与其他应用数据共享的数据

④配置操作

1.导入jar包:ehcache-1.5.0.jar/ commons-logging.jar/ backport-util-concurrent.jar2.开启二级缓存(我要使用二级缓存)
<!-- 9.1 开启二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property>
3.确定二级缓存提供商(我要使用哪个二级缓存)
<!-- 9.2 提供商 --><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
4.确定需要缓存内容1>配置需要缓存的类2>配置需要缓存的集合
<!-- 9.3 确定缓存内容 -->        <!-- 类缓存 -->        <class-cache usage="read-write" class="com.itheima.a_init.Customer"/>        <class-cache usage="read-write" class="com.itheima.a_init.Order"/>        <!-- 集合缓存 -->        <collection-cache usage="read-write" collection="com.itheima.a_init.Customer.orderSet"/>
5.配置ehcache自定义配置文件

这里写图片描述

类缓存:
这里写图片描述

public void demo02(){        //2 类缓存:只存放数据,散装数据。        // * 使用默认的toString();        Session s1 = factory.openSession();        s1.beginTransaction();        //1 查询id=1 -- 执行select        Customer c1 = (Customer) s1.get(Customer.class, 1);        System.out.println(c1);        //2 查询id=1 -- 从一级缓存获取,一级缓存存放对象本身        Customer c2 = (Customer) s1.get(Customer.class, 1);        System.out.println(c2);        s1.getTransaction().commit();        s1.close();        System.out.println("----------");        Session s2 = factory.openSession();        s2.beginTransaction();        //3 查询id=1 -- 对象不一样,数据一样        Customer c3 = (Customer) s2.get(Customer.class, 1);        System.out.println(c3);        s2.getTransaction().commit();        s2.close();    }

集合缓存:
这里写图片描述

public void demo03(){        //3 集合缓存:只存放关联对象OID的值,如果需要数据,从类缓存中获取。        // * 3.1 默认:第一条select 查询客户,第二条 select 查询客户所有订单        // * 3.2 操作:在hibernate.cfg.xml 将 Order 类缓存删除        // *** <!--  <class-cache usage="read-write" class="com.itheima.a_init.Order"/>-->        // *** 多了10条select,通过订单的id查询订单        Session s1 = factory.openSession();        s1.beginTransaction();        //1 查询id=1         Customer c1 = (Customer) s1.get(Customer.class, 1);        System.out.println(c1);        //2 获得订单        for (Order o1 : c1.getOrderSet()) {            System.out.println(o1);        }        s1.getTransaction().commit();        s1.close();        System.out.println("----------");        Session s2 = factory.openSession();        s2.beginTransaction();        //3 查询id=1        Customer c3 = (Customer) s2.get(Customer.class, 1);        System.out.println(c3);        //4 获得订单        for (Order o2 : c3.getOrderSet()) {            System.out.println(o2);        }        s2.getTransaction().commit();        s2.close();    }

时间戳:任何操作都在时间戳中记录操作时间。
这里写图片描述

public void demo04(){        //4 时间戳: 所有的操作都会在时间戳中进行记录,如果数据不一致,将触发select语句进行查询        // * 修改toString()        Session s1 = factory.openSession();        s1.beginTransaction();        //1 查询id=1         Integer cid = 1;        Customer c1 = (Customer) s1.get(Customer.class, cid);        System.out.println(c1);        //2 绕过一级和二级缓存,修改数据库,修改客户cname=大东哥        s1.createQuery("update Customer set cname = ? where cid = ?")            .setString(0, "大东哥")            .setInteger(1, cid)            .executeUpdate();        //3打印        System.out.println(c1);        s1.getTransaction().commit();        s1.close();        System.out.println("----------");        Session s2 = factory.openSession();        s2.beginTransaction();        //4 查询id=1  -- ?        Customer c3 = (Customer) s2.get(Customer.class, 1);        System.out.println(c3);        s2.getTransaction().commit();        s2.close();    }
原创粉丝点击