26.Hibernate-主键和映射.md


目录

1.复合主键映射

数据库表可以用复合主键映射。但是复合主键映射使用时候需要注意:在配置文件中,需要使用一个对象来表示复合主键

  • 单一主键
    <class name="Employee" table="employee">
        <!-- 主键 注意和类成员和表列名称的一致对应 -->
        <id name="empId" column="EmpId" >
            <!-- 主键的生成策略:
                 1.identity  自增长(mysql,db2)
                 2.sequence  自增长(序列), oracle中自增长是以序列方法实现
                 3.native  自增长【会根据底层数据库自增长的方式选择identity或sequence】
                            如果是mysql数据库, 采用的自增长方式是identity
                            如果是oracle数据库, 使用sequence序列的方式实现自增长
                    
                 4.increment  自增长(会有并发访问的问题,一般在服务器集群环境使用会存在问题。)
                    
                 5.assigned  指定主键生成策略为手动指定主键的值
                 6.uuid      指定uuid随机生成的唯一的值
                 7.foreign   (外键的方式, one-to-one讲)
             -->
            <generator class="native" />
            
        </id>
        <!-- 非主键,同样一一映射 
             name:类的属性名称
             column:表的字段名称
             length:设定字段的长度,默认为255
             type:设定映射表的类型,如果不写匹配类对应属性的类型
                     java类型:必须带完整包名:java.lang.String
                     hibernate类型:全部都是小写
              
        -->
        <property name="empName" column="EmpName"></property>
        <property name="workDate" column="WorkDate"></property>
    </class>  

  • 复合主键

a. 首先需要将数据库表对应的对象类中的复合主键,提取为一个对象。所以需要新建一个类,将这个类对象作为表对象的属性。
特别要注意的是这个复合主键类对象一定要实现序列化方法

package per.liyue.code.hibernatehello;
import java.io.Serializable;
public class CompositeKeys implements Serializable {
    private String name = null;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    private int id = 0;
}  

b. 将序列化的对象添加到表对应的类对象中

public class Employee {
    private CompositeKeys  keys;
    private String empName;
    private Date workDate; 
        ......

} 

c. 在配置文件中将符合主键配置

    <class name="Employee" table="employee">
        <composite-id name="keys">
            <key-property name="name" type="String"></key-property>
            <key-property name="id" type="int"></key-property>
        </composite-id>


        <!-- 非主键,同样一一映射 
             name:类的属性名称
             column:表的字段名称
             length:设定字段的长度,默认为255
             type:设定映射表的类型,如果不写匹配类对应属性的类型
                     java类型:必须带完整包名:java.lang.String
                     hibernate类型:全部都是小写
              
        -->
        <property name="empName" column="EmpName"></property>
        <property name="workDate" column="WorkDate"></property>
    </class> 


目录

2.集合映射

2.1Set集合

假若有如下的数据库表:

  • 那么对应的类对象应该是
package per.liyue.code.hibernatecollection;
import java.util.Set;
/*
 * 带有集合的类
 */
public class User {
    private int userId;
    private String userName;
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public Set<String> getUserEmail() {
        return userEmail;
    }
    public void setUserEmail(Set<String> userEmail) {
        this.userEmail = userEmail;
    }
    //一个Set集合,对应数据库中的表,这个表的外键是User表的主键
    private Set<String> userEmail;
}
  • 配置映射文件:
    要注意的是Set集合的配置,对应的数据类型必须填写
<?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">
<!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
<!-- package:类对象所在的包
     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
     Demo:在true时候可以写为session.createQuery("from Employee").list();
               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
 -->
<hibernate-mapping package="per.liyue.code.hibernatecollection" auto-import="true">
    <!-- 类与表的对应
         name:类名称
         table:表名称
    
     -->
    <class name="User" table="user">
    
        <!-- 主键 注意和类成员和表列名称的一致对应 -->
        <id name="userId" column="UserId" >
            <generator class="native" />            
        </id>
        
        <property name="userName" column="UserName"></property>
        
        <!-- Set集合配置:
             set-name:要映射的Set集合类
             set-table:要映射的Set表
                 key-column:指定集合表的外键,也就是User表的主键
                     element-type:集合表其他字段的类型,必须填写!!!
                     element-column:集合表其他自动的表列名称
         -->
        <set name="userEmail" table="UserEmail">
            <key column="UserId"></key>
            <element type="string" column="EmailAddress"></element>
        </set>
        
    </class>
