SSH笔记-Hibernate的映射关系 基于外键/主键一对一映射、多对多映射、映射继承

1、文章分为:
(1) 基于外键一对一映射(对应包为com.demo.sshtest)
(2) 基于主键一对一映射(对应包为com.demo.sshtest2)
(3) 多对多映射(对应包为com.demo.sshtest3)
(4) 映射继承:①subclass②joined-subclass③union-subclass(对应包为com.demo.sshtest4)


2、基于外键一对一映射
①当从数据表中的外键拥有uinique约束时,称为基于唯一外键的一对一关联
②要在两端都创建另一端的对象参数
③需要有外键一端用many-to-one标签配置,不需要外键一端用one-to-one标签配置

(1)Customer.java 不需要外键一端的模型类

package com.demo.sshtest;

public class Customer {

    public Integer customerId;
    public String customerName;

    public Merchant merchant;

    public Integer getCustomerId() {
        return customerId;
    }

    public void setCustomerId(Integer customerId) {
        this.customerId = customerId;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public Merchant getMerchant() {
        return merchant;
    }

    public void setMerchant(Merchant merchant) {
        this.merchant = merchant;
    }

}

(2)Merchant.java 需要配置外键一端的模型类

package com.demo.sshtest;

public class Merchant {

    public Integer merchantId;
    public String merchantName;

    public Customer customer;

    public Integer getMerchantId() {
        return merchantId;
    }

    public void setMerchantId(Integer merchantId) {
        this.merchantId = merchantId;
    }

    public String getMerchantName() {
        return merchantName;
    }

    public void setMerchantName(String merchantName) {
        this.merchantName = merchantName;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

(3)Customer2.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">
<!-- Generated 2018-4-16 16:17:50 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest.Customer" table="CUSTOMERS">
        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMERID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMERNAME" />
        </property>

        <!-- 映射一对一关联关系,MERCHANTS表中已经有外键,这里不需要设置外键 -->
        <one-to-one name="merchant" class="com.demo.sshtest.Merchant" property-ref="customer"></one-to-one>
    </class>
</hibernate-mapping>

(4)Merchant.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">
<!-- Generated 2018-4-16 16:17:50 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest.Merchant" table="MERCHANTS">
        <id name="merchantId" type="java.lang.Integer">
            <column name="MERCHANTID" />
            <generator class="native" />
        </id>
        <property name="merchantName" type="java.lang.String">
            <column name="MERCHANTNAME" />
        </property>

       <!-- 使用many-to-one来映射一对一关联关系,在这里用many-to-one,就会在这个MERCHANTS表里面生成外键 -->
       <many-to-one name="customer" class="com.demo.sshtest.Customer" column="CUSTOMERID" unique="true"></many-to-one>
    </class>
</hibernate-mapping>

(5)TestOne2One.java 测试用的类

package com.demo.sshtest;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestOne2One {

    public SessionFactory sessionFactory;
    public Session session;
    public Transaction transaction;

    //基于外键一对一关联步骤
    //1、外键可以存放在任意一端,在需要存放外键一端,使用many-to-one元素。为many-to-one元素增加unique=“true”属性来表示为一对一关联
    //2、另一端需要使用one-to-one元素,该元素使用 property-ref属性指定使用被关联实体主键以外的字段作为关联字段

    //注意事项:最后不要两端都用外键映射一对一关系,会混乱,而且会出现不是一一对应的情况

    @Before
    public  void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        System.out.println("init");
    }
    @After
    public  void destory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
        System.out.println("destory");
    }

    @Test
    public void testSave(){
        System.out.println("testSave");
        Merchant merchant = new Merchant();
        Customer customer = new Customer();
        merchant.setMerchantName("test-one");
        customer.setCustomerName("testOneXXXX");
        //设定关联关系
        merchant.setCustomer(customer);
        customer.setMerchant(merchant);
        //保存,先保存不需要外键那一个比较好,这样可以少运行一个udpate
        session.save(customer);
        session.save(merchant);
    }

