异步保存和更新

时间:2020-11-08 11:43:46

标签: java spring multithreading hibernate jpa

描述

我正在Java游戏服务器上工作,我已经集成了休眠功能,可以保存,更新和加载我的实体。

我遇到了一个主要问题,即jpa / hibernate块是不完整的,因为这意味着滞后。在保存,更新或加载操作期间,玩家无法与游戏互动几秒钟。

我试图将这些操作简单地包装在额外的线程中,效果不佳...

我当前的数据库流如下...

  • 标记要更新的游戏实体
  • 将其传递给更新线程
  • 克隆标记的实体
  • 公开会议和交易
  • session.update
  • 提交并关闭会话

代码


// Clone entities, chunk ( see below )

// Run the database operation for updating the entities async in a new thread, return updated entities once done
        return CompletableFuture.runAsync(() -> {

            var session = database.openSession();
            session.beginTransaction();

            try {

                // Save identities first
                for (var identity : identities)
                    session.update(identity);

                // Update components, each component-type
                for(var insertedClass : insertationOrder)
                    for (var hbc : componentsPerType.get(insertedClass))
                        session.update(hbc);

                session.flush();
                session.clear();

                session.getTransaction().commit();
            } catch (Exception e){

                var messageComposer = new ExceptionMessageComposer(e);
                GameExtension.getInstance().trace("Update : "+messageComposer.toString());
                session.getTransaction().rollback();
            }

            session.close();
        }).thenApply(v -> entities);

/**
 * A component which marks a {@link com.artemis.Entity} as a chunk and stores its most valuable informations.
 */
@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)
    @JoinTable(name = "chunk_identity", joinColumns = @JoinColumn(name = "identity_id"), inverseJoinColumns = @JoinColumn(name = "id"), inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set<Identity> inChunk = new LinkedHashSet<>();

    @Transient
    public Set<ChunkLoader> loadedBy = new LinkedHashSet<>();

    public Chunk() {}
    public Chunk(int x, int y, Date createdOn) {
        this.x = x;
        this.y = y;
        this.createdOn = createdOn;
    }
}

/**
 * Represents a ID of a {@link com.artemis.Entity} which is unique for each entity and mostly the database id
 */
@Entity
@Table(name = "identity")
@Access(AccessType.FIELD)
@SQLInsert(sql = "insert into identity(tag, typeID, id) values(?,?,?) ON DUPLICATE KEY UPDATE id = VALUES(id), tag = values(tag), typeID = values(typeID)")
@SelectBeforeUpdate(value = false)
public class Identity extends Component {

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

    public Identity() {}
    public Identity(long id, String tag, String typeID) {
        this.id = id;
        this.tag = tag;
        this.typeID = typeID;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        var identity = (Identity) o;
        return id == identity.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, tag, typeID);
    }
}

以前的问题

当我不克隆实体时,休眠会抛出“ ConcurrentModificationException”:https://stackoverflow.com/questions/64719951/concurrentmodificationexception-when-updating-my-entities

当我深克隆它们时,集合永远不会更新,只会插入其子项,从而每次都导致重复的条目:https://stackoverflow.com/questions/64731215/copied-parent-inserts-childs-instead-of-updating-them

我看到很多其他的帖子都在问类似的问题,但是没有一个是一个真实而良好的例子,尤其是在保存和更新方面。

问题

那么,我们如何在一个额外的线程中运行保存和更新操作,而又不丢失集合跟踪并运行到“ ConcurrentModificationException”的容器中?

任何代码示例吗?

0 个答案:

没有答案