</hibernate-mapping>  

  • 配置Hibernate配置文件:
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory name="foo">
        <!-- 数据库连接配置 -->
        <!-- 连接类 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- 连接数据库 -->
        <property name="hibernate.connection.url">jdbc:mysql:///hi</property>
        <!-- 连接用户名 -->
        <property name="hibernate.connection.username">root</property>
        <!-- 连接密码 -->
        <property name="hibernate.connection.password">root</property>
        <!-- 数据库方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        
        <!-- 其他配置 -->
        <property name="hibernate.show_sql"></property>
        
        <property name="hibernate.hbm2ddl.auto">update</property>
        
        
        <!-- 加载所有的映射 -->
        <mapping resource="per/liyue/code/hibernatehello/Employee.hbm.xml"/>
        <mapping resource="per/liyue/code/hibernatecollection/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>  

  • 最后保存数据
package per.liyue.code.hibernatecollection;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class App {
    private static SessionFactory sf;
    static{
        sf = new Configuration().configure().buildSessionFactory();
    }
    
    @Test
    public void setOperation(){
        Session s = sf.openSession();
        s.beginTransaction();
        
        /*
         * Set:保存带Set的集合
         */
        User user = new User();
        user.setUserId(2);
        user.setUserName("李四");
        Set<String> email = new HashSet<>();
        email.add("a@a.com");
        email.add("b@b.com");
        user.setUserEmail(email);
        
        s.save(user);
        
        s.getTransaction().commit();
        s.close();
        sf.close();
        
        
    }
}

2.2其他集合

其他集合大体上类似Set集合,但是具体有不同

  • list
    list在配置文件中需要指定一个索引,因为list是有序的!!!

  • map
    map中key和value都需要指定类型

Demo:
将上文中的例子修改

package per.liyue.code.hibernatecollection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/*
 * 带有集合的类
 */
public class User {
    private int userId;
    private String userName;
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public Set<String> getUserEmail() {
        return userEmail;
    }
    public void setUserEmail(Set<String> userEmail) {
        this.userEmail = userEmail;
    }
    //一个Set集合,对应数据库中的表,这个表的外键是User表的主键
    private Set<String> userEmail;
    
    //一个List集合
    private List<String> userPhoneNumber = new ArrayList<>();
    public List<String> getUserPhoneNumber() {
        return userPhoneNumber;
    }
    public void setUserPhoneNumber(List<String> userPhoneNumber) {
        this.userPhoneNumber = userPhoneNumber;
    }
    
    //一个Map集合
    private Map<String, String> userAddress = new HashMap<>();
    public Map<String, String> getUserAddress() {
        return userAddress;
    }
    public void setUserAddress(Map<String, String> userAddress) {
        this.userAddress = userAddress;
    }
    
}
<?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">
<!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
<!-- package:类对象所在的包
     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
     Demo:在true时候可以写为session.createQuery("from Employee").list();
               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
 -->
<hibernate-mapping package="per.liyue.code.hibernatecollection" auto-import="true">
    <!-- 类与表的对应
         name:类名称
         table:表名称
    
     -->
    <class name="User" table="user">
    
        <!-- 主键 注意和类成员和表列名称的一致对应 -->
        <id name="userId" column="user_id" >
            <generator class="native" />            
        </id>
        
        <property name="userName" column="user_name"></property>
        
        <!-- Set集合配置:
             set-name:要映射的Set集合类
             set-table:要映射的Set表
                 key-column:指定集合表的外键,也就是User表的主键
                     element-type:集合表其他字段的类型
                     element-column:集合表其他自动的表列名称
         -->
        <set name="userEmail" table="UserEmail">
            <key column="user_id"></key>
            <element type="string" column="email_address"></element>
        </set>
        
        <!-- List集合配置
             list-index:需要为list指定排序,因为list是有序的
         -->
        <list name="userPhoneNumber" table="UserPhoneNumber">
            <key column="user_id"></key>
            <list-index column="list_index"></list-index>
            <element type="string" column="phone_number"></element>
        </list>
        
        <!-- Map集合配置
            
         -->
         <map name="userAddress">
             <key column="user_id"></key>
             <map-key type="string" column="area"></map-key>
             <element type="string" column="address"></element>
         </map>
        
    </class>