    @Test
    public void testQuery(){
        System.out.println("testQuery");
        //1、
        //默认对关联属性使用懒加载
        //如果session关闭的话,会抛出懒加载异常
        Merchant merchant = (Merchant)session.get(Merchant.class, 1);
        System.out.println(merchant.getMerchantName());

        //2、
        //session.close();
        //Customer customer = merchant.getCustomer();
        //System.out.println(customer.getClass());
        //session.close 之后 这里抛出异常:
        //org.hibernate.LazyInitializationException: could not initialize proxy - no Session
        //java.sql.SQLException: You can't operate on a closed Connection!!!
        //因为关闭session后,merchant这个代理对象是只能读取、不可操作的
        //System.out.println(customer.getCustomerName());

        //3、
        //查询Customer对象时,左外连接条件是customer0_.CUSTOMERID=merchant1_.MERCHANTID
        //应该是customer0_.MERCHANTID=merchant1_.MERCHANTID
        //所以需要到没有外键,即使用one-to-one那一端的映射关系的one-to-one标签里面加上参数property-ref,并且赋值为该端在另一端数的据模型中的对象名
        //如Customer.hbm.xml的one-to-one标签的property-ref值就应该为Merchant.java中的customer(Customer类在Merchant类中的对象名)
        //修改设置后,sql的左外链接条件就变成:customer0_.CUSTOMERID=merchant1_.CUSTOMERID
        Customer customer = merchant.getCustomer();
        System.out.println(customer.getCustomerName());

        //4、
        //如果是直接查询没外键的实体对象的记录时,使用左连接查询,并查出相关对象,并进行初始化,这个是hibernate特性
        Customer customer2 = (Customer)session.get(Customer.class, 1);
        System.out.println(customer2.getCustomerName());
        System.out.println(customer2.getMerchant().getMerchantId()+">>"+customer2.getMerchant().getMerchantName());
    }

}

相关要注意的和需要注意的都写到对应文件的注释里面了


3、基于主键一对一映射
①当从数据表中的外键即是主键时,称为基于主键的一对一关联
②要在两端都创建另一端的对象参数
③两端的映射配置都用one-to-one标签
④一端以另一端主键值来生成外键的时候,这端需要把主键生成规则设为foreign,并在其 one-to-one 节点还应增加 constrained=true 属性, 以使当前的主键上添加外键约束

(1)Customer2.java 使用自增方式生成主键一端的模型类

package com.demo.sshtest2;

public class Customer2 {

    public Integer customerId;
    public String customerName;

    public Merchant2 merchant2;

    public Integer getCustomerId() {
        return customerId;
    }

    public void setCustomerId(Integer customerId) {
        this.customerId = customerId;
    }

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }

    public Merchant2 getMerchant2() {
        return merchant2;
    }

    public void setMerchant2(Merchant2 merchant2) {
        this.merchant2 = merchant2;
    }

}

(2)Merchant2.java 需要使用另一端的数据表的主键来生成自己数据表主键的一端的模型类

package com.demo.sshtest2;

public class Merchant2 {

    public Integer merchantId;
    public String merchantName;

    public Customer2 customer2;

    public Integer getMerchantId() {
        return merchantId;
    }

    public void setMerchantId(Integer merchantId) {
        this.merchantId = merchantId;
    }

    public String getMerchantName() {
        return merchantName;
    }

    public void setMerchantName(String merchantName) {
        this.merchantName = merchantName;
    }

    public Customer2 getCustomer2() {
        return customer2;
    }

    public void setCustomer2(Customer2 customer2) {
        this.customer2 = customer2;
    }

}

(3)Customer2.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">
<!-- Generated 2018-4-16 17:25:43 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest2.Customer2" table="CUSTOMERS2">
        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMERID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMERNAME" />
        </property>

        <one-to-one name="merchant2" class="com.demo.sshtest2.Merchant2"></one-to-one>

    </class>
</hibernate-mapping>

(4)Merchant2.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">
<!-- Generated 2018-4-16 17:25:43 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest2.Merchant2" table="MERCHANTS2">
        <id name="merchantId" type="java.lang.Integer">
            <column name="MERCHANTID" />
            <!-- 使用外键的方式来生成当前的主键 -->
            <generator class="foreign">
                <!-- property属性指定使用当前持久化类的哪一个属性的主键作为外键 -->
                <param name="property">customer2</param>
            </generator>
        </id>
        <property name="merchantName" type="java.lang.String">
            <column name="MERCHANTNAME" />
        </property>

        <!--  
        采用 foreign 主键生成器策略的一端增加 one-to-one 元素映射关联属性,
        其 one-to-one 节点还应增加 constrained=true 属性, 以使当前的主键上添加外键约束
        -->
        <one-to-one name="customer2" class="com.demo.sshtest2.Customer2" constrained="true"></one-to-one>

    </class>
