Hibernate(带注释) - 如何开始 [英] Hibernate (with annotations) - how to get started

查看:85
本文介绍了Hibernate(带注释) - 如何开始的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着开始使用hibernate,但我找不到任何我理解的教程。
我想创建一个简单的应用程序来开始,但我真的不知道从哪里开始。

我用java很先进,虽然只使用了eclipse。那么,我应该在哪里配置它使用的数据库,等等?



我熟悉ORM的概念,以及Hibernate是什么。我不知道或理解的是从哪里开始我的申请。我打算使用注释,但是在注释了我的POJO之后,我该怎么办?我在哪里指定数据库服务器,用户等?我还需要做什么?

解决方案

我的经历和背景很相似,我也很难找到一个教程它解决了我的开发偏好(与您的开发偏好类似):


  • 优先考虑JPA对XML的批注,只在JPA对应方执行时添加Hibernate批注

  • 使用Hibernate的SessionFactory / Session来访问持久数据而不是JPA EntityManager

  • 尽可能使用不可变类



我阅读了大部分 Hibernate的Java持久性,并且花费很长时间将此用例与它提供的所有其他选项(Hibernate / JPA格式的XML配置,xdoclet注释等)分开。



如果可用的文档需要站点和活动,它对我来说会更有意义我会朝这个方向推动我,而不是给我一堆选择并想知道去哪里。由于缺乏这一点,我通过将标准 Hibernate教程转换为注释。

配置




  • 保持休眠状态。 (见下文)。
  • 使用JPA批注显式定义数据库列/表名,以便获得您想要的模式。你可以使用SchemaExport.create(true,false)来检查它。请注意,如果Hibernate尝试更新现有数据库上的模式(例如,不能为已包含空值的列添加NOT NULL约束),则可能无法获得您期望的确切模式。

  • 使用AnnotationConfiguration.addAnnotatedClass()。addAnnotatedClass()创建SessionFactory的配置...



这是我的hibernate.cfg.xml中。它只设置属性,并明确避免任何映射配置。

 <?xml version ='1.0'encoding ='utf- 8' >?; 
<!DOCTYPE hibernate-configuration PUBLIC - // Hibernate / Hibernate配置DTD 3.0 // EN
http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd\"> ;
< hibernate-configuration>
< session-factory>
<! - 关于要使用的数据库的信息 - >
< property name =connection.driver_class> org.hsqldb.jdbcDriver< / property>
< property name =connection.url> jdbc:hsqldb:hsql:// localhost< / property>
< property name =connection.username> sa< / property>
< property name =connection.password>< / property>
< property name =connection.pool_size> 1< / property>
< property name =dialect> org.hibernate.dialect.HSQLDialect< / property>

<! - Misc。休眠配置 - >
< property name =hbm2ddl.auto>更新< / property>
< property name =current_session_context_class>线程< / property>
< property name =cache.provider_class> org.hibernate.cache.NoCacheProvider< / property>
< property name =show_sql> false< / property>
< / session-factory>
< / hibernate-configuration>



