阻止在更新父项时使 Hibernate 选择其子项。

huangapple go评论78阅读模式
英文:

Prevent hibernate from selecting children when updating its parent?

问题

问题

当我更新父类时,Hibernate 在触发更新之前会选择所有子类。只有当我们添加尚未在数据库中持久的新子项时,才会出现这种情况。Hibernate 逐个选择这些子项,非常... 非常慢。

已经启用并且在正常插入、更新和删除操作中有效的批处理。我为子类提供了一个版本,但是 Hibernate 无法解释它。

select * from identity...
select * from identity...
select * from identity...
select * from identity...
insert .... into identity...
update chunk set ....

问题

是否有办法让 Hibernate 批处理这些查询,或者实现其他机制,使 Hibernate 在首先从数据库中选择新添加的子项之前,仅仅检查它们是否是新的?

基本上,我想摆脱这些“逐个”查询。对于任何可以提供的帮助,我都会感激不尽。

我的类

当我更新包含多个尚未在数据库中的标识(inChunk)的块时... 它尝试确定它们是否在数据库中,从而为每个子项生成一个查询,以过滤需要插入的那些子项... 我如何防止这些多余的查询?我仍然希望保留级联行为。

@Entity
@Access(AccessType.FIELD)
@SQLInsert(sql = "insert into identity(tag, typeID, id, version) values(?,?,?,?) ON DUPLICATE KEY UPDATE id = VALUES(id), tag = values(tag), typeID = values(typeID), version = values(version)")
@SelectBeforeUpdate(value = false)
public class Identity extends Component {

    @Id public long id;
    public String tag;
    public String typeID;

    @Version public long version;
}

@Entity
@Table(name = "chunk", uniqueConstraints = {@UniqueConstraint(columnNames={"x", "y"})}, indexes = {@Index(columnList = "x,y")})
@Access(value = AccessType.FIELD)
@SelectBeforeUpdate(false)
public class Chunk extends HibernateComponent {

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set<Identity> inChunk = new LinkedHashSet<>();
}
英文:

The Problem

When I update my parent class, hibernate selects all its child before triggering the update.
This only happens when we added new children that are not persistent in the database yet.
Hibernate selects those children one by one, which is very... very slow.

Batching is already enabled and working for normal inserts, updates and removals.
I gave the child a version, which hibernates ignores somehow.

select * from identity...
select * from identity...
select * from identity...
select * from identity...
insert .... into identity...
update chunk set ....

Question

Is there a way to either make hibernate batch those selects or to implement some other mechanic in which hibernate simply checks the added child if its new without selecting it from the database first?

I basically want to get rid of those "one by one" selects. Would be glad for any help I can get.

My Classes

When I update chunk which contains multiple identities that are not yet in the database ( inChunk )... it tries to determine if they are in the database which results in one select for each child to filter those children that are need to get inserted... how do I prevent those many selects? I still want to keep the cascading.

@Entity
@Access(AccessType.FIELD)
@SQLInsert(sql = &quot;insert into identity(tag, typeID, id, version) values(?,?,?,?) ON DUPLICATE KEY UPDATE id = VALUES(id), tag = values(tag), typeID = values(typeID), version = values(version)&quot;)
@SelectBeforeUpdate(value = false)
public class Identity extends Component {

    @Id public long id;
    public String tag;
    public String typeID;

    @Version public long version;
}

@Entity
@Table(name = &quot;chunk&quot;, uniqueConstraints = {@UniqueConstraint(columnNames={&quot;x&quot;, &quot;y&quot;})}, indexes = {@Index(columnList = &quot;x,y&quot;)})
@Access(value = AccessType.FIELD)
@SelectBeforeUpdate(false)
public class Chunk extends HibernateComponent {

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set&lt;Identity&gt; inChunk = new LinkedHashSet&lt;&gt;();
}

答案1

得分: 1

单向一对多关联 - 不是一个好的实践。我建议在Identity类中定义多对一关联,然后在inChunk字段的@OneToMany注解上添加mappedBy属性,然后在添加新子项之前获取Chunk.inChunk关联。

@Entity
@Access(AccessType.FIELD)
@SQLInsert(sql = "insert into identity(tag, typeID, id, version) values(?,?,?,?) ON DUPLICATE KEY UPDATE id = VALUES(id), tag = values(tag), typeID = values(typeID), version = values(version)")
@SelectBeforeUpdate(value = false)
public class Identity extends Component {

    @Id public long id;
    public String tag;
    public String typeID;

    @Version public long version;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "chunk_id") // 我假设Chunk实体有id字段
    public Chunk chunk;
}

@Entity
@Table(name = "chunk", uniqueConstraints = {@UniqueConstraint(columnNames={"x", "y"})}, indexes = {@Index(columnList = "x,y")})
@Access(value = AccessType.FIELD)
@SelectBeforeUpdate(false)
public class Chunk extends HibernateComponent {

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "chunk")
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set<Identity> inChunk = new LinkedHashSet<>();
}
英文:

Unidirectional one-to-many association - is not good practice. I would recommend to define the many-to-one association in the Identity class, then add the mappedBy attribute to the @OneToMany annotation on the inChunk field, and then fetch Chunk.inChunk association before add new children.

@Entity
@Access(AccessType.FIELD)
@SQLInsert(sql = &quot;insert into identity(tag, typeID, id, version) values(?,?,?,?) ON DUPLICATE KEY UPDATE id = VALUES(id), tag = values(tag), typeID = values(typeID), version = values(version)&quot;)
@SelectBeforeUpdate(value = false)
public class Identity extends Component {

    @Id public long id;
    public String tag;
    public String typeID;

    @Version public long version;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = &quot;chunk_id&quot;) // I suppose the Chunk entity has id
    public Chunk chunk;
}

@Entity
@Table(name = &quot;chunk&quot;, uniqueConstraints = {@UniqueConstraint(columnNames={&quot;x&quot;, &quot;y&quot;})}, indexes = {@Index(columnList = &quot;x,y&quot;)})
@Access(value = AccessType.FIELD)
@SelectBeforeUpdate(false)
public class Chunk extends HibernateComponent {

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = &quot;chunk&quot;)
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set&lt;Identity&gt; inChunk = new LinkedHashSet&lt;&gt;();
}

huangapple
  • 本文由 发表于 2020年10月6日 23:40:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/64229222.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定