</hibernate-mapping>  

最后再修改实现类

package per.liyue.code.hibernatecollection;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class App {
    private static SessionFactory sf;
    static{
        sf = new Configuration().configure().buildSessionFactory();
    }
    
    @Test
    public void setOperation(){
        Session s = sf.openSession();
        s.beginTransaction();
        
        /*
         * Set:保存带Set的集合
         */
        User user = new User();
        user.setUserId(2);
        user.setUserName("孙五");
        Set<String> email = new HashSet<>();
        email.add("c@a.com");
        email.add("d@b.com");
        user.setUserEmail(email);
        
        /*
         * List:保存List
         */
        user.getUserPhoneNumber().add("189898989");
        user.getUserPhoneNumber().add("108080808");
        
        /*
         * Map:保存Map
         */
        user.getUserAddress().put("上海", "浦东");
        user.getUserAddress().put("杭州", "西湖");
        
        s.save(user);
        
        s.getTransaction().commit();
        s.close();
        sf.close();    
        
    }
}



目录

3.集合数据的读取

集合数据的读取采用懒加载方式:当映射正确的时候,使用到相关集合数据,hibernate才会想数据库发送执行语句
Demo:
将上述例子中的App类中增加读取函数

@Test
    public void GetCollection(){
        Session s = sf.openSession();
        s.beginTransaction();
        
        User user = (User) s.get(User.class, 4);
        System.out.println("查询到用户的信息:");
        System.out.println("用户ID:" + user.getUserId());
        System.out.println("用户名字:" + user.getUserName());
        
        /*
         * 懒加载:当有正确的映射时候,只有当使用集合相关数据时候,hibernate才会想数据库发送相关语句
         */
        System.out.println("用户邮箱:" + user.getUserEmail());
        System.out.println("用户电话: " + user.getUserPhoneNumber());
        System.out.println("用户地址: " + user.getUserAddress());
        
        s.getTransaction().commit();
        s.close();
        sf.close();    
    }  

可以得到结果:

查询到用户的信息:
用户ID:4
用户名字:孙五
用户邮箱:[d@b.com, c@a.com]
用户电话: [189898989, 108080808]
用户地址: {上海=浦东, 杭州=西湖}


目录

4.一对多和多对一映射

4.1概念

实际开发中,有很多情况例如上面的主数据类中保存了子数据类的对象,当时常常这个集合对象内容不是单一的基本数据类型,需要用对象方式来保存更多的数据。这个时候就存在了一对多和多对一的映射关系

4.2配置和开发

4.2.1关键点

配置的关键在于对主数据类和子数据类都可以配置对应的配置文件:

  • 单向关联:配置一对多
  • 单向关联:配置多对一
  • 双向关联:配置上面两种单向关联均配置
    注意:配置了哪一种情况,就可以根据哪一种情况来操作数据。也就是说配置了一对多则可以通过一来维护多(保存时候保存一关联保存多),配置了多对一则可以通过多来维护一(保存时候保存多关联保存一)。因此在使用时候,为了提高效率,建议先保存一的一方再去保存多,因为反过来的话执行一次insert后还要多执行一次update,会降低执行效率!

4.2.2实例

  • 有数据关系:

  • 编写主数据类和子数据类:

package per.liyue.code.hibernate_multimapping;
import java.util.HashSet;
import java.util.Set;
/*
 * 主数据类对象,包含了一个集合类型的属性,内容是另一个类的对象
 */
