在数据库中存储 'large' 数据(由 Java 中的列表表示)的最佳做法是什么?
What is a best practice to store 'large' data, represented by List in Java, in database?
在数据库中存储 'large' 数据(由 Java 中的列表表示)的最佳做法是什么?
我正在考虑 3 种变体:
- 使用“@OneToMany”将数据存储在单独的 table 中。
- 序列化数据并将其存储在父级中table。
- 将数据存储为文件(命名规则?与 id 相同?)。
To be more specific
'Large' 数据实体:
class SingleSleeper{
private Double startPositionOnLeft;
private Double endPositionOnLeft;
private Double startPositionOnRight;
private Double endPositionOnRight;
....
}
class RutEntry{
private Double width;
private Double position;
...
}
在一个父实例中有大约 50 个 SingleSleeper
class 实例和大约 25000 个 RutEntry
class 实例。父实例每天生成约 40 次。
我正在使用 EclipseLink JPA 2.1,derby
Addition
最重要的是,我对 Java 中的最佳可读性感兴趣。但是如果我将太多数据存储到数据库中,我担心数据库速度会显着降低。绝大多数请求将针对 select 特定父实体的 SingleSleeper 或 RutEntry class 的所有实例。我对支持不同的数据库类型不感兴趣,但如果需要,我可以转移到其他数据库。
我想我不会做你的两种变体。
我会向 child 实体添加一个 ManyToOne
(这与您的第一个变体在某种程度上相反):
public class SingleSleeper {
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private ParentEntity parent;
...
}
public class RutEntry {
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private ParentEntity parent;
}
这确保您有一个映射,并且如果您不需要它们,您从不加载 parent object 的所有 25000 个实体(延迟获取确保您甚至不需要加载 parent 实体)。
您可以在parentobject中创建一个OneToMany
和mappedBy
link,如果你真的想要。例如,因为您始终需要 parent 实体中的所有 child object:
class ParentEntity {
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
Collection<SingleSleeper> singleSleepers;
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
Collection<RutEntry> rutEntries;
}
但我不知道 EclipseLink 在这里是如何工作的 - 对于 Hibernate,您至少需要一个额外的 BatchSize
注释来指示它应该一次加载尽可能多的 child 实体。它不能与 parent 实例一起获取(例如,通过将两者定义为 FetchType.EAGER
),因为只允许急切获取一个(否则你将有 25000 * 50 个结果行在SQL select语句对应的结果集).
为 parent 实体加载所有 child 实体的最佳方法是单独加载它们,或者使用 JPQL(更容易阅读,更快写)或 Criteria API(类型安全,但你需要一个 元模型):
ParentEntity parent = entityManager.find(ParentEntity.class, id);
// JPQL:
List<SingleSleeper> singleSleepers = entityManager.createQuery(
"SELECT s FROM SingleSleeper s WHERE s.parent = %parent"
).setParameter("parent", parent).getResultList();
// Or Criteria API:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<SingleSleeper> query = criteriaBuilder.createQuery(SingleSleeper.class);
Root<SingleSleeper> s = query.from(SingleSleeper.class);
query.select(s).where(criteriaBuilder.equal(s.get(SingleSleeper_.parent), parent));
List<SingleSleeper> singleSleepers = entityManager.createQuery(query).getResultList();
这种方法具有三个优点:
- 仍然易于阅读 - 如果您将加载放入它自己的方法中。
- 你可以灵活决定什么时候加载25050children。
- 您也可以加载 children 的子集(通过使用
Query.setFirstResult
和 Query.setMaxResults
修改 createQuery
的结果)。
在数据库中存储 'large' 数据(由 Java 中的列表表示)的最佳做法是什么?
我正在考虑 3 种变体:
- 使用“@OneToMany”将数据存储在单独的 table 中。
- 序列化数据并将其存储在父级中table。
- 将数据存储为文件(命名规则?与 id 相同?)。
To be more specific
'Large' 数据实体:
class SingleSleeper{
private Double startPositionOnLeft;
private Double endPositionOnLeft;
private Double startPositionOnRight;
private Double endPositionOnRight;
....
}
class RutEntry{
private Double width;
private Double position;
...
}
在一个父实例中有大约 50 个 SingleSleeper
class 实例和大约 25000 个 RutEntry
class 实例。父实例每天生成约 40 次。
我正在使用 EclipseLink JPA 2.1,derby
Addition
最重要的是,我对 Java 中的最佳可读性感兴趣。但是如果我将太多数据存储到数据库中,我担心数据库速度会显着降低。绝大多数请求将针对 select 特定父实体的 SingleSleeper 或 RutEntry class 的所有实例。我对支持不同的数据库类型不感兴趣,但如果需要,我可以转移到其他数据库。
我想我不会做你的两种变体。
我会向 child 实体添加一个 ManyToOne
(这与您的第一个变体在某种程度上相反):
public class SingleSleeper {
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private ParentEntity parent;
...
}
public class RutEntry {
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private ParentEntity parent;
}
这确保您有一个映射,并且如果您不需要它们,您从不加载 parent object 的所有 25000 个实体(延迟获取确保您甚至不需要加载 parent 实体)。
您可以在parentobject中创建一个OneToMany
和mappedBy
link,如果你真的想要。例如,因为您始终需要 parent 实体中的所有 child object:
class ParentEntity {
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
Collection<SingleSleeper> singleSleepers;
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
Collection<RutEntry> rutEntries;
}
但我不知道 EclipseLink 在这里是如何工作的 - 对于 Hibernate,您至少需要一个额外的 BatchSize
注释来指示它应该一次加载尽可能多的 child 实体。它不能与 parent 实例一起获取(例如,通过将两者定义为 FetchType.EAGER
),因为只允许急切获取一个(否则你将有 25000 * 50 个结果行在SQL select语句对应的结果集).
为 parent 实体加载所有 child 实体的最佳方法是单独加载它们,或者使用 JPQL(更容易阅读,更快写)或 Criteria API(类型安全,但你需要一个 元模型):
ParentEntity parent = entityManager.find(ParentEntity.class, id);
// JPQL:
List<SingleSleeper> singleSleepers = entityManager.createQuery(
"SELECT s FROM SingleSleeper s WHERE s.parent = %parent"
).setParameter("parent", parent).getResultList();
// Or Criteria API:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<SingleSleeper> query = criteriaBuilder.createQuery(SingleSleeper.class);
Root<SingleSleeper> s = query.from(SingleSleeper.class);
query.select(s).where(criteriaBuilder.equal(s.get(SingleSleeper_.parent), parent));
List<SingleSleeper> singleSleepers = entityManager.createQuery(query).getResultList();
这种方法具有三个优点:
- 仍然易于阅读 - 如果您将加载放入它自己的方法中。
- 你可以灵活决定什么时候加载25050children。
- 您也可以加载 children 的子集(通过使用
Query.setFirstResult
和Query.setMaxResults
修改createQuery
的结果)。