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调用存储过程

  1. 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共三种继承映射策略。

  1. 采用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);
    }
  1. 采用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);
    }
  1. 采用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));
    	}

猜你喜欢

转载自blog.csdn.net/AthlenaA/article/details/82811464
今日推荐