public class Department {
    private int depId;
    private String depName;
    private Set<Employee> employee = new HashSet<Employee>();
    public int getDepId() {
        return depId;
    }
    public void setDepId(int depId) {
        this.depId = depId;
    }
    public String getDepName() {
        return depName;
    }
    public void setDepName(String depName) {
        this.depName = depName;
    }
    public Set<Employee> getEmployee() {
        return employee;
    }
    public void setEmployee(Set<Employee> employee) {
        this.employee = employee;
    }
}
package per.liyue.code.hibernate_multimapping;
/*
 * 子数据类,这个类的对象是主数据类的集合元素
 */
public class Employee {
    private int empId;
    public int getEmpId() {
        return empId;
    }
    public void setEmpId(int empId) {
        this.empId = empId;
    }
    
    private String empName;
    public String getEmpName() {
        return this.empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    
    
    //多对一:
    private Department dept;
    public Department getDept() {
        return dept;
    }
    public void setDept(Department dept) {
        this.dept = dept;
    }
    
}
   

  • 配置两个类的配置文件
    • 一对多的配置
<!-- 主数据类的配置文件 -->
<set name="主数据类中的子数据类的类对象" table="子数据类的表名称">
      <key column="主数据类的主键(也就是子数据类的外键)"></key>
      <one-to-many class="子数据类的类名称,注意同一个包下可以不带包名称,注意不要在不同包下重复用一个类名称"/>
</set>  

* 多对一的配置
<!-- 子数据类的配置文件 -->

<many-to-one name="子数据类中的主数据类对象" column="子数据类的外键(主数据类的主键)" class="主数据类名称"></many-to-one>  

  • Demo:
<?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">
<!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
<!-- package:类对象所在的包
     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
     Demo:在true时候可以写为session.createQuery("from Employee").list();
               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
 -->
<hibernate-mapping package="per.liyue.code.hibernate_multimapping" auto-import="true">
    <class name="Department" table="Department">
        <!-- 主键 -->
        <id name="depId" column="dep_id" >
            <generator class="native" />            
        </id>
        
        <property name="depName" column="dep_name"></property>
        
        <!-- 设置一对多关系:
            name:集合中的类对象对应的类
            table:集合中类对象对应的表
            key:子数据类中对应外键
            one-to-many:子数据类对应的类,如果是同一个包下的类可以不写包名
         -->
        <set name="employee" table="Employee">
            <key column="dep_id"></key>
            <one-to-many class="Employee"/>
        </set>
        
        
        
    </class>
</hibernate-mapping>  

<?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">
<!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
<!-- package:类对象所在的包
     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
     Demo:在true时候可以写为session.createQuery("from Employee").list();
               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
 -->
<hibernate-mapping package="per.liyue.code.hibernate_multimapping" auto-import="true">
    <class name="Employee" table="Employee">
        <!-- 主键 -->
        <id name="empId" column="emp_id" >
            <generator class="native" />            
        </id>
        
        <property name="empName" column="emp_name"></property>
        
        <!-- 设置多对一关系:
            name:映射的主类对象
            column:外键的字段名称
            class:映射主类
         -->
        <many-to-one name="dept" column="dep_id" class="Department"></many-to-one>
        
    </class>
</hibernate-mapping>  

  • 执行语句
package per.liyue.code.hibernate_multimapping;


import java.util.HashSet;
import java.util.Set;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;


public class App_Save {
	private static SessionFactory sf;
	static{
		sf = new Configuration().configure().buildSessionFactory();
	}
	
	@Test
	/*
	* 一维护多,无论保存时候先保存部门还是后保存部门,必须要多执行相应的update语句保证id一致。
	*/
	public void DemoOne2Many(){
		Session s = sf.openSession();
		s.beginTransaction();
		
		Department dept = new Department();
		dept.setDepName("硬件开发部");
		
		Employee zhangSan = new Employee();
		zhangSan.setEmpName("王五");
		
		Employee liSi = new Employee();
		liSi.setEmpName("赵二");
		
		/*
		*这里的映射关系是一对多,也就是通过部门来维护员工 
		*/	
		dept.getEmployee().add(zhangSan);
		dept.getEmployee().add(liSi);		
		
		s.save(zhangSan);
		s.save(liSi);
		s.save(dept);
		
		
		s.getTransaction().commit();
		s.close();
		sf.close();	
		
	}
	
