`
在水伊方
  • 浏览: 110585 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Hibernate继承关系

 
阅读更多

1、整个继承树映射到一张表

在一个论坛中有用户(User)这个实体类,其中User这个实体中有分为普通用户,管理员与游客这3种身份,而这3种现在身份的用户就只有一个字段(即类型)不相同,可以考虑用Hibernate中的Table per class hierarchy策略

 

对象模型(Java类结构)

表结构

 User代码:

package org.hibernate.domain;

import java.util.Date;

/**
 * 实体类
 */
public class User {
	private int id;
	private String name;
	private Date birthday;

	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 Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", birthday=" + birthday
				+ "]";
	}

}

 

Admin代码:

package org.hibernate.domain;

public class Admin extends User {
	private String admin;

	public String getAdmin() {
		return admin;
	}

	public void setAdmin(String admin) {
		this.admin = admin;
	}

}

 

package org.hibernate.domain;

public class Guest extends User {
	private String guest;

	public String getGuest() {
		return guest;
	}

	public void setGuest(String guest) {
		this.guest = guest;
	}

}

 

配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.domain">
	<class name="User" table="user" discriminator-value="0">
		<id name="id">
			<generator class="native" />
		</id>
		
		<!-- 默认为string类型,这里指定为int类型  -->
		<discriminator column="type" type="int" />

		<property name="name" />
		<property name="birthday" />
		
		<subclass name="Admin" discriminator-value="1">
			<property name="admin" column="admin" />
		</subclass>
		
		<subclass name="Guest" discriminator-value="2">
			<property name="guest" column="guest" />
		</subclass>
	</class>
</hibernate-mapping>

 

测试类:

package org.hibernate.test;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.domain.Admin;
import org.hibernate.domain.Guest;
import org.hibernate.domain.User;
import org.hibernate.util.HibernateUtil;

public class TestUser extends TestCase {
	public void testAddUser() {
		Session session = null;
		Transaction tx = null;

		try {
			User user = new User();
			user.setName("user1");
			
			Admin admin = new Admin();
			admin.setName("user2");
			admin.setAdmin("admin user");

			Guest guest = new Guest();
			guest.setName("user3");
			guest.setGuest("guest user");
			
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.save(user);
			session.save(admin);
			session.save(guest);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
	
	public void testQuery() {
		Session session = null;
		Transaction tx = null;

		try {
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.get(User.class, 1);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
}

 

testAddUser方法测试结果: 

Hibernate: insert into user (name, birthday, type) values (?, ?, 0)
Hibernate: insert into user (name, birthday, admin, type) values (?, ?, ?, 1)
Hibernate: insert into user (name, birthday, guest, type) values (?, ?, ?, 2)

 可以看到3个对象都保存在了同一张表(User)中,其中靠type字段来区分不同的用户

 

User表记录如下

 

现在我们测试testQuery方法,结果如下:

Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_, user0_.admin as admin0_0_, user0_.guest as guest0_0_, user0_.type as type0_0_ from user user0_ where user0_.id=?

 将测试代码中的

session.get(User.class, 1);

 更改为

  session.get(User.class, 2);

   则结果如下: 

Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_, user0_.admin as admin0_0_, user0_.guest as guest0_0_, user0_.type as type0_0_ from user user0_ where user0_.id=?

 因为hibernate支持多态查询,故查询语句不变

 

将测试代码中的

session.get(User.class, 2);

 更改为

session.get(Guest.class, 2);

则结果如下:

Hibernate: select guest0_.id as id0_0_, guest0_.name as name0_0_, guest0_.birthday as birthday0_0_, guest0_.guest as guest0_0_ from user guest0_ where guest0_.id=? and guest0_.type=2

   从上述结果可以看到如果是明确知道查询是哪一类用户,则查询语句后面会指定type类型

 

采用这种策略只需要一张表即可。它有一个很大的限制:要求那些由子类定义的字段, 如admin,不能有非空(NOT NULL)约束。

 

    2、每个类映射到一张表

可以看到Hibernate整个类映射到一张表策略中,如果子类中有很多字段的情况下,则表就会产生很多的空字段,由此当子类中有很多字段的情况下,可以采用“每个子类一张表”的映射策略

 

表结构如下:

修改User.hbm.xml映射文件如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.domain">
	<class name="User" table="user">
		<id name="id" column="userId">
			<generator class="native" />
		</id>
		
		<property name="name" />
		<property name="birthday" />
		
		<joined-subclass name="Admin" table="admin">
			<key column="userId" />
			<property name="admin" column="admin" />
		</joined-subclass>
		
		<joined-subclass name="Guest" table="guest">
			<key column="userId" />
			<property name="guest" column="guest" />
		</joined-subclass>
	</class>
</hibernate-mapping>

 

测试类:

package org.hibernate.test;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.domain.Admin;
import org.hibernate.domain.Guest;
import org.hibernate.domain.User;
import org.hibernate.util.HibernateUtil;

public class TestUser extends TestCase {
	public void testAddUser() {
		Session session = null;
		Transaction tx = null;

		try {
			User user = new User();
			user.setName("user1");
			
			Admin admin = new Admin();
			admin.setName("user2");
			admin.setAdmin("admin user");

			Guest guest = new Guest();
			guest.setName("user3");
			guest.setGuest("guest user");
			
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.save(user);
			session.save(admin);
			session.save(guest);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
	
	public void testQuery() {
		Session session = null;
		Transaction tx = null;

		try {
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.get(User.class, 1);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
}

 

testAddUser方法测试结果:

Hibernate: insert into user (name, birthday) values (?, ?)
Hibernate: insert into user (name, birthday) values (?, ?)
Hibernate: insert into admin (admin, userId) values (?, ?)
Hibernate: insert into user (name, birthday) values (?, ?)
Hibernate: insert into guest (guest, userId) values (?, ?)

 当插入的用户不是普通用户的时候,需要往2张表中插入数据

数据库表记录如下:

 

 
  测试testQuery方法,结果如下:
Hibernate: select user0_.userId as userId0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_, user0_1_.admin as admin1_0_, user0_2_.guest as guest2_0_, case when user0_1_.userId is not null then 1 when user0_2_.userId is not null then 2 when user0_.userId is not null then 0 end as clazz_0_ from user user0_ left outer join admin user0_1_ on user0_.userId=user0_1_.userId left outer join guest user0_2_ on user0_.userId=user0_2_.userId where user0_.userId=?
 将测试代码中的
session.get(User.class, 1);
 更改为 
session.get(Admin.class, 1);
 则结果如下:
Hibernate: select admin0_.userId as userId0_0_, admin0_1_.name as name0_0_, admin0_1_.birthday as birthday0_0_, admin0_.admin as admin1_0_ from admin admin0_ inner join user admin0_1_ on admin0_.userId=admin0_1_.userId where admin0_.userId=?
 相比前面的查询语句,这句就简单的多了,所以我们在用“每个子类一张表”的映射策略的时候,最好明确要查询的类,这样可以提高查询的效率 
 
3、混合使用“整个继承树映射到一张表 ”和“每个子类一张表”的映射策略
假设,guest用户的属性很少,而admin的属性很多,则可以使用混合使用“整个继承树映射到一张  表 ”和“每个子类一张表””的映射策略
测试类:
package org.hibernate.test;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.domain.Admin;
import org.hibernate.domain.Guest;
import org.hibernate.domain.User;
import org.hibernate.util.HibernateUtil;

public class TestUser extends TestCase {
	public void testAddUser() {
		Session session = null;
		Transaction tx = null;

		try {
			User user = new User();
			user.setName("user1");
			
			Admin admin = new Admin();
			admin.setName("user2");
			admin.setAdmin("admin user");

			Guest guest = new Guest();
			guest.setName("user3");
			guest.setGuest("guest user");
			
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.save(user);
			session.save(admin);
			session.save(guest);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
	
	public void testQuery() {
		Session session = null;
		Transaction tx = null;

		try {
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.get(User.class, 1);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
}
 
如果在hibernate.cfg.xml配置中配置了如下项:
<property name="hbm2ddl.auto">create</property>
 此时测试testAddUser方法时,测试单元会报如下错误:
程序运行时,会删除数据库中的user表,admin表,而user表中有admin表的外键关联,所以不能删除user数据表了,所以抛出了上面的异常。所以需要先手动删除数据表,再运行程序。
此时测试testAdd方法时,结果如下: 
Hibernate: insert into user (name, birthday, type) values (?, ?, 0)
Hibernate: insert into user (name, birthday, type) values (?, ?, 2)
Hibernate: insert into admin (admin, userId) values (?, ?)
Hibernate: insert into user (name, birthday, guest, type) values (?, ?, ?, 1)
与采用“每个子类一张表”的映射策略相比,插入数据的时候,guest只插入一张表,admin插入了2张表,效率提高了些,如果要查询数据,则当查询admin的时候才会使用连接查询  
 
4、"每个具体类一张表"的映射策略
前面第一种映射策略中表结构存在null字段,第二种与第三种中查询的时候需要用到表连接,采用"每个具体类一张表"的映射策略则不会出现以上情况
表结构:
测试类:
package org.hibernate.test;

import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.domain.Admin;
import org.hibernate.domain.Guest;
import org.hibernate.domain.User;
import org.hibernate.util.HibernateUtil;

public class TestUser extends TestCase {
	public void testAddUser() {
		Session session = null;
		Transaction tx = null;

		try {
			User user = new User();
			user.setName("user1");
			
			Admin admin = new Admin();
			admin.setName("user2");
			admin.setAdmin("admin user");

			Guest guest = new Guest();
			guest.setName("user3");
			guest.setGuest("guest user");
			
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.save(user);
			session.save(admin);
			session.save(guest);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
	
	public void testQuery() {
		Session session = null;
		Transaction tx = null;

		try {
			session = HibernateUtil.getSession();
			tx = session.beginTransaction();
			session.get(User.class, 1);
			tx.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
}
 

配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.domain">
	<class name="User" table="user">
		<id name="id" column="userId">
			<generator class="hilo" />
		</id>
		
		<property name="name" />
		<property name="birthday" />
		
		<union-subclass name="Admin" table="admin">
			<property name="admin" />
		</union-subclass>
		
		<union-subclass name="Guest" table="guest">
			<property name="guest" />
		</union-subclass>
	</class>
</hibernate-mapping>

 

 testAddUser方法测试结果:

Hibernate: insert into user (name, birthday, userId) values (?, ?, ?)
Hibernate: insert into admin (name, birthday, admin, userId) values (?, ?, ?, ?)
Hibernate: insert into guest (name, birthday, guest, userId) values (?, ?, ?, ?)
可以看到3个对象分别插入到3张表中
testQuery方法测试结果:
Hibernate: select user0_.userId as userId0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_, user0_.admin as admin1_0_, user0_.guest as guest2_0_, user0_.clazz_ as clazz_0_ from ( select birthday, null as admin, name, userId, null as guest, 0 as clazz_ from user union select birthday, admin, name, userId, null as guest, 1 as clazz_ from admin union select birthday, null as admin, name, userId, guest, 2 as clazz_ from guest ) user0_ where user0_.userId=?
可以看到Hibernate会把所有的表都连接起来做查询,然后再从中查询出符合条件的记录 
  • 大小: 5.2 KB
  • 大小: 11.3 KB
  • 大小: 9.8 KB
  • 大小: 17 KB
  • 描述: Hibernate每个类映射到一张表结构
  • 大小: 17 KB
  • 大小: 2.1 KB
  • 大小: 2 KB
  • 大小: 3.5 KB
  • 大小: 14.9 KB
  • 大小: 16.7 KB
  • 大小: 21.5 KB
分享到:
评论

相关推荐

    Hibernate继承关系映射.pdf

    标题:“Hibernate继承关系映射.pdf” 描述:“简明扼要地介绍了Hibernate中继承关系的映射方式,深入探讨了三种不同的映射策略及其优缺点,同时解析了多态查询的概念。” 知识点: ### Hibernate继承关系映射...

    用Hibernate映射继承关系

    本主题聚焦于“用Hibernate映射继承关系”,我们将深入探讨Hibernate如何处理对象的继承层次结构,并将其映射到数据库中的表。 Hibernate支持多种继承策略,包括单一表继承(Single Table Inheritance)、联合表...

    Hibernate继承映射代码

    在大型项目中,由于业务需求复杂,我们常常会使用到类的继承来组织代码结构,而Hibernate提供了对这些继承关系的映射支持。本主题将深入探讨"Hibernate继承映射+C3P0代码"的相关知识点。 首先,让我们理解Hibernate...

    jpa/hibernate继承注解

    以下是对"jpa/hibernate继承注解"这一主题的详细说明。 1. **单一表继承(Single Table Inheritance, STI)** 单一表继承是最简单的继承策略,所有的子类信息都存储在一个数据库表中。使用`@Inheritance(strategy ...

    hibernate映射继承关系(每个类都对应一张表)

    Hibernate,作为Java中广泛使用的对象关系映射(ORM)框架,提供了多种方式来处理继承关系的映射,其中一种就是"每个类都对应一张表"的策略。本文将深入探讨这种映射方式,以及如何在Hibernate中实现它。 首先,...

    (2)Hibernate3.2 中的类继承关系

    本话题主要探讨的是Hibernate 3.2版本中的类继承关系处理,这是面向对象编程中常见的概念,但在数据库映射时需要特殊考虑。在Hibernate中,类继承关系的处理允许我们创建更加灵活和可扩展的对象模型。 在Hibernate ...

    Hibernate继承映射的第一种策略:每棵类继承树对应一张表

    Hibernate继承映射是将Java类的继承关系映射到数据库表的一种策略,使得对象模型的复杂性能够平滑地转化为关系数据库模型。本篇将详细介绍Hibernate继承映射的第一种策略——每棵类继承树对应一张表,即单一表继承...

    hibernate继承映射.rar

    Hibernate继承映射是将Java中的继承关系映射到数据库的关系模型中。在Java中,一个基类可以有多个子类,而在数据库中,这些子类可以共享一张表或者各自拥有独立的表,这取决于我们选择的继承策略。Hibernate提供了四...

    Hibernate学习资料(java)

    Hibernate一对一数据关联 Hibernate下的多对多关系 Hibernate关系映射 Hibernate继承关系映射 Hibernate映射类型-主键生成器-核心API Hibernate3 插件Eclipse配置

    Hibernate映射继承关系的三种方案.docx

    在Java的ORM框架Hibernate中,映射继承关系是常见的需求,尤其在处理具有层次结构的实体类时。本文将详细探讨Hibernate中处理继承关系的三种映射策略:subclass、joined-subclass以及union-subclass。 首先,让我们...

    Hibernate继承映射二:每个子类一张表

    在实现这种映射时,我们需要在Hibernate的配置文件(hibernate.cfg.xml或相应的注解)中指定继承关系。例如,我们有一个抽象基类`Person`和两个子类`Student`和`Teacher`,可以这样配置: ```xml &lt;hibernate-...

    Hibernate继承映射(annotation)

    在传统的面向对象编程中,继承是实现代码复用和结构化设计的重要手段,而在关系型数据库中,由于其二维表格的特性,往往需要采用特定的方式来映射这种继承关系。本文将深入探讨使用注解配置的Hibernate继承映射策略...

    hibernate对应关系详解

    6. **继承关系映射**:Hibernate支持类的继承关系映射,包括单表继承(Single Table Inheritance)、联合继承(Concrete Table Inheritance)和歧视值继承(Discriminator Value Inheritance)。单表继承所有子类...

    Hibernate继承映射-概述

    《Hibernate继承映射详解》 在Java开发中,对象关系映射(ORM)框架如Hibernate大大简化了数据库操作。Hibernate不仅提供了对基本数据类型的映射,还支持复杂的数据结构,如继承关系的映射。本篇文章将深入探讨...

    hibernate的继承映射关系

    在ORM(Object-Relational Mapping)框架如Hibernate中,如何优雅地将这些继承关系映射到关系型数据库中,成为了一个重要的议题。本文将深入探讨Hibernate如何处理继承多态映射关系,主要通过三种不同的策略来实现这一...

Global site tag (gtag.js) - Google Analytics