首先我要说的是,我不是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();
}
}
由于某种原因,添加数据到关联表而不是已删除,它在包含删除集合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 (?, ?)
我有感觉,我做错了,谁能告诉我应该 PROPER 做我喜欢的方式?
答案 0 :(得分: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没有多大意义。只要删除了包含其中一本书的书架,就不希望删除该书架。除非你真的明白其含义,否则我建议删除所有级联。