	@Test
	/*
	* 推荐方式:通过多来维护一,这样高效!
	*/
	public void DemoMany2One(){
		Session s = sf.openSession();
		s.beginTransaction();
		
		Department dept = new Department();
		dept.setDepName("软件开发部");
		
		Employee zhangSan = new Employee();
		zhangSan.setEmpName("张三");
		
		Employee liSi = new Employee();
		liSi.setEmpName("李四");
		
		/*
		*这里的映射关系是多对一,也就是通过员工来维护部门 
		*/	
		zhangSan.setDept(dept);
		liSi.setDept(dept);
		
		//这个时候如果部门保存在后面,则保存员工时候没有部门编号,会增加两条update语句
		s.save(dept);
		s.save(zhangSan);
		s.save(liSi);
		
		
		s.getTransaction().commit();
		s.close();
		sf.close();	
		
	}
		
}


执行的语句结果

一对多的情况:
Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)
Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)
Hibernate: insert into Department (dep_name) values (?)
Hibernate: update Employee set dep_id=? where emp_id=?
Hibernate: update Employee set dep_id=? where emp_id=?
多对一的情况:
Hibernate: insert into Department (dep_name) values (?)
Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)
Hibernate: insert into Employee (emp_name, dep_id) values (?, ?)

在hibernate中唯一的方式把对象映射为外键的方式:many-to-one
建议通过多对一来维护,这样操作高效!

  • 读取数据
    • 懒加载:在执行的时候hibernate才发送并执行相关SQL语句
package per.liyue.code.hibernate_multimapping;


import java.util.HashSet;
import java.util.Set;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;


public class App_Get {
	private static SessionFactory sf;
	static{
		sf = new Configuration().configure().buildSessionFactory();
	}
	
	@Test
	/*
	* 一对多和多对一的读取
	*/
	public void DemoOne2Many(){
		Session s = sf.openSession();
		s.beginTransaction();
		
		Department dep = (Department)s.get(Department.class, 1);
		System.out.println("从部门读取:" + dep.getDepId());
		/*
		* 懒加载:不执行下面的调用,hibernate不会向数据库发送相关语句并执行
		*/
		System.out.println("从部门读取:" + dep.getEmployee());
		
		Employee emp = (Employee)s.get(Employee.class, 2);
		System.out.println("从员工读取:" + emp.getEmpName());
		System.out.println("从员工读取:" + emp.getDept());
		
		
		s.getTransaction().commit();
		s.close();
		sf.close();	
		
	}
}



目录

5.反转:inverse

5.1概念

  • 表示反转控制,取消控制
  • 在一对多和多对一的关系中,一的一方可以设置inverse属性。

5.2实例

5.2.1配置

在上面的Department.hbm.xml中,在一对多的映射中可以设定:

<set name="employee" table="Employee" inverse="false">
            <key column="dep_id"></key>
            <one-to-many class="Employee"/>
        </set>  

这里的false是默认值,表示主数据类有控制权限,如果设置为true则表示没有控制权限

5.2.2影响

  • 保存:有影响,解除关联后,子数据类依旧会保存,但是外键关联取消,保存为NULL
  • 读取:无影响
  • 解除关联关系:有影响,解除关联关系的用法是先读取,然后主类调用clear()方法。如果解除,则则不能解除关系,但是不报错
  • 删除:有影响,解除后如果外键有值,删除会违反主外键约束而报错,如果外键没有值为NULL,则可以删除

目录

6.级联:cascade

6.1概念

级联操作的设置,在一对多和多对一均可配置。如在配置文件中:

<set name="employee" table="Employee" inverse="false" cascade="none">
            <key column="dep_id"></key>
            <one-to-many class="Employee"/>
</set>  

