【问题标题】:Hibernate 4.3 Spring 4 batch insert with association tableHibernate 4.3 Spring 4批量插入与关联表
【发布时间】:2014-02-02 15:28:32
【问题描述】:

首先让我说,我不是 Java 程序员,但我正在尝试学习一些(对我而言)新的东西。

我有以下两个 DAO: 货架

package org.sample.bookshelf.model;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity  
@Table(name="shelves") 
public class Shelf {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(cascade=CascadeType.ALL)  
    @JoinTable(name="shelf_books",   
        joinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")},  
        inverseJoinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")}  
    )
    private Set<Book> shelfBooks; 

    public Shelf() {}

    public Shelf(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }


    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Set<Book> getShelfBooks() {
        return shelfBooks;
    }
    public void setShelfBooks(Set<Book> shelfBooks) {
        this.shelfBooks = shelfBooks;
    }
}

预订

package org.sample.bookshelf.model;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity  
@Table(name="books") 
public class Book {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    private String title;

    @OneToOne(cascade=CascadeType.ALL)
    @JoinTable(name="shelf_books",
        joinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")},  
        inverseJoinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")}  
    )
    private Shelf block;

    public Book() {
    }

    public Book(String title)
    {
        this.title = title;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Shelf getShelf() {
        return block;
    }

    public void setShelf(Shelf block) {
        this.block = block;
    }
}

如您所见,它们是按表关联的:*shelf_books*

现在在 BookDaoImpl 中,我想拥有具有 all-or-nothing 行为的方法, 这可以让我保存多本书,如下所示:

@Override
public void saveMulti(List<Book> books) {
    Session sess = sessionFactory.openSession();
    org.hibernate.Transaction tx = null;
    try {
        tx = sess.beginTransaction();
        int i = 0;
        for (Book b : books) {
            logger.debug(String.format("%d %s ", b.getId(), b.getTitle()));
            sess.saveOrUpdate(b);

            i++;
            if (i == 20) {
                sess.flush();
                sess.clear();
                i = 0;
            }
        }
        logger.debug("saving...");
        tx.commit();
        logger.debug("done...");

    } catch (RuntimeException e) {
        if (tx != null) tx.rollback();
        e.printStackTrace();

    } finally {
        sess.close();
    }
}

由于某种原因,关联表的数据被添加而不是被删除,它在以下包含 delete collection org.sample.bookshelf.model.Shelf.shelfBooks的日志中可见:

16:08:13,857 DEBUG BookDaoImpl:58 - saving...
16:08:13,857 DEBUG AbstractTransactionImpl:175 - committing
16:08:13,857 DEBUG AbstractFlushingEventListener:149 - Processing flush-time cascades
16:08:13,857 DEBUG AbstractFlushingEventListener:189 - Dirty checking collections
16:08:13,859 DEBUG AbstractFlushingEventListener:123 - Flushed: 0 insertions, 1 updates, 0 deletions to 11 objects
16:08:13,859 DEBUG AbstractFlushingEventListener:130 - Flushed: 0 (re)creations, 0 updates, 1 removals to 0 collections
16:08:13,859 DEBUG EntityPrinter:114 - Listing entities:
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=2, title=The City of the Sun, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Shelf{id=1, shelfBooks=null, name=dystopia}
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=1, title=1984, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=6, title=Logan's Run, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=5, title=Slaughterhouse Five, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=4, title=Fahrenheit 451, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=3, title=The Honeymoon Trip of Mr. Hamilton, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=10, title=Brave New World, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=9, title=Lord of the Flies, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=8, title=Do Androids Dream of Electric Sheep?, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=7, title=The Futurological Congress, block=org.sample.bookshelf.model.Shelf#1}
16:08:13,867 DEBUG SQL:109 - /* update org.sample.bookshelf.model.Shelf */ update shelves set name=? where id=?
16:08:13,869 DEBUG AbstractCollectionPersister:1174 - Deleting collection: [org.sample.bookshelf.model.Shelf.shelfBooks#1]
16:08:13,869 DEBUG SQL:109 - /* delete collection org.sample.bookshelf.model.Shelf.shelfBooks */ delete from shelf_books where shelf_id=?
16:08:13,870 DEBUG AbstractCollectionPersister:1232 - Done deleting collection
16:08:14,199 DEBUG JdbcTransaction:113 - committed JDBC Connection
16:08:14,199 DEBUG JdbcTransaction:126 - re-enabling autocommit
16:08:14,200 DEBUG BookDaoImpl:60 - done...

我猜出于某种原因 Shelf 不知道添加的书籍,为了使其完整,这就是我添加数据的方式:

        String titles[] = {
                "1984",
                "The City of the Sun",
                "The Honeymoon Trip of Mr. Hamilton",
                "Fahrenheit 451",
                "Slaughterhouse Five",
                "Logan's Run",
                "The Futurological Congress",
                "Do Androids Dream of Electric Sheep?",
                "Lord of the Flies",
                "Brave New World",      
        };
        Vector<Book> books = new Vector<Book>(titles.length);
        for (int i=0; i<titles.length; ++i) {
            Book book = new Book(titles[i]);
            book.setShelf(shelf);
            books.add(book);
        }
        bookDao.saveMulti(books);

如你所见,我没有在任何地方调用 shelf.setShelfBooks,如果我这样做,一切似乎都很好,但是 hibernate 的作用,看起来很糟糕,看看片段以下日志:

16:20:15,015 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=8, title=Do Androids Dream of Electric Sheep?, block=org.sample.bookshelf.model.Shelf#1}
16:20:15,015 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=7, title=Fahrenheit 451, block=org.sample.bookshelf.model.Shelf#1}
16:20:15,021 DEBUG SQL:109 - /* update org.sample.bookshelf.model.Shelf */ update shelves set name=? where id=?
16:20:15,023 DEBUG AbstractCollectionPersister:1174 - Deleting collection: [org.sample.bookshelf.model.Shelf.shelfBooks#1]
16:20:15,023 DEBUG SQL:109 - /* delete collection org.sample.bookshelf.model.Shelf.shelfBooks */ delete from shelf_books where shelf_id=?
16:20:15,026 DEBUG AbstractCollectionPersister:1232 - Done deleting collection
16:20:15,027 DEBUG AbstractCollectionPersister:1256 - Inserting collection: [org.sample.bookshelf.model.Shelf.shelfBooks#1]
16:20:15,028 DEBUG SQL:109 - /* insert collection row org.sample.bookshelf.model.Shelf.shelfBooks */ insert into shelf_books (shelf_id, book_id) values (?, ?)
16:20:15,030 DEBUG SQL:109 - /* insert collection row org.sample.bookshelf.model.Shelf.shelfBooks */ insert into shelf_books (shelf_id, book_id) values (?, ?)
16:20:15,030 DEBUG SQL:109 - /* insert collection row org.sample.bookshelf.model.Shelf.shelfBooks */ insert into shelf_books (shelf_id, book_id) values (?, ?)

我有感觉,我做错了,谁能告诉我应该以正确的方式来做我想做的事?

【问题讨论】:

    标签: spring hibernate one-to-many jointable batch-insert


    【解决方案1】:

    我没有比这两个实体更进一步,因为它们的映射是错误的,这可能是你的问题的原因。

    第一个问题:

    您将书籍声明为

    @OneToMany(cascade=CascadeType.ALL)  
    @JoinTable(name="shelf_books",   
        joinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")},  
        inverseJoinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")}  
    )
    private Set<Book> shelfBooks; 
    

    这意味着存在 OneToMany 关联,由连接表映射。

    然后你声明如下:

    @OneToOne(cascade=CascadeType.ALL)
    @JoinTable(name="shelf_books",
        joinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")},  
        inverseJoinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")}  
    )
    private Shelf block;
    

    这没有意义。

    您可能希望关联是双向的。由于一侧是 OneToMany,因此另一侧必须是 ManyToOne。在双向关联中,一侧必须是反面(使用 mappedBy 属性,并且不声明关联的映射方式,因为它已经在另一侧定义),并且一侧必须是所有者侧。在 OneToMany 关联中,反面必须是一侧。所以账套必须声明为:

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "block") 
    private Set<Book> shelfBooks; 
    

    还要注意,在 ManyToOne 上使用 CascadeType.ALL 没有多大意义。您不希望书架在其中包含的一本书被删除后立即被删除。除非您真正了解其含义,否则我建议您删除所有级联。

    【讨论】:

    • 原来是ManyToOne,不知道那个OneToOne是从哪里来的。感谢所有提示和帮助,现在似乎工作正常。
    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 2012-02-16
    • 2015-07-03
    • 2011-07-04
    • 1970-01-01
    相关资源
    最近更新 更多