</hibernate-mapping>

(5)TestOne2One.java 测试类

package com.demo.sshtest2;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestOne2One {

    public SessionFactory sessionFactory;
    public Session session;
    public Transaction transaction;

    //基于主键一对一关联步骤
    //1、外键的方式来生成主键一端,主键生成规则generator标签值设为foreign
    //2、使用generator标签类的param标签的property属性指定使用当前持久化类的哪一个属性的主键作为外键
    //3、使用one-to-one标签来添加关联关系,指定关联的对象是哪个,并且使用constrained="true",添加约束
    //4、另外一端使用one-to-one标签来添加关联关系即可



    @Before
    public  void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        System.out.println("init");
    }
    @After
    public  void destory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
        System.out.println("destory");
    }

    @Test
    public void testSave(){
        System.out.println("testSave");
        Merchant2 merchant2 = new Merchant2();
        Customer2 customer2 = new Customer2();
        merchant2.setMerchantName("test-one2");
        customer2.setCustomerName("testOneXXXX2");
        //设定关联关系
        merchant2.setCustomer2(customer2);
        customer2.setMerchant2(merchant2);
        //保存顺序没影响,都不需要再执行update
        session.save(customer2);
        session.save(merchant2);
    }

    @Test
    public void testQuery(){
        System.out.println("testQuery");
        //1、
        //默认对关联属性使用懒加载
        //如果session关闭的话,会抛出懒加载异常
        Merchant2 merchant2 = (Merchant2)session.get(Merchant2.class, 1);
        System.out.println(merchant2.getMerchantName());

        //2、
        //session.close();
        //Customer2 customer2 = merchant2.getCustomer();
        //System.out.println(customer2.getClass());
        //session.close 之后 这里抛出异常:
        //org.hibernate.LazyInitializationException: could not initialize proxy - no Session
        //java.sql.SQLException: You can't operate on a closed Connection!!!
        //因为关闭session后,merchant这个代理对象是只能读取、不可操作的
        //System.out.println(customer2.getCustomerName());

        Customer2 customer2 = merchant2.getCustomer2();
        System.out.println(customer2.getCustomerName());
    }

}

相关注意事项等都写到对应文件的注释里面了


4、 多对多映射
①多对多关系是关系数据库中两个表之间的一种关系, 该关系中第一个表中的一个行可以与第二个表中的一个或多个行相关。第二个表中的一个行也可以与第一个表中的一个或多个行相关
②在代表“多”的一端,需要为另一端创建一个集合对象
③映射关系配置文件里面,两端都使用set标签和many-to-many标签就好了
④两端的配置文件中,其中一端要设置主动维护关联关系(即:inverse=”true”),另一端就不需要或者设为false
⑤这个多对多映射会生成一个中间的连接表,这个表就分别存储着两端的主键值,以此来连接两端

(1)Category.java 其中一端模型类

package com.demo.sshtest3;

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

public class Category {

    public Integer catId;
    public String catName;

    public Set<Item> items = new HashSet<Item>();

    public Integer getCatId() {
        return catId;
    }

    public void setCatId(Integer catId) {
        this.catId = catId;
    }

    public String getCatName() {
        return catName;
    }

    public void setCatName(String catName) {
        this.catName = catName;
    }

    public Set<Item> getItems() {
        return items;
    }

    public void setItems(Set<Item> items) {
        this.items = items;
    }

}

(2)Item.java 另一端模型类

package com.demo.sshtest3;

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

public class Item {

    public Integer itemId;
    public String itemName;

    public Set<Category>categories = new HashSet<Category>();

    public Integer getItemId() {
        return itemId;
    }

    public void setItemId(Integer itemId) {
        this.itemId = itemId;
    }

    public String getItemName() {
        return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    public Set<Category> getCategories() {
        return categories;
    }

    public void setCategories(Set<Category> categories) {
        this.categories = categories;
    }
}

(3)Category.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">
<!-- Generated 2018-4-17 10:09:15 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest3.Category" table="CATEGORY">
        <id name="catId" type="java.lang.Integer">
            <column name="CATID" />
            <generator class="native" />
        </id>
        <property name="catName" type="java.lang.String">
            <column name="CATNAME" />
        </property>
        <set name="items" table="ITEM_CATEGORY" inverse="true" lazy="true">
            <key>
                <column name="CATID" />
            </key>
            <many-to-many class="com.demo.sshtest3.Item" column="ITEMID"/>
        </set>
    </class>
</hibernate-mapping>

(4)Item.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">
<!-- Generated 2018-4-17 10:09:15 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest3.Item" table="ITEM">
        <id name="itemId" type="java.lang.Integer">
            <column name="ITEMID" />
            <generator class="native" />
        </id>
        <property name="itemName" type="java.lang.String">
            <column name="ITEMNAME" />
        </property>
        <!--
        name:指定需要映射的另一端在该数据模型中集合的名字
        table:连接表表明
        inverse:是否主动维护映射关系(其中一端关系映射文件中有一个true就可以了)
        lazy:是否使用懒加载

        key
        column:该数据模型需要映射到连接表的主键名

        many-to-many
        column:另一端数据模型需要映射到连接表的主键名

        另一端配置一样,只不过需要注意inverse是不是不同就好了
        -->
        <set name="categories" table="ITEM_CATEGORY" inverse="false" lazy="true">
            <key>
                <column name="ITEMID" />
            </key>
            <many-to-many class="com.demo.sshtest3.Category" column="CATID"/>
        </set>
    </class>
</hibernate-mapping>

(5)TestMany2Many.java 测试类

package com.demo.sshtest3;

import java.util.Iterator;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestMany2Many {

    public SessionFactory sessionFactory;
    public Session session;
    public Transaction transaction;

    //多对多关联
    //1、因为是多对多关联,所以不能在两端都用外键,因为这样设置的话,使用时,会出现对记录操作不完整等问题,所以要建立一个连接表(分别以两端的id为值,以此把两端数据表的数据关联起来 )
    //2、如果是双向多对多关联,两端都需要使用集合属性
    //3、如果是双向多对多关联,必须要用链接表
    //4、对于双向 n-n 关联, 必须把其中一端的 inverse 设置为 true, 否则两端都维护关联关系可能会造成主键冲突

    //多对多关联步骤
    //1、两端数据模型都要创建对应另一端的集合对象
    //2、生成hbm.xml关系映射文件,并且都修改主键生成规则为native
    //3、使用set标签,指定连接表表名(两端的关系映射文件都需要)
    //4、在set标签内,使用key标签的column属性,指定连接表映射该端的主键字段名
    //5、使用many-to-many标签,指定连接表中另一端需要映射的主键字段名
    //6、在其中一端的映射文件中的set标签内,使用inverse="true",使一端主动维护映射关系(另一端inverse="false"或者默认即可)

    @Before
    public  void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        System.out.println("init");
    }
    @After
    public  void destory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
        System.out.println("destory");
    }
    @Test
    public void testSave(){
        System.out.println("testSave");
        Category category1 = new Category();
        Category category2 = new Category();

        Item item1 = new Item();
        Item item2 = new Item();

        category1.setCatName("C-1");
        category2.setCatName("C-2");

        item1.setItemName("I-1");
        item2.setItemName("I-2");

        category1.getItems().add(item1);
        category1.getItems().add(item2);
        category2.getItems().add(item1);
        category2.getItems().add(item2);

        item1.getCategories().add(category1);
        item1.getCategories().add(category2);
        item2.getCategories().add(category1);
        item2.getCategories().add(category2);

        session.save(category1);
        System.out.println(category1);
        session.save(category2);
        System.out.println(category2);
        session.save(item1);
        System.out.println(item1);
        session.save(item2);
        System.out.println(item2);
    }
    @Test
    public void testQuery(){
        System.out.println("testQuery");
        Category category = (Category) session.get(Category.class, 1);
        System.out.println(category.getCatName()); 

        //需要连接中间表
        Set<Item> items = category.getItems();
        Iterator<Item> it = items.iterator();
        while(it.hasNext()){
            Item itvalue = it.next();
            System.out.println(itvalue.getItemId() + "----" + itvalue.getItemName());
        }
    }
}