6.2配置

只在一对多一方配置
级联操作有以下几种配置:

  • none:默认值,不级联操作
  • save-update:设置级联保存和更新。注意:save和update不能拆分使用
  • save-update,delete:设置级联保存、更新和删除
  • all: 全部

6.3inserse和cascade区别

不能在一起使用


目录

7.多对多映射

7.1关系

在实际应用中有多对多的映射关系:

不同的人有不同的角色,不同的角色对应多个人。在数据库中二者的关联关系通常放到另一个表中。形成了多对多映射

7.2配置和实现

7.2.1定义两个数据类

package per.liyue.code.hibernate_mu2mu;


import java.util.HashSet;
import java.util.Set;
/*
 * 数据类角色
 */
public class Role {
	private int roleId;
	private String roleName;
	
	//包含另一个数据类对象
	private Set<Person> person = new HashSet<>();
	
	public int getRoleId() {
		return roleId;
	}
	public void setRoleId(int roleId) {
		this.roleId = roleId;
	}
	public String getRoleName() {
		return roleName;
	}
	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}
	public Set<Person> getPerson() {
		return person;
	}
	public void setPerson(Set<Person> person) {
		this.person = person;
	}
}




7.2.2配置二者的映射关系

<?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">
<!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
<!-- package:类对象所在的包
     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
     Demo:在true时候可以写为session.createQuery("from Employee").list();
               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
 -->
<hibernate-mapping package="per.liyue.code.hibernate_mu2mu" auto-import="true">
    <class name="Role" table="Role">
        <!-- 主键 -->
        <id name="roleId" column="r_id" >
            <generator class="native" />            
        </id>
        
        <property name="roleName" column="r_name"></property>
        
        <!-- 设置多对多关系:
            name:
         -->
        <set name="person" table="Reletionship" inverse="false" cascade="none">
            <key column="r_id"></key>
            <many-to-many column="per_id" class="Person"></many-to-many>
        </set>
        
        
        
    </class>
</hibernate-mapping>  

<?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">
<!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 -->
<!-- package:类对象所在的包
     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:
     Demo:在true时候可以写为session.createQuery("from Employee").list();
               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list();
 -->
<hibernate-mapping package="per.liyue.code.hibernate_mu2mu" auto-import="true">
    <class name="Person" table="Person">
        <!-- 主键 -->
        <id name="personId" column="per_id" >
            <generator class="native" />            
        </id>
        
        <property name="personName" column="per_name"></property>
        
        <!-- 设置多对多关系:
            name:另一个类对象的实例名称
            talbe:二者关系的数据库映射表
            key-column:当前类的主键,关系表的外键
            many-to-mangy-column:另一个类的主键,关系表中的另一个外键
            many-to-mangy-class:另一个类的类名称
         -->
        <set name="role" table="Reletionship" inverse="false" cascade="none" >
            <key column="per_id"></key>
            <many-to-many column="r_id" class="Role"></many-to-many>
        </set>
        
        
        
    </class>
</hibernate-mapping>  

7.2.3实现业务

package per.liyue.code.hibernate_mu2mu;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;


import per.liyue.code.hibernate_multimapping.Department;
import per.liyue.code.hibernate_multimapping.Employee;


public class App {
	private static SessionFactory sf;
	static{
		sf = new Configuration().configure().buildSessionFactory();
	}
	
	@Test
	/*
	* 
	*/
	public void DemoMany2Many(){
		Session s = sf.openSession();
		s.beginTransaction();
		
		//创建
		Person p_zhangsan = new Person();
		p_zhangsan.setPersonName("张三");		
		Person p_lisi = new Person();
		p_lisi.setPersonName("李四");
		
		Role r_teacher = new Role();
		r_teacher.setRoleName("教师");
		Role r_student = new Role();
		r_student.setRoleName("学生");
		Role r_developer = new Role();
		r_developer.setRoleName("开发");
		
		//关系
		p_zhangsan.getRole().add(r_teacher);
		p_zhangsan.getRole().add(r_developer);
		
		p_lisi.getRole().add(r_student);
		
		//保存
		s.save(p_zhangsan);
		s.save(p_lisi);
		s.save(r_teacher);
		s.save(r_student);
		s.save(r_developer);
		
		s.getTransaction().commit();
		s.close();
		sf.close();	
		
	}
}


