Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 411|回复: 0

[Java框架学习]Hibernate起步(2):关系映射

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-7 00:01:34 | 显示全部楼层 |阅读模式
    关联映射
       
       
               
        我们已经将一个持久化的实体类映射到了数据库表中。现在以这个为基础,再增加一些类的关联。首先添加
        people
        到应用程序中,然后存储他们所参与的一系列
        events
        。
       
       
                                                                                                   
       
       
        1.
                
        映射
        Person
        类
       
       
        Persion
        类的第一部分片段代码如下:
       
       
        package
         events;
       
       
        publicclass
         Person {
       
       
            
        private
         Long
        id
        ;
       
       
            
        privateint
        age
        ;
       
       
            
        private
         String
        firstname
        ;
       
       
            
        private
         String
        lastname
        ;
       
       
            
        public
         Person() {}
       
       
            
        // Accessor methods for all properties, private setter for "id"
       
       
        }
       
      
      
      

       
       
        创建一个新的映射文件,命名为
        Person.hbm.xml
        (不要忘记
        DTD
        关联的声明)
       
       
        <hibernate-mapping>
       
       
            <class name="events.Person" table="PERSON">
       
       
                <id name="id" column="PERSON_ID">
       
       
                    <generator class="native"/>
       
       
                </id>
       
       
                <property name="age"/>
       
       
                <property name="firstname"/>
       
       
                <property name="lastname"/>
       
       
            </class>
       
       
        </hibernate-mapping>
       
       
       
    最后,将新的映射添加到
        Hibernate
        配置文件中:
       
       
        <mapping resource="events/Event.hbm.xml"/>
       
       
        <mapping resource="events/Person.hbm.xml"/>
       
       
        现在,我们在两个实体中创建了暗恋。很显然,人可以参与事件,
        person
        可以参与
        events
        ,而
        events
        可以有参与者。我们需要处理的设计问题是:方向性,多元性以及集合行为。
        Directionality
        ,
        mulitiplicity
        和
        collection behavior
        。
       
       
        2.
                
        单向
        Set-based
        关联
       
       
        我们将在
        Person
        类中添加一个
        events
        集合。这样我们就可以通过调用
        aPerson.getEvents()
        查看某个人参与的事件,而不需要通过执行显示的查询。我们使用一个
        java
        集合,
        Set
        ,因为集合不允许包含重复的元素,并且我们并不关心顺序。
       
       
        我们需要一个单向的,多值的关联,通过
        Set
        来实现。
        Java
        代码如下:
       
       
        public class Person {
       
       
            private Set events = new HashSet();
       
       
            public Set getEvents() {
       
       
                return events;
       
       
            }
       
       
            public void setEvents(Set events) {
       
       
                this.events = events;
       
       
            }
       
       
        }
       
       
            在映射关联之前,考虑一下另外一个方面。很显然,可以只维持单向性。或者,可以在
        Event
        类中也创建一个集合,如果我们需要双向查询功能,例如
        anEvent.getParticipants()
        。从功能的角度来说,这不是必须的。可以通过显示的查询来获取某个事件
        event
        的参与者
        participants
        。但是从这个讨论中,关联的多重性
        mulitiplicity
        是清楚的:
        ”many”
        作用两者,我们把它叫做
        many-to-many
        关联。因此,我们使用
        Hibernate
        的
        many-to-many
        映射:
       
       
        <class name="events.Person" table="PERSON">
       
       
            <id name="id" column="PERSON_ID">
       
       
                <generator class="native"/>
       
       
            </id>
       
       
            <property name="age"/>
       
       
            <property name="firstname"/>
       
       
            <property name="lastname"/>
       
       
            <set name="events" table="PERSON_EVENT">
       
       
                <key column="PERSON_ID"/>
       
       
                <many-to-many column="EVENT_ID" class="events.Event"/>
       
       
            </set>
       
       
        </class>
       
       
        Hibernate包含所有的集合映射,<set>是最常用的。对于一个many-to-many关联,,需要一个关联数据库表,表中的每一行代表一个person与event的连接。表的名字通过set元素的table属性进行设置。Person端的关联的主键的列名通过<key>定义,使用<many-to-many>元素的column属性对event端进行设置。同时,Hibernate需要知道集合中对象的类名称。(关联的集合的另一端的类)。
       
       
        这个映射的数据库
        schema
        如下所示:
       
       
       
       
       
         
       
       
        3.
                
        在
        EventManager
        中,将
        people
        和
        events
        结合在一起,代码如下:
       
       
        privatevoid
         addPersonToEvent(Long personId, Long eventId) {
       
       
                      Session session = HibernateUtil.getSessionFactory().getCurrentSession();
       
       
                      session.beginTransaction();
       
       
                      Person aPerson = (Person) session.load(Person.
        class
        , personId);
       
       
                      Event anEvent = (Event) session.load(Event.
        class
        , eventId);
       
       
                      aPerson.getEvents().add(anEvent);
       
       
                      session.getTransaction().commit();
       
       
               }
       
       
        加载完一个
        Person
        和
        Event
        对象后,使用正常的集合方法修改集合。正如你所看到的,没有显示的调用
        update()
        或者
        save()
        方法,
        Hibernate
        自动的检测集合是否被修改,是否需要保存。这叫做
        automatic dirty checking
        。(也就是说,他们只在一个工作单元内就已经被加载和保存)。
        Hibernate
        通过在后台进行变化的监视和
        SQL
        的执行。同步数据库内存状态的处理,通常实在工作单元的结束时进行的,叫做
        flushing
        。在我们的代码中,工作单元以事务的
        commit
        或者
        rollback
        结束的。这是在
        Hibernate
        配置文件的
        thread
        选项中设置的
        CurrentSessionContext
        。
       
       
         
       
       
       
         
       
       
        到目前为止,完成这个练习只需要添加一个新的
        action
        ,以便在命令行进行调用的时候使用。如果你需要
        person
        或者
        event
        的标志符,
        save()
        方法可以返回。
       
       
        else if (args[0].equals("addpersontoevent")) {
       
       
            Long eventId = mgr.createAndStoreEvent("My Event", new Date());
       
       
            Long personId = mgr.createAndStorePerson("Foo", "Bar");
       
       
            mgr.addPersonToEvent(personId, eventId);
       
       
            System.out.println("Added person " + personId + " to event " + eventId);
       
       
        }
        运行:  C:        est>h.bat C:        est>set classpath=.;c:        estlibhibernate3.jar;c:        estlibmysql-connector-java-3.1.10-bin.jar;
    c:        estlibcommons-logging-1.0.4.jar;c:        estlibdom4j-1.6.1.jar;c:        estlibcommons-collections-2.1.1.jar;
    c:        estlibc3p0-0.9.1.jar;c:        estlibasm.jar;c:        estlibcglib-2.1.3.jar;c:        estlibjta.jar;c:        estlibantlr- 2.7.6.jar C:        est>javac -d . *.java

    C:        est>java events.EventManager addpersontoevent 结果:

      
       
        4.
                
        我们给
        Person
        实体添加了一个集合的值类型对象。如果需要存储邮件地址,此时的值类型是
        String
        ,集合的类型仍然是
        Set
        :
       
       
        private Set emailAddresses = new HashSet();
       
       
        public Set getEmailAddresses() {
       
       
            return emailAddresses;
       
       
        }
       
       
        public void setEmailAddresses(Set emailAddresses) {
       
       
            this.emailAddresses = emailAddresses;
       
       
        }
       
       
        这个集合的映射为:
       
       
        <set name="emailAddresses" table="PERSON_EMAIL_ADDR">
       
       
            <key column="PERSON_ID"/>
       
       
            <element type="string" column="EMAIL_ADDR"/>
       
       
        </set>
       
       
        对比两个集合的不同:
       
       
        <
        set
        name
        =
        "events"
        table
        =
        "PERSON_EVENT"
        >
       
       
               
        <
        key
        column
        =
        "PERSON_ID"
        />
       
       
               
        <
        many-to-many
        column
        =
        "EVENT_ID"
        class
        =
        "events.Event"
        />
       
       
        </
        set
        >
       
       
        <
        set
        name
        =
        "emailAddresses"
        table
        =
        "PERSON_EMAIL_ADDR"
        >
       
       
               
        <
        key
        column
        =
        "PERSON_ID"
        />
       
       
               
        <
        element
        type
        =
        "string"
        column
        =
        "EMAIL_ADDR"
        />
       
       
        </
        set
        >
       
       
        和之前的配置不同的是
        element
        元素,这个元素说明了集合中不包含对其他实体的关联,而只是
        String
        类型的元素。(小写的
        string
        说明它是一个
        Hibernate
        映射的类型
        /
        转换器)。同样,
        set
        元素的
        table
        属性指定了集合的数据库表的名称,
        key
        元素定义了集合表的外键,
        element
        元素的
        column
        属性定义了存储
        String
        值的列的名称。
       
       
        更新后的
        Schema
        如下:
       
       
       
       
       
        可以发现,集合表的主键事实上是一个联合主键,使用所有的列。这也表明了每个人的邮件地址不可以重复,这也是
        Java
        语言中
        Set
        类所要求的。
       
       
        现在可以将元素加入到这个集合中,和关联
        persons
        和
        events
        的方式一样。
       
       
               
        privatevoid
        addEmailToPerson
        (Long personId, String emailAddress) {
       
       
                      Session session = HibernateUtil.getSessionFactory().getCurrentSession();
       
       
                      session.beginTransaction();
       
       
                      Person aPerson = (Person) session.load(Person.
        class
        , personId);
       
       
                      
        // The getEmailAddresses() might trigger a lazy load of the collection
       
       
                      aPerson.getEmailAddresses().add(emailAddress);
       
       
                      session.getTransaction().commit();
       
       
               }
       
       
        这次,我们不使用查询语句来初始化集合元素,而是使用
        getter
        方法来获取它。
       
       
        5.
                
        双向关联
       
       
        接下来创建一个双向关联映射
        -
        创建
        person
        和
        event
        的双向关联。当然,数据库
        Schema
        不变,仍然使用
        many-to-many
        的多重关系。关系数据库比网络编程语言要灵活得多,所以不需要做任何修改,数据就可以以任何方式来查看和获取。
       
       
        首先,给
        Event
        类添加一个集合。
       
       
               
        private
         Set
        participants
         =
        new
         HashSet();
       
       
               
        public
         Set getParticipants() {
       
       
                      
        return
        participants
        ;
       
       
               }
       
       
               
        publicvoid
         setParticipants(Set participants) {
       
       
                      
        this
        .
        participants
         = participants;
       
       
               }
       
       
        然后,在
        Event.hbm.xml
        中添加关联的映射:
       
       
        <set name="participants" table="PERSON_EVENT" inverse="true">
       
       
            <key column="EVENT_ID"/>
       
       
            <many-to-many column="PERSON_ID" class="events.Person"/>
       
       
        </set>
       
       
        这和
        Person
        中的配置是一样的。需要注意的是
        key
        元素和
        many-to-many
        元素中的列的名字。最重要的添加是
        inverse=”true”
        属性。
       
       
        这意味着当需要查询两者之间的关联信息时,需要考虑
        Persion
        类。
       
       
         
       
       
        6.
                
        首先,记住
        Hibernate
        不影响
        Java
        语义。我们在单向的例子中是如何创建的
        Person
        与
        Event
        之间的关联的?添加一个
        Event
        对象到一个
        Person
        实例的
        Event
        集合中。所以,所以,很显然,如果想使这个
        link’
        是双向工作的,我们必须将一个
        Person
        实例添加到一个
        Event
        的集合中。在两边都设置
        link
        (
        setting the link on both sides
        )是必须的,千万别忘记这样做。
       
       
         
       
       
        很多程序开发人员为了通过创建一个
        link
        管理方法来预防上面的问题,例如在
        Person
        中:
       
       
        protected Set getEvents() {
       
       
            return events;
       
       
        }
       
       
        protected void setEvents(Set events) {
       
       
            this.events = events;
       
       
        }
       
       
        public void addToEvent(Event event) {
       
       
            this.getEvents().add(event);
       
       
            event.getParticipants().add(this);
       
       
        }
       
       
        public void removeFromEvent(Event event) {
       
       
            this.getEvents().remove(event);
       
       
            event.getParticipants().remove(this);
       
       
        }
       
       
        注意,这里的
        get
        和
        set
        方法都是
        protected
        ,允许同一个包中,子类来访问这些方法,而除此之外的类却不能访问。在
        Event
        类中也需要同样处理。
       
       
        那么
        inverse
        属性到底是做什么的呢?对于,对于
        Java
        来说,一个双向的
        link
        ,存在一个在双向正确的设置引用的问题。
        Hibernate
        没有足够的信息来正确的安排
        SQL
        的
        INSERT
        和
        UPDATE
        语句(为了避免违反约束),需要一个合适的办法来处理双向关联。使关联的一方是
        inverse
        ,可以使
        Hibernate
        忽略它,只是把它当作另一方的镜像。这就是
        Hibernate
        所需要的。你所需要记住的规则是明了的:所有的双向关联需要将一方设置为
        inverse
        。在
        one-to-many
        关联中,必须为
        many
        &#65533;,在
        many-to-many
        中,可以是任意一侧。
       
       
         
       

       
         
         
          
          

            
          

            
          
         
       

      


    源码下载:http://www.hnzz3z.com:8103/zz3zcwb/test1.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 10:18 , Processed in 0.436847 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表