繁体   English   中英

Hibernate:@OneToMany,避免多个选择

[英]Hibernate: @OneToMany, avoid multiple SELECTs

考虑一个人可以拥有很多汽车的例子。 这就是我们使用 @OneToMany 注释的原因:

@Entity
@Table(name = "person")
public class Person  {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "phone")
    private String phone;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "owner")
    private List<Car> cars = new ArrayList<Car>();

    public Person() {
    }

    // Getters setters
}

@Entity
@Table(name = "cars")
public class Car {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @ManyToOne
    private Person owner;

    @Column(name = "description")
    private String description;

    public Car() {
    }

    // Getters setters

持久性和一切正常,但我想改变一些东西以满足我的需要。 当程序启动时,我希望所有人都被加载到 memory 中,比如说在List<Person>中。 所以,我这样做:

List<Person> persons = session.createQuery("from Person", Person.class).list();

但是,因为它是有道理的,Hibernate 也加载汽车。 有没有办法阻止它这样做?

其原因是因为执行以下操作更快:

List<Person> persons = loadAllPersonsFromDatabase();
List<Car> allCars = loadAllCarsFromDatabase();
for (Person p : persons)
{
    List<Car> carsOfThisPerson = findCarsOfThisPerson(allCars,p);
    p.setCars(carsOfThisPerson);
}

因为我想要 memory 中的所有内容。

我知道在 memory 中加载数据库的所有记录不是一种常见的做法,其原因是因为一个是数据库,另一个是 memory。 但是,我的环境是桌面连接,查询速度有点慢(因为数据库是独立的),我确信这些记录永远不会有那么多会导致OutOfMemoryError

我认为同样重要的是要提到将FetchType.EAGER更改为FetchType.LAZY对我不起作用。 这将是相同的,因为在我加载数据后,我为所有人调用getCars()

评论中的@crizis 有一个很好的观点。 我之所以不简单地删除这两个(Person,Car)的关系(做@Transient List<Car> cars ),是因为我想拥有持久性提供的其他功能。 我的意思是,如果我这样做:

Car car = getCarByPerson("John");
car.setDescription("John");

我将能够通过以下方式拯救这辆车:

hibernateSession.save(john);

而不是: hibernateSession.save(car);

另外,如果我删除 John,我希望他的所有汽车也被删除(这就是CASCADE的用武之地),而不是被迫:

for (Car c : john.getCars())
    hibernateSession.delete(c);

管他呢。

在 web 上进行一些实验和搜索后,我发现使用FetchMode.SELECT将完全符合我的要求,这正是我想要的。 我变了:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "owner")
private List<Car> cars = new ArrayList<Car>();

至:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "owner")
@Fetch(value = FetchMode.SUBSELECT)
private List<Car> cars = new ArrayList<Car>();

实际上它只做 2 次选择。

创建一个 memory 转储并分析它,看看是什么在使用所有 memory。 也许您只需要增加最大堆大小。 你也可以让它变得懒惰并在汽车集合上使用Hibernate.initialize 那样的话,我什至认为它可以使用像 SUBSELECT 这样的获取模式。 如果没有任何帮助,我可以推荐使用 Blaze-Persistence Entity Views 将加载的 state 减少到最低限度,并确保使用 SUBSELECT 获取策略。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM