Java第三阶段之Hibernate4操作对象、映射类型、映射继承、映射关系、检索策略
五Hibernate 通过session操作对象
Session接口是Hibernate向应用程序提供的操纵数据库的最主要接口,其提供有基本的保存、更新、删除和加载Java对象的方法。
Session具有一个缓存,位于缓存中的对象称为持久化对象,其与数据表中相关记录相对应;其中,Session对象能够在某些时间点,按照缓存中对象的变化来执行对应SQL语句,以同步更新数据库,该过程被称为刷新缓存(flush)。
站在持久化的角度来看,Hibernate将对象分为四种状态:持久化状态、临时状态、游离状态和删除状态,Session的特定方法能使对象从一个状态转换到另一个状态。
1session缓存概念
1Session缓存
概念:在Session接口的实现中包含一系列的Java集合,这些集合构成Session缓存。
作用:Session缓存可减少Hibernate应用程序访问数据库的频率,因为只要Session实例没有结束生命周期且没有清理缓存,则存放在其缓存中的对象也不会消失。
其中,Session缓存的基本原理测试代码如下所示:
// 注意:只会向数据库发送一条SQL语句
News news1 = (News) session.get(News.class, 1);
System.out.println(news1);
News news2 = (News) session.get(News.class, 1);
System.out.println(news2);
System.out.println(news1 == news2); // true
1.1 flush缓存
作用: Session按照缓存中对象的属性变化来同步更新数据库中的表记录。
实现:刷新缓存的时间点为session.flush(); 或 transaction.commit()。
比较: Session对象的flush()方法可能会执行SQL语句,但不提交事务;而Transaction对象的commit()方法先调用flush()方法,再提交事务(将对数据库的操作永久保存)。
设定刷新缓存的时间点:可以调用Session对象的setFlushMode()方法显式设定刷新缓存的时间点,具体模式
注意:在未提交事务或显式调用Session对象flush()方法,也可能会进行缓存刷新操作,具体如下:
执行HQL或QBC查询时:若缓存中持久化对象的属性发生变化,则会先刷新缓存,以保证查询结果能够反映持久化对象的最新状态;
执行save()方法保存对象时:若对象使用native生成器生成OID,则执行保存操作时,会立即执行刷新操作以保证对象的ID是存在的。
1.2refresh缓存
作用:强制发送SELECT语句,以使Session缓存中对象的状态和数据表中对应的记录保持一致。
注意:MySQL数据库的默认事务隔离级别为“REPEATABLE READ”,需要手动修改为“READ COMMITED”。
1.3 clear缓存
作用:Session对象的clear()方法可以清除Session缓存中的所有缓存对象。
2. 数据库的隔离级别
数据库的隔离性是指隔离并发运行各个事务的能力,而隔离级别是指一个事务与其他事务的隔离程度;隔离级别越高,数据一致性就越好,但并发性越弱。
2.1 并发问题概述
对于同时运行的多个事务,当这些事务访问数据库中相同数据时,如果没有采取必要的隔离机制,会导致各种并发问题,如下:
脏读:对于两个事务T1和T2,T1读取了已经被T2更新但还没有被提交的字段后,若T2回滚,T1读取的内容就是临时且无效的;
不可重复读:对于两个事务T1和T2,T1读取一个字段后,T2更新了该字段;之后T1再次读取同一个字段时值发生变化;
幻读:对于两个事务T1和T2,T1从一个表中读取了一个字段后,T2在该表中插入一些新的行;之后,如果T1再次读取同一个表,就会多出几行。
2.2 事务隔离级别
数据库提供的四种事务隔离级别,分别是:
其中,Oracle 支持“READ COMMITED”(默认)和“SERIALIZABLE”两种事务隔离级别,而MySQL支持四种事务隔离级别,默认为“READ COMMITED”。
2.3 在MySQL中设置隔离级别
在MySQL数据库中,每启动一个程序就会获得一个单独的数据库连接,每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。
查看当前的隔离级别:SELECT @@tx_isolation;
设置当前MySQL连接的隔离级别:set transaction isolation level read committed;
设置当前MySQL数据库的隔离级别:set global transaction isolation level read committed。
2.4 在Hibernate中设置隔离级别
JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate中可通过配置其hibernate.connection.isolation属性的方式来设置事务的隔离级别,具体说明如下:
<!-- 1). 配置数据库的事务隔离级别为:READ UNCOMMITED -->
<property name="hibernate.connection.isolation">1</property>
<!-- 2). 配置数据库的事务隔离级别为:READ COMMITED -->
<property name="hibernate.connection.isolation">2</property>
<!-- 3). 配置数据库的事务隔离级别为:REPEATABLE READ -->
<property name="hibernate.connection.isolation">4</property>
<!-- 4). 配置数据库的事务隔离级别为:SERIALIZEABLE -->
<property name="hibernate.connection.isolation">8</property>
3. 持久化对象的状态
站在持久化的角度,Hibernate把对象分为四种状态:持久化状态、临时状态、游离状态、删除状态;Session的特定方法能使对象从一个状态转换到另一个状态。
3.1 临时对象(Transient)
在使用代理主键的情况下,OID通常为null;
不处于Session缓存中;
在数据库中没有对应的记录。
3.2 持久化对象(Persist)
OID不为null;
位于Session缓存中;
若在数据库中已经有与其对应的记录,持久化对象和数据库中的相关记录对应;
Session 在flush缓存时,会根据持久化对象的属性变化,来同步更新数据库;
在同一个Session实例的缓存中, 数据库表中每条记录只对应唯一的持久化对象。
3.3 删除对象(Removed)
在数据库中没有和其OID对应的记录;
不再处于Session缓存中;
一般情况下,应用程序不该再使用被删除的对象。
3.4 游离对象(Detached)
OID不为null;
不再处于Session缓存中;
一般情况下,游离对象是由持久化对象转变而来,在数据库中可能还存在与其对应的记录。
3.5对象状态转换图
临时状态(transient):刚用 new 语句创建,还没有被持久化,并且不处于 Sesssion 的缓存中。处于临时状态 的 Java 对象被称为临时对象。
持久化状态(persistent):已经被持久化,并且加入到 Session 的缓存中。处于持久化状态的 Java 对象被称为 持久化对象。
删除状态(removed):不再处于 Session 的缓存中,并且 Session 已经计划将其从数据库中删除。处于删除状 态的 Java 对象被称为删除对象。
游离状态(detached):已经被持久化,但不再处于 Session 的缓存中。处于游离状态的 Java 对象被称为游离对象。
新建项目Hibernate05
->StudentTest.java
package com.java1234.service;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.java1234.model.Class;
import com.java1234.model.Student;
import com.java1234.util.HibernateUtil;
public class StudentTest {
public static void main(String[] args) {
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
Class c1=new Class(); // 临时对象1
c1.setName("08计本");
Class c2=new Class(); // 临时对象2
c2.setName("09计本");
session.save(c1); // 持久化对象
session.save(c2); // 持久化对象
session.delete(c2); // 删除对象//只是会删除数据表中对应的数据,
session.getTransaction().co mmit(); // 提交事务//提交完事务后他才更新到数据表中
session.close(); // 关闭session
System.out.println(c1.getName()); // 游离对象
System.out.println(c2.getName()); // 删除对象
}
}
->执行结果:
“Hibernate:insert into t_class(className) values(?)”
“Hibernate:insert into t_class(className) values(?)”
“Hibernate:delete from t_class where classId=?”
删除了两个对象依然可以打印出来
2Session 常用方法讲解
1,save()方法 将一个临时对象转变成持久化对象;
2,load()方法 VS get()方法 都是根据 OID 从数据库中加载一个持久化对象。
区别 1:假如数据库中不存在与 OID 对应的记录,Load()方法会抛出异常,而 get()方法返回 null;
区别 2:load 方法默认采用延迟加载策略,get 方法采用立即检索策略;
3,update()方法 将一个游离对象转变为持久化对象;
4,saveOrUpdate()方法 包含了 save()和 update()方法;
5,merge()方法,合并对象;
6,delete()方法,删除对象;
1,save()方法 将一个临时对象转变成持久化对象;
4.1 save()与persist()方法
/**
* Session对象的save()方法:
* 1). 将临时对象加入Session缓存中,使其转变为持久化对象;
* 2). 选用映射文件指定的标识符生成器,为持久化对象分配唯一的OID;
* 3). 在flush缓存时,会发送一条INSERT语句;
* 4). 在使用代理主键的情况下,通过setId()方法为临时对象设置OID是无效的;
* 5). 持久化对象的OID不能被随意修改,因其维持着持久化对象与数据库记录的对应关系。
*
* Session对象的persist()方法:也会执行INSERT操作;
* 与save()方法的不同之处:当临时对象的OID不为空时,该方法将抛出异常。
*/
@Test
public void testSaveAndPersist() {
News news = new News(null, "qiaobc", "qiaobei", new Date());
news.setId(1001); // 为临时对象设置OID是无效的
System.out.println(news);
// session.persist(news);
session.save(news);
System.out.println(news);
// news.setId(1002); // 持久化对象的OID不能修改
}
2,load()方法 VS get()方法 都是根据 OID 从数据库中加载一个持久化对象。
区别 1:假如数据库中不存在与 OID 对应的记录,Load()方法会抛出异常,而 get()方法返回 null;
区别 2:load 方法默认采用延迟加载策略,get 方法采用立即检索策略;
4.2 get()与load()方法
/**
* Session对象的get()与load()方法:均可根据OID从数据库中加载一个持久化对象
* 1). 执行get()方法时,立即加载对象;
* 而执行load()方法时,延迟加载对象,即若不使用该对象,则不会立即查询,而是返回一个代理对象;
* 2). load()方法可能会抛出LazyInitializationException异常:在需要初始化代理对象前关闭Session对象;
* 3). 若数据表中没有与OID对应的记录,则get()方法返回null;
* 而load()方法,若不使用该对象的任何属性则没问题,若需要初始化则抛出ObjectNotFoundException异常。
*/
@Test
public void testGet() {
News news1 = (News) session.get(News.class, 10);
System.out.println(news1); // 持久化状态
session.close(); // 游离状态
System.out.println(news1);
}
@Test
public void testLoad() {
News news2 = (News) session.load(News.class, 1);
// 若不使用,则返回代理对象com.qiaobc.hibernate.entities.News_$$_javassist_0
System.out.println(news2.getClass().getName());
session.close(); // 游离状态
System.out.println(news2); // 抛出LazyInitializationException异常
}
3,update()方法 将一个游离对象转变为持久化对象;
4.3 update()方法
/**
* Session对象的update()方法:
* 1). 更新持久化对象不需要显式调用update()方法,因为事务提交时会flush缓存;
* 2). 更新游离对象需要显式调用update()方法,将其转变为持久化对象;
*
* 注意:
* 1). 无论要更新的游离对象和数据表的记录是否一致,均会发送UPDATE语句;
* 当Hibernate与触发器协同工作时,可在*.hbm.xml文件的class节点
* 设置select-before-update=true以确保不盲目发送UPDATE语句;
* 2). 当 update()方法关联一个游离对象时,如果在数据库中不存在相应的记录,抛出异常;
* 3). 当 update()方法关联一个游离对象时,如果在Session缓存中已经存在相同OID的持久化对象,抛出异常;
*/
@Test
public void update1() {
News news = (News) session.get(News.class, 1);
news.setAuthor("SUN");
session.update(news); // 若更新持久化对象不需要显式调用update()方法
}
@Test
public void update2() {
News news = (News) session.get(News.class, 1);
transaction.commit();
session.close();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
news.setAuthor("SUN"); // 此时news为游离对象
session.update(news);
}
4,saveOrUpdate()方法 包含了 save()和 update()方法;
4.4 saveOrUpdate()方法
/**
* Session对象的saveOrUpdate()方法:临时对象执行保存操作,游离对象执行更新操作。
* 1). 判定对象为临时对象的标准:Java对象的OID是否为null;
* 2). 了解:若Java对象的OID取值等于映射文件中id节点unsaved-value属性值,则其也为临时对象。
*/
@Test
public void testSaveOrUpdate() {
// OID不为空,执行更新操作;若OID对应的记录不存在,则抛出StaleStateException异常。
News news1 = new News(10, "qiaobc1", "qiaobei1", new Date());
session.saveOrUpdate(news1);
// OID为空,执行保存操作
News news2 = new News(null, "qiaobc", "qiaobei", new Date());
session.saveOrUpdate(news2);
}
5,merge()方法,合并对象;
4.5 merge()方法
6,delete()方法,删除对象;
4.6 delete()方法
/**
* Session对象的delete()方法:既可以删除一个游离对象,也可以删除一个持久化对象
* 1). 只要OID与数据表中记录对应,即执行删除操作;无对应记录则抛出异常;
* 2). 通过设置hibernate.use_identifier_rollback=true,使删除对象时置OID=null;
*/
@Test
public void testDelete() {
News news = new News();
news.setId(5);
session.delete(news); // 删除游离对象
News news2 = (News) session.get(News.class, 6);
session.delete(news2); // 删除持久化对象
// 配置前:News [id=6, title=qiaobc, author=qiaobei, date=2017-02-20 17:10:35.0]
// 配置后:News [id=null, title=qiaobc, author=qiaobei, date=2017-02-20 17:10:35.0]
System.out.println(news2);
}
4.7 evict()方法
/**
* Session对象的evict()方法:从缓存中将持久化对象移除
*/
@Test
public void testEvict() {
News news1 = (News) session.get(News.class, 1);
News news2 = (News) session.get(News.class, 2);
news1.setAuthor("No.1");
news2.setAuthor("No.2");
session.evict(news2); // 移除news2对象,不再更新该对象
}
以下是完整的例子:
新建项目Hibernate05-02
->Class Student
->StudentTest.java
package com.java1234.service;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Class;
import com.java1234.model.Student;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testSaveClassAndStudent() {
Class c=new Class();
c.setName("08计本");
Student s1=new Student();
s1.setName("张三");
s1.setC(c);
Student s2=new Student();
s2.setName("李四");
s2.setC(c);
session.save(s1);
session.save(s2);
}
/*
执行结果:
Hibrenate:insert into t_class (className) values(?)
Hibrenate:insert into t_class (stuName,classId) values(?,?)
Hibrenate:insert into t_class (stuName,classId) values(?,?)
*/
@Test
public void testLoadClass(){
// Class c=(Class)session.load(Class.class, Long.valueOf(2)); //2是不存在的,输出异常
Class c=(Class)session.load(Class.class, Long.valueOf(1));
System.out.println(c.getStudents());//延迟加载,要用到c时才会去加载,在此之前c都是代理类
}
@Test
public void testGetClass(){
// Class c=(Class)session.get(Class.class, Long.valueOf(2));//2是不存在的,输出selectXXXNull
Class c=(Class)session.get(Class.class, Long.valueOf(1));
System.out.println(c.getStudents());//立即检索
}
@Test
public void testUpdateClass(){//游离状态,即持久化对象后,将session关闭变为游离态
Session session1=sessionFactory.openSession();
session1.beginTransaction();
Class c=(Class)session1.get(Class.class, Long.valueOf(1));
session1.getTransaction().commit(); // 提交事务
session1.close();
Session session2=sessionFactory.openSession();
session2.beginTransaction();
c.setName("08计算机本科2");
session2.update(c); //将一个游离对象转变为持久化对象
session2.getTransaction().commit(); // 提交事务
session2.close();
}
@Test
public void testSaveOrUpdateClass(){
Session session1=sessionFactory.openSession();
session1.beginTransaction();
Class c=(Class)session1.get(Class.class, Long.valueOf(1));
session1.getTransaction().commit(); // 提交事务
session1.close();
Session session2=sessionFactory.openSession();
session2.beginTransaction();
c.setName("08计算机本科3");
Class c2=new Class();
c2.setName("09计算机本科3");
session2.saveOrUpdate(c);
session2.saveOrUpdate(c2);
session2.getTransaction().commit(); // 提交事务
session2.close();
}
@Test
public void testMergeClass(){
Session session1=sessionFactory.openSession();
session1.beginTransaction();
Class c=(Class)session1.get(Class.class, Long.valueOf(1));
session1.getTransaction().commit(); // 提交事务
session1.close();
Session session2=sessionFactory.openSession();
session2.beginTransaction();
Class c2=(Class)session2.get(Class.class, Long.valueOf(1));
c.setName("08计算机本科4");
session2.merge(c);
session2.getTransaction().commit(); // 提交事务
session2.close();
}
@Test
public void testDeleteStudent(){
Student student=(Student)session.load(Student.class, Long.valueOf(1));
session.delete(student);
}
}
3. Hibernate调用存储过程
- Hibernate调用存储过程
4. Hibernate与触发器协同工作
六Hibernate 映射类型
一基本类型映射
新建项目Hibernate06
->新建model Book.java
package com.java1234.model;
import java.sql.Blob;
import java.util.Date;
public class Book {
private int id;
private String bookName; // 图书名称
private float price; // 图书价格
private boolean specialPrice; // 是否是特价
private Date publishDate; // 发布日期
private String author; // 作者
private String introduction; // 简介
private Blob bookPic; // 图书图片
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public boolean isSpecialPrice() {
return specialPrice;
}
public void setSpecialPrice(boolean specialPrice) {
this.specialPrice = specialPrice;
}
public Date getPublishDate() {
return publishDate;
}
public void setPublishDate(Date publishDate) {
this.publishDate = publishDate;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getIntroduction() {
return introduction;
}
public void setIntroduction(String introduction) {
this.introduction = introduction;
}
public Blob getBookPic() {
return bookPic;
}
public void setBookPic(Blob bookPic) {
this.bookPic = bookPic;
}
}
->新建Book.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Book" table="t_book">
<id name="id" column="bookId">
<generator class="native"></generator>
</id>
<property name="bookName" column="bookName" length="40"></property>
<property name="price" column="price" type="float"></property>
<property name="specialPrice" column="specialPrice" type="boolean"></property>
<property name="publishDate" column="publishDate" type="date"></property>
<property name="author" column="author" length="20"></property>
<property name="introduction" column="introduction" type="text"></property>
<property name="bookPic" column="bookPic" type="blob"></property>
</class>
</hibernate-mapping>
->新建hibernate.cfg.xml加上下面这句
<mapping resource="com/java1234/model/Book.hbm.xml"/>
->更新驱动mysql-connector-java-5.1.26
->新建BookTest.java
package com.java1234.service;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Blob;
import java.text.SimpleDateFormat;
import org.hibernate.LobHelper;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.java1234.model.Book;
import com.java1234.util.HibernateUtil;
public class BookTest {
public static void main(String[] args) throws Exception{
SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
Session session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
Book book=new Book();
book.setBookName("java编程思想");
book.setPrice(100);
book.setSpecialPrice(true);
book.setPublishDate(new SimpleDateFormat("yyyy-MM-dd").parse("2018-1-1"));//用SimpleDateFormat生成格式化数据
book.setAuthor("埃克尔");
book.setIntroduction("简介...");
//图片怎么放呢》用hibernate4提供的接口LobHelper
LobHelper lobHelper=session.getLobHelper();
InputStream in=new FileInputStream("c://java编程思想.jpg");//文件输入流
Blob bookPic=lobHelper.createBlob(in, in.available());//第二个参数是长度
book.setBookPic(bookPic);
session.save(book);
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
}
->执行结果:
Hibernate:insert into t_book(bookName,price,specialPrice,…)
表中也插入成功了
二集合类型映射
1,Set 无序 元素不可重复
2,List 有序 元素可重复
3,Bag 无序 元素可重复
4,Map 键值对
新建项目Hibernate06-02
Set
一个类生成了两个表
->新建Student.java
package com.java1234.model;
import java.util.Set;
public class Student {
private long id;
private String name;
private Set<String> images;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<String> getImages() {
return images;
}
public void setImages(Set<String> images) {
this.images = images;
}
}
->新建Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<set name="images" table="t_image">
<key column="studentId"></key>
<element column="imageName" type="string"></element>
</set>
</class>
</hibernate-mapping>
->新建StudentTest.java
package com.java1234.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Student;
import com.java1234.model.Student2;
import com.java1234.model.Student3;
import com.java1234.model.Student4;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testSetSave(){
Set<String> imageSet=new HashSet<String>();
imageSet.add("image1.png");
imageSet.add("image2.png");
imageSet.add("image3.png");
imageSet.add("image3.png");
Student s1=new Student();
s1.setImages(imageSet);
session.save(s1);
}
@Test
public void testSetFetch(){
Student student=(Student)session.get(Student.class, Long.valueOf(1));
Iterator it=student.getImages().iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
->启动程序:
“Hibernate:insert into t_student(stuName) values(?)”
“Hibernate:insert into t_image(studentId,imageName) values(?,?)”
“Hibernate:insert into t_image(studentId,imageName) values(?,?)”
“Hibernate:insert into t_image(studentId,imageName) values(?,?)”
表结构建好了,表t_student和t_image呈现多关联关系
表t_student中新增一条数据,学号为1,姓名为空
t_image中新增三条记录
->遍历的话,显示selectXX,遍历出来了
List
一个类生成了两个表
->新建Student2.java
package com.java1234.model;
import java.util.List;
public class Student2 {
private long id;
private String name;
private List<String> images;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
}
->新建Student2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student2" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<list name="images" table="t_image2">
<key column="studentId"></key>
<list-index column="imageIndex"></list-index>//集合的话,需要有索引,这里多一列
<element column="imageName" type="string"></element>
</list>
</class>
</hibernate-mapping>
->新建StudentTest.java
package com.java1234.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Student;
import com.java1234.model.Student2;
import com.java1234.model.Student3;
import com.java1234.model.Student4;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testListSave(){
List<String> imageList=new ArrayList<String>();
imageList.add("image1.png");
imageList.add("image2.png");
imageList.add("image3.png");
imageList.add("image3.png");
Student2 s2=new Student2();
s2.setImages(imageList);
session.save(s2);
}
@Test
public void testListFetch(){
Student2 student2=(Student2)session.get(Student2.class, Long.valueOf(2));
Iterator it=student2.getImages().iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
->启动程序:
“Hibernate:insert into t_student(stuName) values(?)”
“Hibernate:insert into t_image2(studentId,imageIndex,imageName) values(?,?)”
“Hibernate:insert into t_image2(studentId,imageIndex,imageName) values(?,?)”
“Hibernate:insert into t_image2(studentId,imageIndex,imageName) values(?,?)”
“Hibernate:insert into t_image2(studentId,imageIndex,imageName) values(?,?)”
表结构建好了,表t_student和t_image呈现关联关系
->遍历的话,显示selectXX,遍历出来了
Bag
一个类生成了两个表
->新建Student3.java
package com.java1234.model;
import java.util.List;
public class Student3 {
private long id;
private String name;
private List<String> images;//用list模拟
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
}
->新建Student3.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student3" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<idbag name="images" table="t_image3">
<collection-id type="long" column="imageId">
<generator class="increment"></generator>
</collection-id>
<key column="studentId"></key>
<element column="imageName" type="string"></element>
</idbag>
</class>
</hibernate-mapping>
->新建StudentTest.java
package com.java1234.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Student;
import com.java1234.model.Student2;
import com.java1234.model.Student3;
import com.java1234.model.Student4;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testBagSave(){
List<String> imageList=new ArrayList<String>();//用List来模拟
imageList.add("image1.png");
imageList.add("image2.png");
imageList.add("image3.png");
imageList.add("image3.png");
Student3 s3=new Student3();
s3.setImages(imageList);
session.save(s3);
}
@Test
public void testBagFetch(){
Student3 student3=(Student3)session.get(Student3.class, Long.valueOf(3));
Iterator it=student3.getImages().iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
->启动程序:
“Hibernate:insert into t_student(stuName) values(?)”
“Hibernate:select max(imageId) from t_image3”
“Hibernate:insert into t_image3(studentId,imageId,imageName) values(?,?)”
“Hibernate:insert into t_image3(studentId,imageId,imageName) values(?,?)”
“Hibernate:insert into t_image3(studentId,imageId,imageName) values(?,?)”
“Hibernate:insert into t_image3(studentId,imageId,imageName) values(?,?)”
表结构建好了,表t_student和t_image呈现关联关系
->遍历的话,显示selectXX,遍历出来了
Bag
一个类生成了两个表
->新建Student4.java
package com.java1234.model;
import java.util.Map;
public class Student4 {
private long id;
private String name;
private Map<String,String> images;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getImages() {
return images;
}
public void setImages(Map<String, String> images) {
this.images = images;
}
}
->新建Student4.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student4" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<map name="images" table="t_image4">
<key column="studentId"></key>
<map-key column="imageKey" type="string"></map-key>
<element column="imageName" type="string"></element>
</map>
</class>
</hibernate-mapping>
->新建StudentTest.java
package com.java1234.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Student;
import com.java1234.model.Student2;
import com.java1234.model.Student3;
import com.java1234.model.Student4;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testMapSave(){
Map<String,String> imageMap=new HashMap<String,String>();
imageMap.put("i1", "image1.png");
imageMap.put("i2", "image2.png");
imageMap.put("i3", "image3.png");
imageMap.put("i4", "image4.png");//key不能重复
Student4 s4=new Student4();
s4.setImages(imageMap);
session.save(s4);
}
@Test
public void testMapFetch(){
Student4 student4=(Student4)session.get(Student4.class, Long.valueOf(4));
Map<String,String> imageMap=student4.getImages();
Set keys=imageMap.keySet();
Iterator it=keys.iterator();
while(it.hasNext()){
String key=(String)it.next();
System.out.println(key+":"+imageMap.get(key));//如何取到键值对
}
}
}
->启动程序:
“Hibernate:insert into t_student(stuName) values(?)”
“Hibernate:insert into t_image4(studentId,imageKey,imageName) values(?,?)”
“Hibernate:insert into t_image4(studentId,imageKey,imageName) values(?,?)”
“Hibernate:insert into t_image4(studentId,imageKey,imageName) values(?,?)”
“Hibernate:insert into t_image4(studentId,imageKey,imageName) values(?,?)”
表结构建好了,表t_student和t_image呈现关联关系
->遍历的话,显示selectXX,遍历出来了
七Hibernate 映射继承
对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。而Hibernate的继承映射可以理解持久化类之间的继承关系,其支持subclass、joined-subclass和union-subclass共三种继承映射策略。
- 采用subclass元素的继承映射
主要特点:
(1). 对于继承关系中的父类和子类使用同一张数据表;
(2). 需要在该数据表中添加辨别者列以区分记录所属哪个类的实例;
(3). 所有子类定义的字段均不能添加非空约束。
对象关系映射文件示例如下:
< class name=“Person” table=“PERSONS” discriminator-value=“PERSON”>
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<!-- 配置辨别者列 -->
<discriminator column="TYPE" type="string"></discriminator>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property>
<!-- 配置继承映射 -->
<subclass name="Student" discriminator-value="STUDENT">
<property name="school" column="SCHOOL" type="string"></property>
</subclass>
</class>
单元测试:
/**
* 缺点:
* 1. 使用了辨别者列;
* 2. 子类独有的字段不能添加非空约束;
* 3. 若继承层次较深,则数据表的字段也会较多。
*/
/**
* 查询操作
* 1. 查询父类记录,只需要查询一张数据表;
* 2. 查询子类记录,也只需要查询一张数据表。
*/
@Test
public void testQuery() {
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size());
List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
/**
* 插入操作
* 1. 对于子类对象只需将记录插入到一张数据表中;
* 2. 辨别者列由Hibernate自动维护。
*/
@Test
public void testSave() {
Person person = new Person();
person.setName("qiaobc");
person.setAge(23);
Student student = new Student();
student.setName("qiaob");
student.setAge(22);
student.setSchool("WHUT");
session.save(person);
session.save(student);
}
-
采用joined-subclass元素的继承映射
主要特点:
(1). 对于继承关系中的父类和子类各使用一张数据表;
(2). 父类实例保存在父类表中,子类实例由父类表和子类表共同存储;
(3). 无须使用辩别者列,但需要为每个子类使用key元素映射共有主键;
(4). 子类的独有属性可以添加非空约束,因为子类独有属性和父类属性没有保存在一张数据表中。
对象关系映射文件核心代码示例如下:
单元测试:
/**
* 优点:
* 1. 不需要使用辨别者列;
* 2. 子类独有的字段能添加非空约束;
* 3. 没有冗余的字段。
*/
/**
* 查询操作:需要查询多张表
* 1. 查询父类记录,做一个左外连接查询;
* 2. 查询子类记录,做一个内连接查询。
*/
@Test
public void testQuery() {
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size());
List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
/**
* 插入操作
* 1. 对于子类对象至少需要插入到两张数据表中;
*/
@Test
public void testSave() {
Person person = new Person();
person.setName("qiaobc");
person.setAge(23);
Student student = new Student();
student.setName("qiaob");
student.setAge(22);
student.setSchool("WHUT");
session.save(person);
session.save(student);
}
-
采用union-subclass元素的继承映射
主要特点:
(1). 将每一个实体对象映射到一张独立的数据表中;
(2). 子类实例的数据仅保存在子类表中,子类的独有属性可以添加非空约束;
(3). 既不需要使用辩别者列,也无须使用key元素来映射共有主键;
(4). 不可使用identity的主键生成策略,因为同一类继承层次中所有实体类都需要使用同一个主键种子,即多个持久化实体对应记录的主键应该是连续的。
对象关系映射文件核心代码示例如下:
单元测试:
/**
* 优点:
* 1. 不需要使用辨别者列;
* 2. 子类独有的字段能添加非空约束;
*
* 缺点:
* 1. 存在冗余的字段;
* 2. 若更新父表的字段,则更新效率较低。
*/
@Test
public void testUpdate() {
String hql = "UPDATE Person p SET p.age = 20";
session.createQuery(hql).executeUpdate();
}
/**
* 查询操作:需要查询多张表
* 1. 查询父类记录,需把父表和字表记录汇总到一起再做查询,性能稍差;
* 2. 查询子类记录,性能较好。
*/
@Test
public void testQuery() {
List<Person> persons = session.createQuery("FROM Person").list();
System.out.println(persons.size());
List<Student> students = session.createQuery("FROM Student").list();
System.out.println(students.size());
}
/**
* 插入操作:性能不错
*/
@Test
public void testSave() {
Person person = new Person();
person.setName("qiaobc");
person.setAge(23);
Student student = new Student();
student.setName("qiaob");
student.setAge(22);
student.setSchool("WHUT");
session.save(person);
session.save(student);
}
三种继承映射方式对比
一每个具体类对应一个表
意思是抽象类不对应表
新建Hibernate07
->新建Image.java是个父类是抽象的类,它不能实例化
package com.java1234.model;
public abstract class Image {
private int id;
private String imageName;
**private Student student;**//实现多对一
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
->新建Student.java
package com.java1234.model;
import java.util.Set;
public class Student {
private int id;
private String name;
**private Set<Image> images;**
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Image> getImages() {
return images;
}
public void setImages(Set<Image> images) {
this.images = images;
}
}
->新建LifeImage.java
package com.java1234.model;
public class LifeImage extends Image{
}
->新建WorkImage.java
package com.java1234.model;
public class WorkImage extends Image{
}
->新建Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
</class>
</hibernate-mapping>
->新建LifeImage.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="LifeImage" table="t_lifeImage">
<id name="id" column="lifeImageId">
<generator class="native"></generator>
</id>
<property name="imageName" column="imageName"></property>
//多对一,LifeImage是多的一端
<many-to-one name="student" column="stuId" class="com.java1234.model.Student"></many-to-one>
</class>
</hibernate-mapping>
->新建WorkImage.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="WorkImage" table="t_workImage">
<id name="id" column="workImageId">
<generator class="native"></generator>
</id>
<property name="imageName" column="imageName"></property>
<many-to-one name="student" column="stuId" class="com.java1234.model.Student"></many-to-one>
</class>
</hibernate-mapping>
->新建hibernate.cfg.xml
<mapping resource="com/java1234/model/Student.hbm.xml"/>
<mapping resource="com/java1234/model/LifeImage.hbm.xml"/>
<mapping resource="com/java1234/model/WorkImage.hbm.xml"/>
->新建StudentTest .java
package com.java1234.service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Image;
import com.java1234.model.Image2;
import com.java1234.model.Image3;
import com.java1234.model.Student2;
import com.java1234.model.Student3;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testGetAllImages(){
List<Image> imageList=new ArrayList<Image>();
int stuId=1;
List<Image> lifeImageList=(List<Image>)session.createQuery("from LifeImage l where l.student.id="+stuId).list();
imageList.addAll(lifeImageList);
List<Image> workImageList=(List<Image>)session.createQuery("from WorkImage w where w.student.id="+stuId).list();
imageList.addAll(workImageList);
Iterator it=imageList.iterator();
while(it.hasNext()){
Image image=(Image)it.next();
System.out.println(image.getImageName());
}
}
}
}
->执行结果:
“Hibernate:select lifeimage0_.lifeImageId as lifeImage1_0_,lifeImage0_0_”
“Hibernate:select workimage0_.workImageId as workImage1_2_,workImage0_0_”
image1.jpg
image2.jpg
二根类对应一个表
这里的父类是具体的!
->新建Image2.java
package com.java1234.model;
public class Image2 {
private int id;
private String imageName;
private String imageType;//这是一个标识字段
private Student2 student;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public Student2 getStudent() {
return student;
}
public void setStudent(Student2 student) {
this.student = student;
}
public String getImageType() {
return imageType;
}
public void setImageType(String imageType) {
this.imageType = imageType;
}
}
->新建Student2.java
package com.java1234.model;
import java.util.Set;
public class Student2 {
private int id;
private String name;
private Set<Image2> images;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Image2> getImages() {
return images;
}
public void setImages(Set<Image2> images) {
this.images = images;
}
}
->新建LifeImage2.java
package com.java1234.model;
public class LifeImage2 extends Image2{
}
->新建WorkImage2.java
package com.java1234.model;
public class WorkImage2 extends Image2{
}
->Student2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student2" table="t_student2">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
//实现一对多
<set name="images">
<key column="stuId"></key>
<one-to-many class="com.java1234.model.Image2"/>
</set>
</class>
</hibernate-mapping>
->Image2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Image2" table="t_image2">
<id name="id" column="imageId">
<generator class="native"></generator>
</id>
//映射父类的时候,这里要多一个字段,用来辨别
<discriminator column="imageType" type="string"></discriminator>
<property name="imageName" column="imageName"></property>
//实现多对一
<many-to-one name="student" column="stuId" class="com.java1234.model.Student2"></many-to-one>
//在这里把子类都加上!discriminator-value是标识器
<subclass name="com.java1234.model.LifeImage2" discriminator-value="li"></subclass>
<subclass name="com.java1234.model.WorkImage2" discriminator-value="wi"></subclass>
</class>
</hibernate-mapping>
->hibernate.hbm.xml
<mapping resource="com/java1234/model/Student2.hbm.xml"/>
<mapping resource="com/java1234/model/Image2.hbm.xml"/>
->执行结果:
生成两个表,学生表和照片表
->StudentTest.java测试
@Test
public void testGetAllImages2(){
Student2 student2=(Student2)session.get(Student2.class, 1);
Set<Image2> images=student2.getImages();
Iterator it=images.iterator();
while(it.hasNext()){
Image2 image=(Image2)it.next();
System.out.println(image.getImageName());
}
}
->执行结果:
以根类来获取
这种方式获取比较简单
上一种若有多个子类,得获取很多次
三每个类对应一个表
->Student3.java
package com.java1234.model;
import java.util.Set;
public class Student3 {
private int id;
private String name;
private Set<Image3> images;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Image3> getImages() {
return images;
}
public void setImages(Set<Image3> images) {
this.images = images;
}
}
->Image3.java
package com.java1234.model;
public class Image3 {
private int id;
private String imageName;
private Student3 student;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public Student3 getStudent() {
return student;
}
public void setStudent(Student3 student) {
this.student = student;
}
}
->LifeImage3.java
package com.java1234.model;
public class LifeImage3 extends Image3{
}
->WorkImage3.java
package com.java1234.model;
public class WorkImage3 extends Image3{
}
->Student3.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student3" table="t_student3">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<set name="images">
<key column="stuId"></key>
<one-to-many class="com.java1234.model.Image3"/>
</set>
</class>
</hibernate-mapping>
->Image3.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Image3" table="t_image3">
<id name="id" column="imageId">
<generator class="native"></generator>
</id>
<property name="imageName" column="imageName"></property>
//实现多对一
<many-to-one name="student" column="stuId" class="com.java1234.model.Student3"></many-to-one>
//实现子类
<joined-subclass name="com.java1234.model.LifeImage3" table="t_lifeImage3">
<key column="lifeImageId"></key>
</joined-subclass>
<joined-subclass name="com.java1234.model.WorkImage3" table="t_workImage3">
<key column="workImageId"></key>
</joined-subclass>
</class>
</hibernate-mapping>
->配置上hibernate.hbm.xml
->StudentTest.java
@Test
public void testGetAllImages3(){
Student3 student3=(Student3)session.get(Student3.class, 1);
Set<Image3> images=student3.getImages();
Iterator it=images.iterator();
while(it.hasNext()){
Image3 image=(Image3)it.next();
System.out.println(image.getImageName());
}
->执行结果:
每个类都对应着一个表!不管是抽象表还是具体表
八Hibernate 映射关系
域模型:
一个用户对应着一个地址
一个地址对应着一个用户
关系数据模型:
按照主键映射:两表间主键直接对应
按照外键映射:在多对一的基础上,为classid添加唯一约束
Hibernate 一对一映射关系实现
1.按照主键映射
主要策略:指一端的主键生成器使用foreign策略,即根据”对方”的主键来生成自己的主键,同时也是自己的一个外键,本身不能自动生成主键。
User Address
id id
name address
address zipcode
user
t_user t_address
userId addressId(使用别的类的外键,来生成自己的主键,也是自己的外键)
userName address
address zipcode
在使用foreign主键生成器的一端:增加one-to-one元素,并设置其constrained属性为true,即当前持久化类对应数据库表的主键添加一个外键约束,示例代码如下:
<class name="Address" table="t_address">
<id name="id" column="addressId">//主键同时也是外键,是用户表的主键
<generator class="foreign">//使用外键的方式来生成当前主键
<param name="property">user</param>//property属性指定使用当前持久化类的哪一个属性的主键做外键
</generator>
</id>
<property name="address" column="address"></property>
<property name="zipcode" column="zipcode"></property>
//配置一对一映射:需要为其添加外键约束。表明address表的主键是由user表的主键生成的,它们一一对应。
<one-to-one name="user" class="com.java1234.model.User" constrained="true"></one-to-one>
</class>
在不用foreign主键生成器的一端:增加one-to-one元素映射关联属性即可,示例代码如下:
<!-- 配置一对一映射 -->
<one-to-one name="address" class="com.java1234.model.Address" cascade="all"></one-to-one>
全部代码:
<class name="User" table="t_user">
<id name="id" column="userId">
<generator class="native"></generator>
</id>
<property name="name" column="userName"></property>
//实现一对一映射,根据主键来实现
<one-to-one name="address" class="com.java1234.model.Address" cascade="all"></one-to-one>
</class>
新建Hibernate08
->User.java
package com.java1234.model;
public class User {
private int id;
private String name;
private Address address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
->Address.java
package com.java1234.model;
public class Address {
private int id;
private String address;
private String zipcode;
private User user;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
->User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="User" table="t_user">
<id name="id" column="userId">
<generator class="native"></generator>
</id>
<property name="name" column="userName"></property>
//实现一对一映射,根据主键来实现
<one-to-one name="address" class="com.java1234.model.Address" cascade="all"></one-to-one>
</class>
</hibernate-mapping>
->Address.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Address" table="t_address">
<id name="id" column="addressId">//主键同时也是外键,是用户表的主键
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<property name="address" column="address"></property>
<property name="zipcode" column="zipcode"></property>
<one-to-one name="user" class="com.java1234.model.User" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
->UserTest.java
package com.java1234.service;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Address;
import com.java1234.model.Address2;
import com.java1234.model.User;
import com.java1234.model.User2;
import com.java1234.util.HibernateUtil;
public class UserTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testSave1(){
User user=new User();
user.setName("张三");
Address address=new Address();
address.setAddress("某地方");
address.setZipcode("43242");
address.setUser(user);
user.setAddress(address);//相互设置一下
session.save(user);
}
}
->配置hibernate.hbm.xml
->执行结果;
生成一对一的两个表结构,地址表中id既是主键也是外键
“Hibernate:insert into t_user (userName) values(?)”
“Hibernate:insert into t_address (address,zipcode,addressId) values(?,?,?)”
共享主键,所以同时插入了标号为1的记录
2,按照外键映射;
对于基于外键映射的1-1关联关系,其外键可以放在任意一端,但不能两边都使用外键映射。
User Address
id id
name address
address zipcode
user
t_user2 t_address2
userId addressId(使用别的类的外键,来生成自己的主键)
userName address
address zipcode
在需要存放外键的一端:增加many-to-one元素,并设置其unique属性为true来表示1-1关联,示例代码如下:
<!-- 配置多对一映射,并添加唯一性约束 -->
<many-to-one name="address" class="com.java1234.model.Address2" column="addressId" cascade="all" unique="true"></many-to-one>
全部代码:
<class name="User2" table="t_user2">
<id name="id" column="userId">
<generator class="native"></generator>
</id>
<property name="name" column="userName"></property>
//实现多对一,这个表是唯一的
<many-to-one name="address" class="com.java1234.model.Address2" column="addressId" cascade="all" unique="true"></many-to-one>
</class>
在不需存放外键的一端:增加one-to-one元素,且必须使用property-ref属性指定使用被关联实体主键以外的字段作为关联字段,示例代码如下:
<!-- 配置一对一映射 -->
<!-- 若不配置property-ref属性,则在左外连接查询时,将使用被关联实体的主键作为关联字段 -->
<one-to-one name="user" class="com.java1234.model.User2" property-ref="address"></one-to-one>
全部代码:
<class name="Address2" table="t_address2">
<id name="id" column="addressId">
<generator class="native">
</generator>
</id>
<property name="address" column="address"></property>
<property name="zipcode" column="zipcode"></property>
<one-to-one name="user" class="com.java1234.model.User2" property-ref="address"></one-to-one>
</class>
User2.java
package com.java1234.model;
public class User2 {
private int id;
private String name;
private Address2 address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address2 getAddress() {
return address;
}
public void setAddress(Address2 address) {
this.address = address;
}
}
->Address2.java
package com.java1234.model;
public class Address2 {
private int id;
private String address;
private String zipcode;
private User2 user;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public User2 getUser() {
return user;
}
public void setUser(User2 user) {
this.user = user;
}
}
->User2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="User2" table="t_user2">
<id name="id" column="userId">
<generator class="native"></generator>
</id>
<property name="name" column="userName"></property>
//实现多对一,这个表是唯一的
<many-to-one name="address" class="com.java1234.model.Address2" column="addressId" cascade="all" unique="true"></many-to-one>
</class>
</hibernate-mapping>
->Address2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Address2" table="t_address2">
<id name="id" column="addressId">
<generator class="native">
</generator>
</id>
<property name="address" column="address"></property>
<property name="zipcode" column="zipcode"></property>
<one-to-one name="user" class="com.java1234.model.User2" property-ref="address"></one-to-one>
</class>
</hibernate-mapping>
->UserTest.java
@Test
public void testSave2(){
User2 user=new User2();
user.setName("李四");
Address2 address=new Address2();
address.setAddress("某地方2");
address.setZipcode("432422");
address.setUser(user);
user.setAddress(address);//互相设置一下
session.save(user);
}
执行结果 :
user的外键addressid关联了address的主键addressid,unique使得实现一对一
“Hibernate:insert into t_user (userName) values(?)”
“Hibernate:insert into t_address (address,zipcode,addressId) values(?,?,?)”
实现了这样的关联
Hibernate 多对多映射关系实现
多对多的单向
单向的话,通过学生可以获取它选修的课程。但是通过课程不能获取选修这门课程的学生。
Student Course
id id
name name
courses
t_student student_course t_course
stuId student_id courseId
stuName course_id courseName
实现:单向n-n关联关系必须使用中间连接表来实现,示例映射配置代码如下:
<set name="courses" table="student_course" cascade="save-update">
//table:指定中间表。多对多,要借助中间表来实现
<key column="student_id"></key>
//学生课程关联表的关联学生表的一个外键。指定当前持久化类在中间表的外键列的名称
<many-to-many class="com.java1234.model.Course" column="course_id"></many-to-many>
//column指定Set集合中持久化类在中间表的外键列的名称
</set>
新建Hibernate08
->Student.java
package com.java1234.model;
import java.util.HashSet;
import java.util.Set;
public class Student {
private int id;
private String name;
private Set<Course> courses=new HashSet<Course>();//一对多,一个学生选修多门课程
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
->新建Course.java
单向的话,是以学生为主。所以课程 这边就简单了。
package com.java1234.model;
public class Course {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
->Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student" table="t_student">
<id name="id" column="studentId">
<generator class="native"></generator>
</id>
<property name="name" column="studentName"></property>
<set name="courses" table="student_course" cascade="save-update">//多对多,要借助中间表来实现
<key column="student_id"></key>//学生课程关联表的关联学生表的一个外键
<many-to-many class="com.java1234.model.Course" column="course_id"></many-to-many>//另一个外键
</set>
</class>
</hibernate-mapping>
->Course.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Course" table="t_course">
<id name="id" column="courseId">
<generator class="native"></generator>
</id>
<property name="name" column="courseName"></property>
</class>
</hibernate-mapping>
->配置hibernate.hbm.xml
->StudentTest.java
package com.java1234.service;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Course;
import com.java1234.model.Course2;
import com.java1234.model.Student;
import com.java1234.model.Student2;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testSave1(){
Course course1=new Course();
course1.setName("语文");
Course course2=new Course();
course2.setName("数学");
Student student1=new Student();
student1.setName("张三");
student1.getCourses().add(course1);//从学生这边添加课程
student1.getCourses().add(course2);
Student student2=new Student();
student2.setName("李四");
student2.getCourses().add(course1);
student2.getCourses().add(course2);
session.save(student1);//只保存学生,课程会被级联保存
session.save(student2);
}
@Test
public void testLoad1(){
Student student=(Student)session.get(Student.class, 1);
Set<Course> courses=(Set<Course>)student.getCourses();//只能从学生这端去获取课程
Iterator it=courses.iterator();
while(it.hasNext()){
Course c=(Course)it.next();
System.out.println(c.getName());
}
}
}
}
->执行结果:
表t_student(studentId,studentName)
表student_course(studentId,courseId)
表t_course(courseId,courseName)
通过中间表,实现了多对多的关系
->执行结果:对 testSave1进行jUtil单元测试
insert into t_student(studentName) values(?)
insert into t_course(courseName) values(?)
insert into t_course(courseame) values(?)
insert into t_student(studentName) values(?)
insert into student_course (student_id,course_id) values(?,?)
insert into student_course (student_id,course_id) values(?,?)
insert into student_course (student_id,course_id) values(?,?)
insert into student_course (student_id,course_id) values(?,?)
->执行结果:对 testLoad1进行jUtil单元测试
Hibernate:select student0_.studentId as studentI1_2_0,student0_.stu
Hibernate:select courses0_.student_id as student_1_2_0,course0_cour
数学
语文
多对多的双向
Student Course
id id
name name
courses students
t_student student_course2 t_course
stuId student_id courseId
stuName course_id courseName
实现:双向n-n关联关系需要两段都使用集合属性,且必须使用中间连接表来实现。
注意:对于双向n-n关联关系,必须把其中一端的inverse属性设置为true,即放弃维护关联关系,否则会抛出异常。
其中,示例映射配置代码如下:
<set name="courses" table="student_course2" cascade="save-update">//table:指定中间表
<key column="student_id"></key>//指定当前持久化类在中间表的外键列的名称
<many-to-many class="com.java1234.model.Course2" column="course_id"></many-to-many>
//column指定Set集合中持久化类在中间表的外键列的名称
</set>
//需要在两端的任意一端添加inverse=true,否则抛出异常
<set name="students" table="student_course2" inverse="true" >
//inverse是指从学生端来维护这个表的关系
<key column="course_id"></key>//前持久化类在中间表的外键列的名称
<many-to-many class="com.java1234.model.Student2" column="student_id"></many-to-many>
//column指定Set集合中持久化类在中间表的外键列的名称
</set>
->Student2.java
package com.java1234.model;
import java.util.HashSet;
import java.util.Set;
public class Student2 {
private int id;
private String name;
private Set<Course2> courses=new HashSet<Course2>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Course2> getCourses() {
return courses;
}
public void setCourses(Set<Course2> courses) {
this.courses = courses;
}
}
->Course2.java
package com.java1234.model;
import java.util.HashSet;
import java.util.Set;
public class Course2 {
private int id;
private String name;
private Set<Student2> students=new HashSet<Student2>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student2> getStudents() {
return students;
}
public void setStudents(Set<Student2> students) {
this.students = students;
}
}
->Student2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student2" table="t_student2">
<id name="id" column="studentId">
<generator class="native"></generator>
</id>
<property name="name" column="studentName"></property>
<set name="courses" table="student_course2" cascade="save-update">
<key column="student_id"></key>
<many-to-many class="com.java1234.model.Course2" column="course_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
->Course2.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Course2" table="t_course2">
<id name="id" column="courseId">
<generator class="native"></generator>
</id>
<property name="name" column="courseName"></property>
<set name="students" table="student_course2" inverse="true" >
//inverse是指从学生端来维护这个表的关系
<key column="course_id"></key>
<many-to-many class="com.java1234.model.Student2" column="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
->配置hibernate.cfg.xml
->执行结果:
->StudentTest.java
@Test
public void testSave2(){
Course2 course1=new Course2();
course1.setName("语文");
Course2 course2=new Course2();
course2.setName("数学");
Student2 student1=new Student2();
student1.setName("张三");
student1.getCourses().add(course1);//从学生端去添加课程
student1.getCourses().add(course2);
Student2 student2=new Student2();
student2.setName("李四");
student2.getCourses().add(course1);
student2.getCourses().add(course2);
session.save(student1);
session.save(student2);
}
@Test
public void testLoad2(){
Course2 course=(Course2)session.get(Course2.class, 1);
Set<Student2> students=(Set<Student2>)course.getStudents();//通过课程去获取学生
Iterator it=students.iterator();
while(it.hasNext()){
Student2 s=(Student2)it.next();
System.out.println(s.getName());
}
->执行结果:
->执行结果:
张三
李四
九Hibernate检索策略
Hibernate在检索数据时需要保证不浪费内存且具有更高的查询效率。以Class和Student的多对一关联关系为例,当Hibernate从数据库中加载Class对象时,如果同时加载所有关联的Student对象而不需要使用时即白白浪费了许多内存;同时,在查询时应发送尽可能少的SQL语句,以提高查询效率。
1类级别的检索策略
2一对多与多对多关联的检索策略
在对象关系映射文件中,用set元素来配置一对多和多对多关联关系,其具有lazy、fetch和batch-size属性,说明如下。
set元素的lazy属性
set元素的fetch属性
set元素的batch-size属性
该属性用来为延迟检索或立即检索策略设定批量检索的数量,以减少SELECT语句的数目,提高延迟检索或立即检索的运行性能。
3多对一与一对一关联的检索策略
4检索策略小结
类级别和关联级别可选的检索策略及默认的检索策略:
三种检索策略的运行机制:
映射文件中用于设定检索策略的几个属性:
比较Hibernate的三种检索策略:
一检索策略属性 Lazy
Lazy:true(默认) 延迟检索 ;配置在set 端 一对多
Lazy:false 立即检索;set 端 一对多
Lazy:extra 增强延迟检索; set 端 一对多
Lazy:proxy(默认) 延迟检索;many-to-one 多对一
Lazy:no-proxy 无代理延迟检索;many-to-one 多对一 (需要编译时字节码增强)
延迟检索
新建项目Hibernate09 双向的一对多
->Student.java
package com.java1234.model;
public class Student {
private long id;
private String name;
private Class c;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class getC() {
return c;
}
public void setC(Class c) {
this.c = c;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
->Class.java
package com.java1234.model;
import java.util.HashSet;
import java.util.Set;
public class Class {
private long id;
private String name;
private Set<Student> students=new HashSet<Student>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
->Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<many-to-one name="c" column="classId" class="com.java1234.model.Class" cascade="save-update" ></many-to-one>
</class>
</hibernate-mapping>
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="true" >
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->配置hibernate.cfg.xml
->StudentTest.java
package com.java1234.service;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.java1234.model.Class;
import com.java1234.model.Student;
import com.java1234.util.HibernateUtil;
public class StudentTest {
private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
private Session session;
@Before
public void setUp() throws Exception {
session=sessionFactory.openSession(); // 生成一个session
session.beginTransaction(); // 开启事务
}
@After
public void tearDown() throws Exception {
session.getTransaction().commit(); // 提交事务
session.close(); // 关闭session
}
@Test
public void testLazy1() {
Class c=(Class)session.get(Class.class, Long.valueOf(1));//只是查询了班级
Set<Student> studentList=(Set<Student>)c.getStudents();//等到用的时候才会去查询学生
System.out.println(studentList.size());
// studentList.iterator();
}
}
->执行结果:
Class c=(Class)session.get(Class.class, Long.valueOf(1));//只是查询了班级,关联的学生是不会被查询的
Hibernate:select class0_.classId as classId1_0_0,class0_.className as className2_0_0_ from t_class class0_ where class0_.classId=?
Set studentList=(Set)c.getStudents();//等到用的时候才会去查询学生
这就叫做延迟检索
Hibernate:select students0_.classId as classId3_0_0_,students0_.classId as classId3_1_1_ from t_student students0_ where students0_.classId=?
立即检索
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="false" >
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testLazy1() {
Class c=(Class)session.get(Class.class, Long.valueOf(1));
//执行这个时,就会把班级和学生都检索出来了 、
}
->执行结果:
Class c=(Class)session.get(Class.class, Long.valueOf(1));///执行这个时,就会把班级和学生都检索出来了
Hibernate:select class0_.classId as classId1_0_0,class0_.className as className2_0_0_ from t_class class0_ where class0_.classId=?
Hibernate:select students0_.classId as classId3_0_0_,students0_.classId as classId3_1_1_ from t_student students0_ where students0_.classId=?
增强延迟检索
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="true" >
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testLazy1() {
Class c=(Class)session.get(Class.class, Long.valueOf(1));
Set<Student> studentList=(Set<Student>)c.getStudents();
System.out.println(studentList.size());
//studentList.iterator();
}
执行结果:
Hibernate:select class0_.classId as classId1_0_0_,class0_.classNam
Hibernate:select students0_.classId as classId3_0_0_,students0_,stu
3
以上是应用默认延迟加载的情况
但是要取得数量,可以优化一下
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="extra" >
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testLazy1() {
Class c=(Class)session.get(Class.class, Long.valueOf(1));
Set<Student> studentList=(Set<Student>)c.getStudents();
System.out.println(studentList.size());
//studentList.iterator();
}
执行结果:
Hibernate:select class0_.classId as classId1_0_0_,class0_.classNam
Hibernate:select count(stuId) from t_student where classId=?
3
延迟检索many-to-one
->Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Student" table="t_student">
<id name="id" column="stuId">
<generator class="native"></generator>
</id>
<property name="name" column="stuName"></property>
<many-to-one name="c" column="classId" class="com.java1234.model.Class" cascade="save-update" lazy="no-proxy"></many-to-one>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testLazy2() {
Student student=(Student)session.get(Student.class, Long.valueOf(1));
student.getC().getName();
}
->执行结果:
代理类去数据库查询
二检索策略属性 batch-size
1,批量延迟检索;
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="true" batch-size="3" >
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testBatch1(){
List<Class> classList=session.createQuery("from Class").list();
Iterator it=classList.iterator();
Class c1=(Class)it.next();
Class c2=(Class)it.next();
Class c3=(Class)it.next();
c1.getStudents().iterator();
c2.getStudents().iterator();
c3.getStudents().iterator();
}
->执行结果:
首先查询所有的班级,然后去获取每个班级下面的所有学生
Hibernate:select class0_.classId as classId1_0_,class0_.className as classNam2_0
Hibernate:select students0_.classId as classId3_0_0_,students0_.stuId as stuId1_1_
Hibernate:select students0_.classId as classId3_0_0_,students0_.stuId as stuId1_1_
Hibernate:select students0_.classId as classId3_0_0_,students0_.stuId as stuId1_1_
加上batch-size="3"后
Hibernate:select class0_.classId as classId1_0_,class0_.className as classNam2_0
Hibernate:select students0_.classId as classId3_0_1_,students0_.stuId as stuId1_1_
这样的话是批量检索三个班级的
2,批量立即检索;
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="false" batch-size="3" >
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testBatch2(){
List<Class> classList=session.createQuery("from Class").list();
}
->执行结果:
Hibernate:select class0_.classId as classId1_0_,class0_.className as class
Hibernate:select students0_.classId as classId3_0_1_,students0_.stuId as from t_student students0_ where students0_.classId in(?,?,?)批量是几个,这里就是几个
三检索策略属性 Fetch
1,Fetch:select(默认) 查询方式;
->Class.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.java1234.model">
<class name="Class" table="t_class">
<id name="id" column="classId">
<generator class="native"></generator>
</id>
<property name="name" column="className"></property>
<set name="students" cascade="delete" inverse="true" lazy="false" batch-size="3" fetch="select">
<key column="classId"></key>
<one-to-many class="com.java1234.model.Student"/>
</set>
</class>
</hibernate-mapping>
->StudentTest.java
@Test
public void testFetch1(){
List<Class> classList=session.createQuery("from Class").list();
Iterator it=classList.iterator();
Class c1=(Class)it.next();
Class c2=(Class)it.next();
Class c3=(Class)it.next();
c1.getStudents().iterator();
c2.getStudents().iterator();
c3.getStudents().iterator();
}
->执行结果:
Hibernate:select class0_.classId as classId1_0_,class0_.className as
Hibernate:select students0_.classId as classId3_0_1_,students0_.stu
2,Fetch:subselect 子查询方式;
这里用到了子查询
在性能上可能会提升一些
3,Fetch:join 迫切左外连接查询方式;
@Test
public void testFetch2(){
Class c=(Class)session.get(Class.class, Long.valueOf(1));
}