4、映射继承
①subclass标签就是为子类嵌入父类的表中而设计的,而且要指定鉴别器,即用subclass一定要有判断类型的一个列,鉴别器指定记录属于哪个类型。
②joined-subclass标签,提供的功能是只能为子类设定外部表,而且没有鉴别器,即子类一张表,父类一张表,子类以父类的主键为外键。
③union-subclass是将父类中的属性,添加到子类对应的表中去了。使用union-class,子类对应的表中的外键则和父类的外键是一样的,因为子类把父类继承的属性,也加到了自己的表当中。
④使用subclass的继承映射(1个数据表,1个映射文件)
⑤使用joined-subclass的继承映射(3个数据表,1个映射文件)
⑥使用union-subclass的继承映射(2个数据表,1个映射文件)

subclass继承映射

(1)TOne.java 父类

package com.demo.sshtest4.subclass;

public class TOne {

    public Integer id;
    public String name;
    public String description;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

}

(2)TTwo.java 子类

package com.demo.sshtest4.subclass;

public class TTwo extends TOne{

    public Integer twoId;
    public String twoName;
    public Integer getTwoId() {
        return twoId;
    }
    public void setTwoId(Integer twoId) {
        this.twoId = twoId;
    }
    public String getTwoName() {
        return twoName;
    }
    public void setTwoName(String twoName) {
        this.twoName = twoName;
    }

}

(3)TOne.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="com.demo.sshtest4.subclass">

    <!-- 如果只是操作父类字段,则辨别者列的值为class标签的discriminator-value的值 -->
    <class name="TOne" table="TONES" discriminator-value="TONE666">

        <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>

        <!-- 这里要注意,字段名不要跟sql语句的关键字相同 不然会导致sql走不动,最后hibernate抛出异常 -->
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>

        <!-- 映射子类 TTwo, 使用 subclass 进行映射 -->
        <!-- 如果还操作了子类字段,则辨别者列的值为subclass标签的discriminator-value的值 -->
        <subclass name="TTwo" discriminator-value="TTWO666">
            <property name="twoId" type="java.lang.Integer" column="TWOID"></property>
            <property name="twoName" type="string" column="TWONAME"></property>
        </subclass>

    </class>
</hibernate-mapping>

(4)HibernateTest.java 测试类

package com.demo.sshtest4.subclass;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {

    //步骤:
    //1、新建一个父类,编写父类的参数
    //2、新建一个子类并继承父类,编写子类的参数
    //3、生成父类关系映射文件,主键生成规则改为native
    //4、使用subclass标签映射子类
    //5、subclass标签类使用property标签配置子类对应数据表的字段
    //6、使用discriminator标签设置辨别者列(column:辨别者列名 type:辨别者字段类型)
    //7、为class标签和subclass标签配置discriminator-value属性值,调用时,如果只是操作父类字段,则辨别者列的值为class标签的discriminator-value的值,如果还操作了子类字段,则辨别者列的值为subclass标签的discriminator-value的值

    //注意:
    //配置辨别者列要在父类主键下,其他字段前写,不然会报错

    //缺点:
    //1、使用了辨别者列.
    //2、子类独有的字段不能添加非空约束.
    //3、若继承层次较深, 则数据表的字段也会较多. 


    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @Before
    public void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = 
                new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                            .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);

        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    @After
    public void destroy(){
        transaction.commit();
        session.close();
        sessionFactory.close();
    }

    //查询:
    //1. 查询父类记录, 只需要查询一张数据表
    //2. 对于子类记录, 也只需要查询一张数据表
    @Test
    public void testQuery(){
        List<TOne> tOnes = session.createQuery("FROM TOne").list();//通过父类获取 所以写"FROM TOne"
        System.out.println(tOnes.size()); 

        List<TTwo> tTwos = session.createQuery("FROM TTwo").list();//通过子类获取 所以写"FROM TTwo"
        System.out.println(tTwos.size()); 
    }

    //插入操作: 
    //1. 对于子类对象只需把记录插入到一张数据表中.
    //2. 辨别者列由 Hibernate自动维护. 
    @Test
    public void testSave(){
        System.out.println("testsave2");
        TOne tOne = new TOne();
        tOne.setName("A");
        tOne.setDescription("AA");

        session.save(tOne);

        TTwo tTwo = new TTwo();
        tTwo.setName("B");
        tTwo.setDescription("BB");
        tTwo.setTwoId(12312);
        tTwo.setTwoName("TTTT");

        session.save(tTwo);
    }
}
joined-subclass继承映射