8.映射关系配置总结

  • 一对多:

<set name="映射的集合属性" table="(可选)集合属性对应的外键表">
    <key column="外键表的,外键字段" />
    <one-to-many class="集合元素的类型" />
</set>
  • 多对一:

<many-to-one name="对象属性" class="对象类型" column="外键字段字段" />
  • 多对多

<set name="" table="">
    <key column="" />
    <many-to-many column="" class="">
</set>    


目录

8.一对一映射

8.1分类

可以有两种一对一映射:

  • 基于外键,外键唯一
  • 基于主键
    假设有用户和身份证的一一映射,可以有下面的两种数据库表关系

那么两种模型下的实例为:

8.2有主键的映射

8.2.1类对象





8.2.2配置文件









8.2.3主配置和实现







8.3无主键的映射

8.3.1类对象





8.3.2配置文件









8.3.3主配置和实现








目录

9.组件映射

9.1适用范围

  • 组件映射指的是一个类中包含了另一个类的对象。是包含与被包含的概念
  • 映射会将两个类映射到一个表中

9.2实例

9.2.1类

package per.liyue.code.component_demo;/** * Created by liyue on 2016/10/21. */public class User{    private int id;    private String name;    private Wheel wheel;}```


```java
package per.liyue.code.component_demo;/** * Created by liyue on 2016/10/21. */public class Wheel{    private int count;    public int getCount()    {        return count;    }    public void setCount(int count)    {        this.count = count;    }    public int getSize()    {        return size;    }    public void setSize(int size)    {        this.size = size;    }    private int size;}```


## 9.2.2配置文件
```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"><!-- Generated Nov 9, 2006 6:27:53 PM by Hibernate Tools 3.2.0.beta7 --><!-- package:类对象所在的包     auto-import:表面是自动导入包,如果设定为false,则需要在执行hql语句时候将包名写清楚:     Demo:在true时候可以写为session.createQuery("from Employee").list();               在false时候必须写为session.createQuery("from per.liyue.code.hibernatehello.Employee").list(); --><hibernate-mapping package="per.liyue.code.component_demo.User" auto-import="true">    <class name="User" table="t_User">        <!-- 主键 -->        <id name="id" column="user_id" >            <generator class="native" />        </id>        <property name="name" column="user_name"></property>        <!--        组件关系        -->        <component name="wheel">            <!--组件成员-->            <property name="count"></property>            <property name="size"></property>        </component>    </class></hibernate-mapping>```




---
[toc]
---


# 10.继承映射
## 10.1概念
### 10.1.1简单继承
有多少个子类写多少个配置文件

// 动物类
public abstract class Animal {

private int id;
private String name;
<class name="Cat" table="t_Cat">
	<!-- 简单继承映射: 父类属性直接写 -->
	<id name="id">
		<generator class="native"></generator>
	</id>
	<property name="na"></property>
	<property name="catchMouse"></property>					 
</class>

@Test
public void getSave() {

	Session session = sf.openSession();
	session.beginTransaction();
	
	// 保存

// Cat cat = new Cat();
// cat.setName("大花猫");
// cat.setCatchMouse("抓小老鼠");
// session.save(cat);

	// 获取时候注意:当写hql查询的使用,通过父类查询必须写上类的全名
	Query q = session.createQuery("from cn.itcast.e_extends1.Animal");
	List<Animal> list = q.list();
	System.out.println(list);
	
	session.getTransaction().commit();
	session.close();
	
}




### 10.1.2复杂继承
* 多个子类共用一个表 
不推荐使用,因为违反数据库设计原则。在子类数量众多且属性单一情况下适用。



* 每个子类用一个表



* 父类不对应表

 


## 10.2实例
原文地址:https://www.cnblogs.com/bugstar/p/8512845.html