*一)持久化对象的状态变化和对应的方法
(1)持久化对象在整个hibernate框架中运行,一共有四种不同的状态产生:
我们从三个方面进行比较:A)位于session缓存内外;B)是否有与数据库交互能力;C)OID是否有值
A)临时状态
就是通过关健字new创建出来的对象
session缓存【外】
不能与数据库进行交互
无OID值,此时hibernate框架没有为customer对象分配OID值
B)持久化状态【重要】
session缓存【内】
能与数据库进行交互
有OID值,此时hibernate框架根据OID生成策略,自动产生id值,通过setId()方法,传入到持久化对象中
C)游离状态
session缓存【外】
不能与数据库进行交互
有OID值,该OID值是原来持久化对象留下来的值
D)删除状态
session缓存【外】
不能与数据库进行交互
有OID值,该OID值是原来持久化对象留下来的值
参见<<PPT第7,8,9页>>
(2)测试addCustomer()和findCustomerById()演示上述四种不同的状态产生
(3)curd方法使用的细节
A)save()方法细节
1)解析映射文件,并检查正确性
2)根据OID生成策略,hibernate为对象分配值
3)动态生成对应的SQL语句,暂未执行,就时也叫计划执行一条SQL命令
*B)update()方法细节
>>持久化对象和游离对象都可以操作update()方法
>>当update()方法关联一个游离对象时,如果这时Session缓存中已经存在相同OID的持久化对象, 会抛出异常
>>当update()方法关联一个游离对象时,如果在数据库中不存在相应的记录,也会抛出异常.
>>Session缓存特有的快照功能,即自动更新
>>save()方法 + update()方法 = saveOrUpdate()方法
C)get() 和 load() 方法
load()方法如果找到了,返回该对象;如果找不到,抛异常java.lang.ObjectNotFoundException
get()方法如果找到了,返回该对象;如果找不到,抛异常java.lang.NullPointerException
这二个方法的查找策略也不同,第四天再讲。
D)持久化对象和游离对象都可以操作delete()方法
只要调用delete()方法,对象就会进入删除状态
二)映射持久化对象的标识符
(1)Java中采用什么来区别同一个类的不同对象?
通过hashCode()来区分同一个类的不同对象
(2)表中采用什么来区别不同记录
通过主键来区别不同记录
(3)Hibernate中采用什么来区别Session一级缓存中的持久化对象?
通过OID来区别Session一级缓存中的持久化对象
(4)表中有哪些字段适合作主键?
A)【单个、组合】自然主健:具有业务含义的字段做主键,叫自然主健
B)【单个】代理主健:无任何业务含义的字段做主键,代理主键
*(5)hibenate内置主健生成策略:
我们从三个方面进行比较:A)主键类型;B)是否依赖于底层数据库;C)多线程情况下是否安全;
>>increment
int/long/short
不需要依赖于底层数据库
不能在多线程下运行
争对代理主健
>>identity
int/long/short
需要依赖于底层数据库,在MySQL中,一定要加上auto_increment关健字
能在多线程下运行
争对代理主健
>>native【重要】
如果底数据库是MySQL或SQLServer等支持自动增长id的数据库,选用identity
如果底数据库是Oracle等不支持自动增长id的数据库,选用sequence
争对代理主健
>>uuid
只能是字符串类型(varchar/String)
不需要依赖于底层数据库
能在多线程下运行
id值,所占空间相对整型而言,较大
>>sequence【专用于oracle数据库,学完oracle再用】
>>assigned
与业务字段同类型
不需要依赖于底层数据库
不能在多线程下运行
争对自然主键
>>composite-id
与业务字段同类型
不需要依赖于底层数据库
不能在多线程下运行
争对多个自然主键
需要实现序列化接口
参见<<PPT第24页>>
三)【单向】多对一【客户(id/name/age/des) vs 订单(id/orderno/price/time)】
order.java
private Integer id;//与记录的主键一一对应
private String orderno;
private Integer price;
private Timestamp time;//下订单时间
private Customer customer;//关联属性
Order.hbm.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- hibernate映射文件 --> <hibernate-mapping package="cn.itcast.web.hibernate.many2one_single"> <class name="Order" table="ORDERS"> <id name="id" column="ID"> <generator class="native"/> </id> <property name="orderno" column="ORDERNO"/> <property name="price" column="PRICE"/> <property name="time" column="TIME"/> <!-- 映射关联属性 name:表示Order类的关联属性 column:orders表的外健 cascade:表示当操作Order对象时,级联Order对象所关联的其它对象 常用的取值如下: save-update:表示级联保存和更新 delete : 表示级联删除 all : save-update + delete 的所有功能 --> <many-to-one name="customer" column="customers_id" /> </class> </hibernate-mapping>
1)先保存1客户,再保存2订单-----3条SQL
2)先保存2订单,再保存1客户-----5条SQL
3)只保存2订单,级联保存1客户【cascade="save-update"】
4)删除订单,级联删除客户【cascade="delete/all"】
5)只删除订单,不级联删除客户
参见<<PPT第43页>>
四)【单向】一对多【客户 vs 订单】
Customer.java
private Integer id;
private String name;
private Integer age;
private String des;
private Set<Order> orderSet = new HashSet<Order>();//关联属性
Customer.hbm.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- hibernate映射文件 --> <hibernate-mapping package="cn.itcast.web.hibernate.one2many_double"> <class name="Customer" table="CUSTOMERS"> <id name="id" column="ID"> <generator class="native"/> </id> <property name="name" column="NAME"/> <property name="age" column="AGE"/> <property name="des" column="DES"/> <!-- 映射关联属性 name表示Customer类的关联属性 table表示Customer类对应的Order表名 column表示orders表的外健 class表示Order的类型 --> <set name="orderSet" table="ORDERS" cascade="all"> <key column="CUSTOMERS_ID"/> <one-to-many class="Order"/> </set> </class> </hibernate-mapping>
1)只保存客户,级联保存订单
2)只更新客户,级联更新订单
3)只删除客户,级联删除订单
*五)【双向】一对多【客户 vs 订单】
1)增加1个客户,级联增加3个订单
2)查询和修改1个客户,级联查询和修改3个订单
3)删除1个客户,级联删除3个订单
六)动手练习
【需求】
Student(id编号/name姓名/gender性别) vs Phone(id编号,no手机号码,address归属地)
Student(单方)vs Phone(多方)
1)保存Student,级联保存Phone
2)删除Student,级联删除Phone
3)更新Student,级联更新Phone
public class StudentDao {
public void saveStudent() {
Student student = new Student("貂蝉", "女");
Phone phone1 = new Phone("1234", "三国");
Phone phone2 = new Phone("1212", "三国");
student.getPhoneset().add(phone1);
student.getPhoneset().add(phone2);
// phone1.setStudent(student);
// phone2.setStudent(student);
Session session = DBUtils.getFactory().openSession();
Transaction transaction = session.beginTransaction();
session.save(student);
transaction.commit();
session.close();
}
public Student getStudent(int stu_id) {
Student student = new Student();
Session session = DBUtils.getFactory().openSession();
student = (Student) session.get(Student.class, stu_id);
return student;
}
public void delstudent(int stu_id) {
Session session = DBUtils.getFactory().openSession();
Transaction transaction = session.beginTransaction();
Student student = (Student) session.get(Student.class, 3);
session.delete(student);
transaction.commit();
session.close();
}
public void update(int stu_id) {
Session session = DBUtils.getFactory().openSession();
Transaction transaction = session.beginTransaction();
Student student = (Student) session.get(Student.class, stu_id);
student.setName("大乔");
for (Phone phone : student.getPhoneset()) {
phone.setNumber(phone.getNumber() + "1");
}
transaction.commit();
session.close();
}
}