(1)TThree.java 父类

package com.demo.sshtest4.joinedsubclass;

public class TThree {

    public Integer id;
    public String name;
    public String description;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

}

(2)TFour.java 子类

package com.demo.sshtest4.joinedsubclass;

public class TFour extends TThree{

    public String fourName;
    public String getFourName() {
        return fourName;
    }
    public void setFourName(String fourName) {
        this.fourName = fourName;
    }

}

(3) TThree.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="com.demo.sshtest4.joinedsubclass">

    <class name="TThree" table="TTHREE">

        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>

        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>

        <!-- 映射子类 TFour, 使用 joined-subclass 进行映射 -->
        <joined-subclass name="TFour" table="TFOUR">
            <key column="FID"></key>
            <property name="fourName" type="string" column="FOURNAME"></property>
        </joined-subclass>

    </class>
</hibernate-mapping>

(4)HibernateTest.java 测试类

package com.demo.sshtest4.joinedsubclass;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {

    //步骤:
    //1、新建一个父类,编写父类的参数
    //2、新建一个子类并继承父类,编写子类的参数
    //3、生成父类关系映射文件,主键生成规则改为native
    //4、使用joined-subclass标签映射子类
    //5、在joined-subclass标签下,使用key标签指定子类对应数据表中的主键字段名(这个字段的值对应父类数据表中的主键值)
    //6、在joined-subclass标签下,使用property标签指定子类中独有字段


    //优点:
    //1、不需要使用辨别者列.
    //2、子类独有的字段能添加非空约束.
    //3、冗余字段


    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @Before
    public void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = 
                new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                            .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);

        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    @After
    public void destroy(){
        transaction.commit();
        session.close();
        sessionFactory.close();
    }

    //查询:
    //1. 查询父类记录, 做一个左外连接查询
    //2. 对于子类记录, 做一个内连接查询
    @Test
    public void testQuery(){
        List<TThree> tThree = session.createQuery("FROM TThree").list();//通过父类获取 所以写"FROM TThree"
        System.out.println(tThree.size()); 

        List<TFour> fTFour = session.createQuery("FROM TFour").list();//通过子类获取 所以写"FROM TFour"
        System.out.println(fTFour.size()); 
    }

    //插入操作: 
    //1. 对于子类对象至少需要把记录插入到两张数据表中.
    @Test
    public void testSave(){
        System.out.println("testsave2");
        TThree tThree = new TThree();
        tThree.setName("A");
        tThree.setDescription("AA");

        session.save(tThree);

        TFour tFour = new TFour();
        tFour.setName("B");
        tFour.setDescription("BB");
        tFour.setFourName("TTTT");

        session.save(tFour);
    }
}
union-subclass继承映射

(1).java 父类

package com.demo.sshtest4.unionsubclass;

public class TFive {

    public Integer id;
    public String name;
    public String description;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

}

(2).java 子类

package com.demo.sshtest4.unionsubclass;

public class TSix extends TFive{

    public String sixName;
    public String sixdescription;
    public String getSixName() {
        return sixName;
    }
    public void setSixName(String sixName) {
        this.sixName = sixName;
    }
    public String getSixdescription() {
        return sixdescription;
    }
    public void setSixdescription(String sixdescription) {
        this.sixdescription = sixdescription;
    }

}

(3)TFive.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="com.demo.sshtest4.unionsubclass">

    <class name="TFive" table="TFIVE">

        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="hilo" />
        </id>

        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>

        <union-subclass name="TSix" table="TSIX">
            <property name="sixName" type="string" column="SIXNAME"></property>
            <property name="sixdescription" type="string" column="SIXDESCRIPTION"></property>
        </union-subclass>

    </class>
</hibernate-mapping>

(4)HibernateTest.java 测试类

