Hibernate3.6 入门3:映射_级联_对象状态
2015-10-24 09:30
337 查看
一.对象状态
1.临时状态
a.直接new出来的对象b.不处于session管理c.数据库没有对象记录2.持久化状态
a.处于session管理b.数据库中有对应的记录c.持久化对象的来源:执行session对象的方法:save/update/get/load/list()等方法,获取到的当前对象.d.若对持久化的对象进行修改,提交事务的时候会映射到数据库中,同步数据库数据.3.游离状态
a.一般session关闭后,对象就会由持久化变为游离b.不处于sessio4000
n管理c.数据库中有此记录
4.状态的转换
<span style="font-size:14px;"> private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(User.class) .addClass(Address.class) .buildSessionFactory(); } public void po_status(){ Session session = sf.openSession(); session.beginTransaction(); // 创建对象 User user = new User(); // 【【临时】】 user.setName("测试用户"); // 保存 session.save(user); //***** insert // 【【持久化】】 // 修改 user.setName("test1"); // 修改持久化对象,提交时候会反映到数据库! ****** update user.setName("test2"); user.setName("test3"); // (智能) 以最后修改的为准! 最后,只是一条update语句! session.getTransaction().commit(); session.close(); // 【事务提交后【user,为游离状态】】 user.setName("aaaaaaaaaaaaaa"); // 不会反映到数据库 }</span>
二、一级缓存(session缓存)
1.Session缓存
Hibernate的一级缓存是由Session提供的,因此它存在于Session的整个生命周期中,当程序调用save()/update()/saveOrupdate()/get()等及查询接口方法list()/iterator()方法时候,如果session中不存在该对象,那么会先将本次的对象存储到一级缓存中便于以后使用,当Session关闭时同时清空一级缓存数据.clear()/evict()2.Session的缓存作用
减少访问数据库的次数,进而提高效率.保证缓存中的对象与数据库的记录保持同步,当缓存的对象改变后,session不会立即执行sql,而是将多个sql语句合并为一条sql进行执行,提高效率.3.清除缓存
清空session缓存的指定对象:session.evict([对象]);清空session缓存的所有对象:session.clear();当session对象关闭后,缓存就自动被清除了.4.手动实现一级缓存与数据库同步
session.flush();其实提交事务时,就是调用了flush()方法.===*5.list()与iterator()查询的区别:
list()查询:只执行一条select查询语句.即,返回值就保存了所有的数据库记录,遍历返回值就可以获取每一条记录.iterator()查询:会执行N+1条sql语句.a.先出现数据表中所有的主键,返回所有主键的集合;b.遍历iterator集合,获取每一个主键,在根据主键生成select查询语句,并执行.c.即,iterator()查询是懒加载,只有用到的时候才后查询.list()与iterator()的缓存:1).list()的查询结果会放入缓存中,但此查询不会获取缓存的数据.即,当完成了第一次list()查询后,再执行一次list()查询,第二次查询不会获取缓存中的数据,而是重新查询.2).iterator()的查询结果会放入缓存中,也会获取缓存中的数据.即当执行第二次iterator()查询时,若缓存中有相同的数据,就会直接获取缓存中的数据,而不会重新查询数据表.三、级联操作
cascade级联操作:save-update/delete/all/none在 映射配置文件 中:
<set cascade="none" ></set>
<many-to-one cascade="none"></many-to-one>
默认为none值,关闭级联操作.
若级联操作开启时,当一个数据表与另一个数据库有关联(引用),当修改一个数据表的数据,那么就会影响另一个表中的数据.影响效果跟cascade的值有关.
<span style="font-size:14px;"> //如:若cascade="save-update" public void save(){ Session session = sf.openSession(); session.beginTransaction(); // 用户 User user = new User(); user.setName("Jack"); user.setAge(18); // 地址 Address add1 = new Address(); add1.setAddress("广东湛江"); add1.setProvince("广东"); add1.setCity("湛江"); // 关系2 add1.setUser(user); /* * 保存 */ session.save(add1); //不需要手动保存用户,才能保存地址.可以直接保存地址,而用户会由后台维护. session.getTransaction().commit(); session.close(); } <span style="white-space:pre"> </span>//若cascade="delete" public void delete() { Session session = sf.openSession(); session.beginTransaction(); //删除 ---- 成功 //自动维护t_employee表的外键引用,将其置空 //一对多 Object obj = session.get(Dept.class, 2); session.delete(obj); /* *Hibernate: select dept0_.id as id0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.id=? Hibernate: update t_employee set dept_id=null where dept_id=? Hibernate: delete from t_dept where id=? 查询要删除的对象Dept id=2 将外键表中的引用置空为null,即Employee中所有的dept_id=2的数据的dept_id都为null 删除对象 */ /* //成功 //删除用户后,该用户引用的部门id对应的部门记录也被删除,而用户表的另一个引用了部门表的id被置空 Object obj = session.get(Employee.class, 2); session.delete(obj); * Hibernate: select employee0_.id as id1_0_, employee0_.empName as empName1_0_, employee0_.age as age1_0_, employee0_.gender as gender1_0_, employee0_.dept_id as dept5_1_0_ from t_employee employee0_ where employee0_.id=? Hibernate: select dept0_.id as id0_0_, dept0_.deptName as deptName0_0_ from t_dept dept0_ where dept0_.id=? Hibernate: update t_employee set dept_id=null where dept_id=? Hibernate: delete from t_employee where id=? Hibernate: delete from t_dept where id=? * * 先查询要删除的对象id=2的Employee * 根据查询的对象Employee(id=2)的外键(dept_id)查询对应的主键表(Dept)的记录 * 将要删除的对象(Employee)的外键值(dept_id)的所有记录(Employee中)的外键置空为null * 删除对象Employee id=2 * 删除对象对应的主键表记录 Dept id=dept_id */ /* //更新 -----成功 //不需要保存部门,保存e1就行,d自动维护 //员工 Employee e1 = new Employee(); e1.setEmpName("Man"); //部门 Dept d = new Dept(); d.setDeptName("财务部"); e1.setDept(d); //d.getEmployees().add(e1);//失败 session.save(e1); //session.save(d); */ session.getTransaction().commit(); session.close(); }</span>
四、映射
1).一对一映射
1.基于对象映射
外键表的外键不是主键.a.JavaBean,属性略<span style="font-size:14px;">public class IdCard { private int id; private String cardNo; private String place; // 身份证,关联的用户; 一对一; 有外键方 private Person person; } public class Person { private int id; private String name; private int age; // 身份证; 一对一; 没有外键方 private IdCard idcard; }b.映射配置</span>
b.映射配置
<span style="font-size:14px;"><!-- IdCard对象的映射配置 -->
<class name="IdCard" table="t_IdCard">
<id name="id">
<generator class="native"></generator>
</id>
<property name="cardNo" length="50"></property>
<property name="place" length="20"></property>
<!-- 一对一,有外键方 (person映射到数据库,对应的是外键字段!) -->
<!-- unique="true" 添加唯一约束! -->
<many-to-one name="person" class="Person" column="person_id" unique="true" cascade="save-update"></many-to-one>
</class>
<!-- Person对象的映射配置 -->
<class name="Person" table="t_person">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" length="50"></property>
<property name="age"></property>
<!-- 一对一, 无外键方 -->
<one-to-one name="idcard" class="IdCard"></one-to-one>
</class></span>
2.基于外键策略:主键作为外键
外键表的外键是表的主键.a.JavaBean
<span style="font-size:14px;">public class IdCard {
private int person_id;
private String cardNo;
private String place;
// 身份证,关联的用户; 一对一; 有外键方
private Person person;
}
public class Person {
private int id;
private String name;
private int age;
// 身份证; 一对一; 没有外键方
private IdCard idcard;
}</span>b.配置映射
<span style="font-size:14px;"><class name="IdCard" table="t_IdCard">
<!-- 主键生成策略: 外键策略! -->
<id name="person_id" column="person_id">
<generator class="foreign">
<span style="white-space:pre"> </span><param name="property">person</param> <!-- 引用的是one-to-one中的name属性! -->
</generator>
</id>
<property name="cardNo" length="50"></property>
<property name="place" length="20"></property>
<!-- 一对一 【主键生成策略是: 外键策略】 -->
<!-- constrained="true" 表示在主键上添加外键约束! -->
<one-to-one name="person" class="Person" constrained="true"></one-to-one>
</class>
------------------------------------------------
<class name="Person" table="t_person">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" length="50"></property>
<property name="age"></property>
<!-- 一对一, 无外键方 -->
<one-to-one name="idcard" class="IdCard"></one-to-one>
</class></span>
2).组合映射
<span style="font-size:14px;">由多个(类)对象映射成一张表.1.JavaBean
public class Car {
private int id;
private String name;
private double price;
// 车轮
private Wheel wheel;
}
public class Wheel {
private int size;
private int count;
private double price;
}</span>
<span style="font-size:14px;">2.映射配置 <class name="Car" table="t_cat"> <id name="id"> <generator class="native"></generator> </id> <property name="name" length="50"></property> <property name="price"></property> <!-- 组合映射:由两个对象组成一张表 --> <component name="wheel"> <property name="count"></property> <property name="size"></property> <property name="price" column="wheel_price"></property> </component> </class></span>
3).继承映射
<span style="font-size:14px;">//*******JavaBean**********//父类
public class Animal {
private int id;
private String name;
}
//子类
public class Cat extends Animal{
// 抓老鼠
private String catching;
}
pub
c59f
lic class Dog extends Animal{
// 玩耍
private String play;
}</span>
1.普通继承映射
<span style="font-size:14px;"><class name="Cat" table="t_cat"> <!-- 父类 --> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <!-- 子类 --> <property name="catching"></property> </class></span>
注意:当Animal的子类有很多的时候,就会有很多子类对应的表,那么如何查询出来所有的Animal子类对象的记录?HQL“fromAnimal”,此时报错为没有指定的hbm文件,因此需要在HQL语句查询的时候指定全类名.HQL “from cn.hib.extend.Animal”即可.
2.方式1:整个继承结构一张表(不推荐)
<span style="font-size:14px;"><class name="Animal"> <!-- 父类 --> <id name="id"> <generator class="native"></generator> </id> <!-- 鉴别器字段,主要用于区分是哪个子类 [冗余字段] --> <discriminator column="type_" type="string"></discriminator> <!-- 父类字段 --> <property name="name"></property> <!-- 子类:猫 --> <!-- discriminator-value 指定鉴别器字段(type_)的值; 如果没有指定默认是子类的全名! --> <subclass name="Cat" discriminator-value="cat_"> <property name="catching"></property> </subclass> <!-- 子类:狗--> <subclass name="Dog" discriminator-value="dog_"> <property name="play"></property> </subclass> </class></span>表结构:
ID NAME catching play type_(区分不同的子类) 【鉴别器】
1 黑猫 抓老鼠 NULL Cat
2 狗 NULL 抓猫 Dog
结论:
1. 整个继承,只需要一个映射文件.
父类、子类的信息写在一起.
减少xml文件的个数.
2. 生成的表,不符合数据库设计原则.
有很多冗余的字段.
如:鉴别器字段 猫数据的play字段 狗数据的catching字段 都为冗余字段.
3.方式2:每个类对应一张表(不是特别好)
<span style="font-size:14px;"><class name="Animal"> <!-- 父类 --> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <!-- 子类:猫 --> <joined-subclass name="Cat" table="t_cat"> <key column="animal_id"></key> <span> </span><property name="catching"></property> <span> </span></joined-subclass> <!-- 子类:狗--> <joined-subclass name="Dog" table="t_dog"> <key column="animal_id"></key> <property name="play"></property> </joined-subclass> </class></span>表结构:
t_animal 父类表(id被子类的映射表引用为主键)
id name
t_cat 猫表
animal_id catching 【animal_id 是外键,应用父类表的主键】
t_dog 狗狗
animal_id play
结论:
a. 整个继承结构,1个映射文件.
b. 父类对应表,每个子类对应表.
c. 表太多,表关系比较复杂.
表关系复杂,数据库效率低下.
例如: 插入猫
先把父类信息插入父类对应表.
再把猫的信息,插入当前子类.(外键引用.)
4.方式3:父类对应表, 每个子类一张表(推荐)
<span style="font-size:14px;"><!-- abstract="true" 表示当前映射的对象,不对应表 --> <class name="Animal" abstract="true"> <!-- 父类 --> <id name="id"> <generator class="assigned"></generator> </id> <property name="name"></property> <!-- 子类:猫 --> <union-subclass name="Cat" table="t_cat"> <property name="catching"></property> </union-subclass> <!-- 子类:狗--> <union-subclass name="Dog" table="t_dog"> <property name="play"></property> </union-subclass> </class></span>表结构:(父类Animal不会生成表)
t_cat 猫id name catching
t_dog 狗id name play
结论:
a. 最合理的方式.b. 简化映射配置* 映射文件,只需要一个* 父类属性,只需要写一次c. 生成的表,最合理.注意:主键不能为自增长.
五、关于查询
<span style="font-size:14px;">//1. hql入门 // auto-import="true" 默认值,hql查询的时候可以不用写包名! // auto-import="false" hql查询的时候必须写类全名 Query q = session.createQuery("from User"); //2. 查询全部 //q = session.createQuery("from User"); //q = session.createQuery("select u from User u"); //q = session.createQuery("select u.* from User u"); // 不支持 *, 报错! //3. 查询指定的列, 不会自动封装为对象! // 如果查询的是一列,返回的list集合是: List<Object> // 如果查询的是多列, 返回的list集合是: List<Object[]> //q = session.createQuery("select id,name,age from User"); //List<Object[]> list = q.list(); //System.out.println(list); //3. 查询指定的列, 自动封装 //q = session.createQuery("select new User(id,name,age) from User"); //System.out.println(q.list()); //4. 条件查询! q = session.createQuery("from User where name='副班1' or name='副班2'"); q = session.createQuery("from User where name='副班1' and name='副班2'"); q = session.createQuery("from User where id between 1 and 3"); q = session.createQuery("from User where id in(1,2)"); q = session.createQuery("from User where name like '%班%'"); //5. ? 占位符查询 q = session.createQuery("from User where name=? or name=?"); // 设置占位符值 q.setParameter(0, "副班1"); // 注意:下表从0开始! (JDBC的pstmt从1开始!) q.setParameter(1, "副班2"); //5. 命名查询 q = session.createQuery("from User where name=:name1_ or name= :name2_"); q.setParameter("name1_", "副班1"); q.setParameter("name2_", "副班2"); //6. 从xml中获取hql,执行! //q = session.createQuery("from User where id>=1 and id<=3 "); q = session.getNamedQuery("my_hql_byId"); System.out.println(q.list()); /* <!-- 保存hql语句 --> <!-- CDATA, 用于批量转移字符串! --> <query name="my_hql_byId"> <![CDATA[ from User where id>=3 and id<=4 ]]> </query> */</span>
相关文章推荐
- POJ 1088 滑雪
- hdu1877 又一版 A+B
- python 性能- and-or 学习技能
- Gradle之旅-搭建eclipse+gradle环境
- CSS浏览器兼容问题整理(IE6.0、IE7.0+ 与 FireFox)(四)
- js数组
- storm 事务和DRPC结合
- CSS浏览器兼容问题整理(IE6.0、IE7.0+ 与 FireFox)(三)
- UVa 11220 - Decoding the message
- 利用ViewPager实现图片循环滚动
- ACM总结
- 返回前一页并刷新页面方法
- maven 项目 启动时异常:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListen
- CSS浏览器兼容问题整理(IE6.0、IE7.0+ 与 FireFox)(二)
- js变量
- CSS浏览器兼容问题整理(IE6.0、IE7.0+ 与 FireFox)(一)
- spark-submit命令行设置
- Leetcode -- Find Minimum in Rotated Sorted Array II
- HTML语言中img标签的alt属性和title属性的作用于区别
- 动手动脑之Stringequals()方法,整理String类的Length(),charAt(),getChars(),replace(),toUpperCase(),toLowerCase(),trim(),toCharArray()使用说明