在多对多关系中添加新条目时,我遇到了一个问题,因为列表太大了。前任:
Item item = new Item(1);
Category cat = dao.find(1, Category.class);
List<Category> list = new ArrayList<>();
list.add(cat);
item.setCategoryList(list);
cat.getItemList().add(item);
问题是category itens列表非常庞大,有很多itens,因此执行cat.getitemlist()需要很长时间。无论在哪里,我都在寻找正确的方法来添加多对多条目,这说明有必要这样做。有人能帮忙吗?
编辑:一个小上下文:我用标签组织我的iten,所以一个项目可以有多个标签,一个标签可以有多个iten,时间过去了,现在我有很多iten(>5.000)的标签,现在当我用这些标签中的一个保存一个新项目时,需要很长时间,我已经调试了我的代码,发现大部分延迟都在cat.getitenslist()行中,with是有意义的,因为它有大量的iten列表。我已经搜索了很多关于如何做到这一点的方法,每个人都说在多对多的情况下保存条目的正确方法是在关系的两边添加到列表中,但是如果其中一方很大,那么调用getitenslist()会在上下文中加载它们,这将花费很多时间。我正在寻找一种方法来保存我的项目参考标签没有加载该标签的所有iten。
编辑2:我的类:项:
@Entity
@Table(name = "transacao")
@XmlRootElement
public class Transacao implements Serializable {
@ManyToMany(mappedBy = "transacaoList")
private List<Tagtransacao> tagtransacaoList;
...(other stuff)
}
标签:
@Entity
@Table(name = "tagtransacao")
@XmlRootElement
public class Tagtransacao implements Serializable {
@JoinTable(name = "transacao_has_tagtransacao", joinColumns = {
@JoinColumn(name = "tagtransacao_idTagTransacao", referencedColumnName = "idTagTransacao")}, inverseJoinColumns = {
@JoinColumn(name = "transacao_idTransacao", referencedColumnName = "idTransacao")})
@ManyToMany
private List<Transacao> transacaoList;
...(other stuff)
}
编辑3:我做了什么来解决:正如ariel kohan所回答的,我试图做一个nativequery来插入关系:
Query query = queryDAO.criarNativeQuery("INSERT INTO " + config.getNomeBanco() + ".`transacao_has_tagtransacao` "
+ "(`transacao_idTransacao`, `tagtransacao_idTagTransacao`) VALUES (:idTransacao, :idTag);");
query.setParameter("idTransacao", transacao.getIdTransacao());
query.setParameter("idTag", tag.getIdTagTransacao());
我能够将查询时间从10秒减少到300英里,这是令人印象深刻的。最后,对于我的项目来说,最好是它已经开始运行了,而不是创建一个表示多对多关系的新类。感谢所有试图帮助的人\o/
2条答案
按热度按时间kr98yfug1#
这基本上是从一个类似的答案,我之前给出了,但类似的问题,以及复制。下面的代码在我第一次写的时候运行,但是我修改了名字来匹配这个问题,所以可能会有一些拼写错误。spring数据jpa是jpa之上的一层。每个实体都有自己的存储库,您必须处理它。为了处理springdatajpa中的多对多关系,如果您认为这是个好主意,可以为link表创建一个单独的存储库。
并使用它。步骤3显示了您当前的执行方式,并在执行更新之前创建对现有联接的读取。步骤4只是直接在联接表中插入一个关系,不会导致对现有联接的预读取。
我没有明确设置
ItemCategoryId
身份证。这些由持久层(在本例中为hibernate)处理。另外请注意,您可以更新
ItemCategory
条目要么用自己的回购协议明确说明,要么从列表中添加和删除它们CascadeType.ALL
已设置,如图所示。使用CascadeType.ALL
对于spring数据jpa来说,即使您预取了连接表实体,spring数据jpa仍然会再次执行。试图通过CascadeType.ALL
对于新实体来说是有问题的。没有
CascadeType
也不是items
或者categories
列表(应该是集合)是关系的所有者,因此添加到列表中并不能实现持久性,只能用于查询结果。在阅读
ItemCategory
因为你没有关系,所以你需要特别的联系他们FetchType.EAGER
. 问题在于FetchType.EAGER
如果你不想要连接,并且你把它放在两个上面,那么开销是多少Category
以及Item
然后您将创建一个递归的获取categories
以及items
任何查询。js5cn81o2#
在这种情况下,我将阻止您的代码在内存中加载项列表。
为此,我可以考虑两种选择:
使用@modyfing查询直接在数据库中插入项。
[建议用于希望避免更改模型的情况]
您可以尝试使用普通jpql创建查询,但是根据您的模型,您可能需要使用本机查询。使用本机查询类似于:
创建此查询后,需要更新代码,删除内存中加载对象的部分,并添加调用insert语句的部分。
[更新]正如您在评论中提到的,这样做可以将性能从10英里提高到300英里。
修改您的实体,以便将@manytomany替换为@onetomanys关系
该解决方案的思想是替换实体之间的多个关系
A
以及B
中间实体RelationAB
. 我认为你可以通过两种方式来做到这一点:仅将relationab中a和b的id保存为复合键(当然,您可以添加其他字段,如日期或任何您想要的内容)。
向relationab添加自动生成的id,并将a和b作为relationab实体中的其他字段添加。
我使用第一个选项做了一个示例(您将看到类不是公共的,这只是因为为了简单起见,我决定在单个文件中执行它。当然,如果需要,可以在多个文件和公共类中执行此操作:
Entities A and B
:@Embeddable
class RelationABId implements Serializable {
private Long entityAId;
private Long entityBId;
}
@Entity
class RelationABEntity {
}
@Repository
interface RelationABEntityRepository extends JpaRepository<RelationABEntity, RelationABId> {
}
@Repository
interface ARepository extends JpaRepository<EntityA, Long> {
}
@Repository
interface BRepository extends JpaRepository<EntityB, Long> {
}
@RunWith(SpringRunner.class)
@DataJpaTest
public class DemoApplicationTest {
}