package com.demo.sshtest4.unionsubclass;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {

    //步骤:
    //1、新建一个父类,编写父类的参数
    //2、新建一个子类并继承父类,编写子类的参数
    //3、生成父类关系映射文件,主键生成规则改为hilo
    //4、使用subclass标签映射子类
    //5、union-subclass标签类使用property标签配置子类对应数据表的字段

    //注意:
    //1、使用 union-subclass 映射策略是不可使用 identity 的主键生成策略, 
    //因为同一类继承层次中所有实体类都需要使用同一个主键种子, 即多个持久化实体对应的记录的主键应该是连续的. 受此影响, 也不该使用 native 主键生成策略, 
    //因为 native 会根据数据库来选择使用 identity 或 sequence
    //2、每一个实体对象都会映射到一个独立的表中,即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中

    //优点:
    //1、不需要使用辨别者列.
    //2、子类独有的字段能添加非空约束.
    //缺点:
    //1、存在冗余字段
    //2、更新父表效率低

    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @Before
    public void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = 
                new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                            .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);

        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    @After
    public void destroy(){
        transaction.commit();
        session.close();
        sessionFactory.close();
    }


    //查询:
    //1. 需要把父表和子表汇总后才查询,性能差
    @Test
    public void testQuery(){
        List<TFive> tFive = session.createQuery("FROM TFive").list();//通过父类获取 所以写"FROM TFive"
        System.out.println(tFive.size()); 

        List<TSix> tSix = session.createQuery("FROM TSix").list();//通过子类获取 所以写"FROM TSix"
        System.out.println(tSix.size()); 
    }

    //插入操作: 
    //1. 对于子类对象只需把记录插入到一张数据表中
    @Test
    public void testSave(){
        System.out.println("testsave2");
        TFive tFive = new TFive();
        tFive.setName("A");
        tFive.setDescription("AA");

        session.save(tFive);

        TSix tSix = new TSix();
        tSix.setName("B");
        tSix.setDescription("BBBBBBBB");
        tSix.setSixName("sixsixsix");
        tSix.setSixdescription("TTTT");

        session.save(tSix);
    }
}

5、hibernate.cfg.xml hibernate配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!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>

        <!-- 配置连接数据库基本信息 -->
        <property name="connection.username">root</property>
        <property name="connection.password"></property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- localhost是地址,如果用默认可以不写localhost,hebernateTEST是数据库名 -->
        <property name="connection.url">jdbc:mysql://localhost/hebernateTEST</property>

        <!-- 配置hibernate基本信息-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 执行操作室是否在控制台打印sql -->
        <property name="show_sql">true</property>
        <!-- 是否对sql格式化 -->
        <property name="format_sql">true</property>

        <!-- 指定自动生成数据表的策略 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 设置 Hibernate 的事务隔离级别 -->
        <property name="connection.isolation">2</property>

        <!-- 设置调用delete()时,OID变成null -->
        <property name="hibernate.use_identifier_rollback">true</property>

        <!--C3P0 数据库连接池-->
        <property name="hibernate.c3p0.max_size">10</property>
        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.timeout">2000</property>
        <property name="hibernate.c3p0.max_statements">10</property>
        <property name="hibernate.c3p0.idle_test_period">2000</property>
        <property name="hibernate.c3p0.acquire_increment">2</property>

        <!--设定JDBC的statement读取数据-->
        <property name="hibernate.jdbc.fetch_size">100</property>
        <property name="hibernate.jdbc.batch_size">50</property>

        <!-- 指定关联的 *.hbm.xml文件(目录结构) 每个.hbm.xml对应一个数据表-->
        <mapping resource="com/demo/sshtest/Customer.hbm.xml"/>
        <mapping resource="com/demo/sshtest/Merchant.hbm.xml"/>
        <mapping resource="com/demo/sshtest2/Customer2.hbm.xml"/>
        <mapping resource="com/demo/sshtest2/Merchant2.hbm.xml"/>
        <mapping resource="com/demo/sshtest3/Category.hbm.xml"/>
        <mapping resource="com/demo/sshtest3/Item.hbm.xml"/>
        <mapping resource="com/demo/sshtest4/subclass/TOne.hbm.xml"/>
        <mapping resource="com/demo/sshtest4/joinedsubclass/TThree.hbm.xml"/>
        <mapping resource="com/demo/sshtest4/unionsubclass/TFive.hbm.xml"/>

    </session-factory>
</hibernate-configuration>

6、注意事项:
①参数名不要跟sql的关键字一样,不然会导致hibernate生成的sql不能用
②映射继承的时候,都只需要为父类创建映射关系配置文件
③多对多映射的时候,会有中间表,配置两端的映射关系时,set标签的table值,要用同一个中间表表名

7、项目目录
项目目录

8、demo
https://download.csdn.net/download/qq_22778717/10357379

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值