范围




  • 在每个Manager / DAO类之外开始/提交/回滚事务。我不知道为什么教程的EventManager启动/提交自己的事务,因为本书将此标识为反模式。对于本教程中的servlet,可以通过创建一个Filter来启动事务,调用FilterChain的其余部分,然后提交/回滚事务。
  • 类似地,make将SessionFactory传递给每个Manager / DAO类,然后在任何需要访问数据的时候调用SessionFactory.getCurrentSession()。当需要对DAO类进行单元测试时,请制作连接到内存数据库的SessionFactory(例如jdbc:hsqldb:mem:test)并将其传递到正在测试的DAO中。
  • b

    $ b

    例如,我的EventManager版本中有一些片段:

      public final class EventManager {

    private final SessionFactory sessionFactory;
    $ b $ **用于JSP的默认构造函数* /
    public EventManager(){

    this.sessionFactory = HibernateUtil.getSessionFactory();

    $ b $ ** @param非空访问数据存储会话* /
    public EventManager(SessionFactory sessionFactory){

    this.sessionFactory = sessionFactory;
    }

    / ** @return Nonnull事件;如果不存在,则为空* /
    public List< Event> getEvents(){

    final Session db = this.sessionFactory.getCurrentSession();
    return db.createCriteria(Event.class).list();
    }

    / **
    *创建并存储没有人员尚未注册的事件。
    * @param title Nonnull;请参阅{@link Event}
    * @param date Nonnull;请参阅{@link事件}
    * @return创建的Nonnull事件
    * /
    public Event createEvent(String title,Date date){

    final事件事件= new Event(title,date,new HashSet< Person>());
    this.sessionFactory.getCurrentSession()。save(event);
    返回事件;
    }

    / **
    *为指定事件注册指定人员。
    * @param personId现有人员的ID
    * @param eventId现有事件的ID
    * /
    public void register(long personId,long eventId){

    最终会话db = this.sessionFactory.getCurrentSession();
    final Person person =(Person)db.load(Person.class,personId);
    final Event event =(Event)db.load(Event.class,eventId);
    person.addEvent(event);
    event.register(person);
    }

    ...其他查询/更新方法...
    }



    数据类




    • 字段为私有

    • Getter方法返回防御因为Hibernate可以直接访问字段

    • 除非真的必须添加setter方法。

    • 当需要更新某些字段时在课堂上,以保持封装的方式进行。将event.addPerson(person)而不是event.getPeople()。add(person)称为像event.addPerson(person)更为安全。例如,


    例如,只要您记得Hibernate在需要时直接访问字段,我发现这个Event的实现更容易理解。

      @Entity(name =EVENT)
    public final class Event {

    private @Id @GeneratedValue @Column(name =EVENT_ID)Long id; //可空值

    / *商业密钥属性(假定始终存在)* /
    private @Column(name =TITLE,nullable = false)字符串标题;

    @Column(name =DATE,nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    私人日期日期;

    / *与其他对象的关系* /
    @ManyToMany
    @JoinTable(
    name =EVENT_PERSON,
    joinColumns = {@JoinColumn =EVENT_ID_FK,nullable = false)},
    inverseJoinColumns = {@JoinColumn(name =PERSON_ID_FK,nullable = false)})
    private Set< Person>注册; //非空

    public Event(){/ *为框架使用所必需* /}

    / **
    * @param title非空名称事件
    * @param date事件发生的非空日期
    * @param参与者参与此事件的非空人
    * /
    public Event(字符串标题,日期日期,设置<人>参与者){

    this.title = title;
    this.date = new Date(date.getTime());
    this.registrants = new HashSet< Person> (参加者);

    $ b $ *查询方法* /

    / ** @return用于持久化的可空的ID * /
    public Long getId(){

    返回this.id;
    }

    public String getTitle(){

    return this.title;
    }

    public Date getDate(){

    return new Date(this.date.getTime());
    }

    / ** @return如果有的话,Nonnull人员注册此事件。 * /
    public Set< Person> getRegistrants(){

    返回新的HashSet< Person> (this.registrants);
    }

    / *更新方法* /

    公共无效注册(人员){

    this.registrants.add(person );
    }
    }

    希望有帮助!


    I'm trying to get started with hibernate, but I can't find any tutorials I understand. I'm trying to create a simple app to get started, but I've really no idea where to get started.

    I'm pretty advanced with java, although only used eclipse really. So.. where do I configure what DB it uses, and alike?

    [edit]
    I'm familiar with the concepts of ORM, and what Hibernate is. What I don't know or understand, is where to begin my application. I intend to use annotations, but, after annotating my POJOs, what do I do? Where do I specify database server, user, etc? What else do I need to do?

    解决方案

    My experiences and background were similar, and I also had a hard time finding a tutorial that addressed my development preferences (which seem similar to yours):

    • Prefer JPA annotations over XML, only adding Hibernate annotations when the JPA counterparts do not suffice
    • Use Hibernate's SessionFactory / Session to access persistent data rather than JPA EntityManager
    • Use immutable classes wherever possible

    I read most of Java Persistence with Hibernate, and it took a long time to separate this use case from all the other options that it presents (XML configuration in Hibernate/JPA format, xdoclet "annotations", etc...).

    It would have made so much more sense to me if the available documentation would take a stand and actively push me in this direction instead of giving me a bunch of options and wondering where to go. Lacking that, I learned the following lessons by converting the standard Hibernate Tutorial over to annotations.

    Configuration

    • Keep hibernate.cfg.xml to the bare minimum (see below).
    • Define database column / table names explicitly with the JPA annotations so you get exactly the schema you want. You can double-check it by using SchemaExport.create(true, false). Note that you may not get the exact schema you expect if Hibernate tries to update the schema on an existing database (for example, you can't add a NOT NULL constraint to a column that already contains null values).
    • Create the SessionFactory's Configuration using AnnotationConfiguration.addAnnotatedClass().addAnnotatedClass()...

    Here's my copy of hibernate.cfg.xml. It only sets properties, and explicitly avoids any mapping configuration.

    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
        <session-factory>
            <!-- Information about the database to be used -->
            <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
            <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
            <property name="connection.username">sa</property>
            <property name="connection.password"></property>
            <property name="connection.pool_size">1</property>
            <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
    
            <!-- Misc. Hibernate configuration -->
            <property name="hbm2ddl.auto">update</property>
            <property name="current_session_context_class">thread</property>
            <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
            <property name="show_sql">false</property>
        </session-factory>
    </hibernate-configuration>
    

    Scope

    • Begin/commit/rollback transactions outside each Manager / DAO class. I have no idea why the tutorial's EventManager starts/commits its own transactions, as the book identifies this as being an anti-pattern. For the servlet in the tutorial, this can be done by making a Filter that starts the transaction, invokes the rest of the FilterChain, and then commits/rolls back the transaction.
    • Similarly, make the SessionFactory outside and pass it in to each Manager / DAO class, which then calls SessionFactory.getCurrentSession() any time it needs to access data. When it comes time to unit test your DAO classes, make your own SessionFactory that connects to an in-memory database (such as "jdbc:hsqldb:mem:test") and pass it into the DAO being tested.

    For example, some snippets from my version of EventManager:

    public final class EventManager {
    
    private final SessionFactory sessionFactory;
    
    /** Default constructor for use with JSPs */
    public EventManager() {
    
        this.sessionFactory = HibernateUtil.getSessionFactory();
    }
    
    /** @param Nonnull access to sessions with the data store */
    public EventManager(SessionFactory sessionFactory) {
    
        this.sessionFactory = sessionFactory;
    }
    
        /** @return Nonnull events; empty if none exist */
    public List<Event> getEvents() {
    
        final Session db = this.sessionFactory.getCurrentSession();
        return db.createCriteria(Event.class).list();
    }
    
    /**
     * Creates and stores an Event for which no people are yet registered.
     * @param title Nonnull; see {@link Event}
     * @param date Nonnull; see {@link Event}
     * @return Nonnull event that was created
     */
    public Event createEvent(String title, Date date) {
    
        final Event event = new Event(title, date, new HashSet<Person> ());
        this.sessionFactory.getCurrentSession().save(event);
        return event;
    }
    
    /**
     * Registers the specified person for the specified event.
     * @param personId ID of an existing person
     * @param eventId ID of an existing event
     */
    public void register(long personId, long eventId) {
    
        final Session db = this.sessionFactory.getCurrentSession();
        final Person person = (Person) db.load(Person.class, personId);
        final Event event = (Event) db.load(Event.class, eventId);
        person.addEvent(event);
        event.register(person);
    }
    
    ...other query / update methods...
    }
    

    Data classes

    • Fields are private
    • Getter methods return defensive copies since Hibernate can access the fields directly
    • Don't add setter methods unless you really have to.
    • When it is necessary to update some field in the class, do it in a way that preserves encapsulation. It's much safer to call something like event.addPerson(person) instead of event.getPeople().add(person)

    For example, I find this implementation of Event much simpler to understand as long as you remember that Hibernate accesses fields directly when it needs to.

    @Entity(name="EVENT")
    public final class Event {
    
        private @Id @GeneratedValue @Column(name="EVENT_ID") Long id; //Nullable
    
        /* Business key properties (assumed to always be present) */
        private @Column(name="TITLE", nullable=false) String title;
    
        @Column(name="DATE", nullable=false) 
        @Temporal(TemporalType.TIMESTAMP)
        private Date date;
    
        /* Relationships to other objects */
        @ManyToMany
        @JoinTable(
            name = "EVENT_PERSON",
            joinColumns = {@JoinColumn(name="EVENT_ID_FK", nullable=false)},
            inverseJoinColumns = {@JoinColumn(name="PERSON_ID_FK", nullable=false)})
        private Set<Person> registrants; //Nonnull
    
        public Event() { /* Required for framework use */ }
    
        /**
         * @param title Non-empty name of the event
         * @param date Nonnull date at which the event takes place
         * @param participants Nonnull people participating in this event
         */
        public Event(String title, Date date, Set<Person> participants) {
    
            this.title = title;
            this.date = new Date(date.getTime());
            this.registrants = new HashSet<Person> (participants);
        }
    
        /* Query methods */
    
        /** @return Nullable ID used for persistence */
        public Long getId() {
    
            return this.id;
        }
    
        public String getTitle() {
    
            return this.title;
        }
    
        public Date getDate() {
    
            return new Date(this.date.getTime());
        }
    
        /** @return Nonnull people registered for this event, if any. */
        public Set<Person> getRegistrants() {
    
            return new HashSet<Person> (this.registrants);
        }
    
        /* Update methods */
    
        public void register(Person person) {
    
            this.registrants.add(person);
        }
    }
    

    Hope that helps!

    这篇关于Hibernate(带注释) - 如何开始的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