当前位置: 首页 > 知识库问答 >
问题:

处理BLOB字段时如何提高Eclipse Link的性能?

田化
2023-03-14

由于每个实体都有BLOB字段,我的Java应用程序变得非常慢。该字段通常用于存储PDF文件,每当我必须列出所有对象时,都需要相当长的时间,直到持久性提供程序可以完成其工作。我寻找有关如何处理此类数据的答案,但其中一些人谈到将BLOB存储在单独的表中,然后使用FetchType.LAZY.是否有任何方法仅在需要时获取此字段而无需创建另一个表?如果没有,创建另一个表是最合适的解决方案吗?

实体代码

@Cache(alwaysRefresh = true)
public class ScdDocumento implements Serializable, MultipleSelector {
    @Transient
    public static final String QUERY_RELATORIO_DOC_LOC = "consultas/ctrl_docs/consulta_relatorio_doc_local.txt";

    @Transient
    public static final String QUERY_RELATORIO_DOC_GRUPO = "consultas/ctrl_docs/consulta_relatorio_doc_grupo.txt";

    @Id
    @Column(name = "nome", length = 50)
    private String nome;

    @Column(name = "revisao")
    private int revisao;

    @Column(name = "id_tipo")
    private int id_tipo;

    @Column(name = "situacao", length = 1)
    private String situacao;

    @Column(name = "doc_blob_nome", length = 50)
    private String doc_blob_nome;

    @Lob 
    @Basic(fetch = FetchType.LAZY)
    @Column(name = "documento_blob", nullable = false)
    private byte[] documento_blob; //The field that impacts the application perfomance

    @Column(name = "abrangencia_geral")
    private int abrangencia_geral;

    @ManyToMany
    @JoinTable(name = "SCD_DOC_GRUPO", joinColumns = {@JoinColumn(name = "id_doc")},
        inverseJoinColumns = {@JoinColumn(name = "id_grupo")})
    private Set<SosGrupo> grupos;

    @ManyToOne
    @JoinColumn(name = "id_tipo", insertable = false, updatable = false)
    private ScdTipo tipo;

    @ManyToMany
    @JoinTable(name = "SCD_REFERENCIA", joinColumns = {@JoinColumn(name = "doc_pai")},
        inverseJoinColumns = {@JoinColumn(name = "doc_filho")})
    private Set<ScdDocumento> referencias;

    @ManyToMany
    @JoinTable(name = "SCD_REFERENCIA", joinColumns = {@JoinColumn(name = "doc_filho")},
        inverseJoinColumns = {@JoinColumn(name = "doc_pai")})
    private Set<ScdDocumento> referenciadoPor;

    @ManyToMany
    @JoinTable(name = "SCD_PALAVRA_REFERENCIA", joinColumns = {@JoinColumn(name = "documento")},
        inverseJoinColumns = {@JoinColumn(name = "palavra")})
    private Set<ScdPalavraChave> palavrasChaves;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "documento")
    private Set<ScdOrdem> ordens;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "documento")
    private Set<ScdArquivoOs> arquivosOs;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "documento")
    private Set<ScdArquivoHistorico> arquivosHistorico;

    @ManyToMany(cascade = {CascadeType.REFRESH, CascadeType.MERGE})
    @JoinTable(name = "SCD_LOCAL_DOC", joinColumns = {@JoinColumn(name = "id_doc")},
        inverseJoinColumns = {@JoinColumn(name = "id_local")})
    private Set<ScdLocal> locais;

    @Override
    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getRevisao() {
        return revisao;
    }

    public void setRevisao(int revisao) {
        this.revisao = revisao;
    }

    public int getIdTipo() {
        return id_tipo;
    }

    public void setIdTipo(int id_tipo) {
        this.id_tipo = id_tipo;
    }

    public String getSituacao() {
        return situacao;
    }

    public void setSituacao(String situacao) {
        this.situacao = situacao;
    }

    public String getDocBlobNome() {
        return doc_blob_nome;
    }

    public void setDocBlobNome(String doc_blob_nome) {
        this.doc_blob_nome = doc_blob_nome;
    }

    public byte[] getDocumentoBlob() {
        return documento_blob;
    }

    public void setDocumentoBlob(byte[] documento_blob) {
        this.documento_blob = documento_blob;
    }

    public int getAbrangenciaGeral() {
        return abrangencia_geral;
    }

    public void setAbrangenciaGeral(int abrangencia_geral) {
        this.abrangencia_geral = abrangencia_geral;
    }

    public Set<SosGrupo> getGrupos() {
        return grupos;
    }

    public void setGrupos(Set<SosGrupo> grupo) {
        this.grupos = grupo;
    }

    public ScdTipo getTipo() {
        return tipo;
    }

    public void setTipo(ScdTipo tipo) {
        this.tipo = tipo;
    }

    public Set<ScdDocumento> getReferencias() {
        return referencias;
    }

    public void setReferencias(Set<ScdDocumento> referencias) {
        this.referencias = referencias;
    }

    public Set<ScdDocumento> getReferenciadoPor() {
        return referenciadoPor;
    }

    public void setReferenciadoPor(Set<ScdDocumento> referenciadoPor) {
        this.referenciadoPor = referenciadoPor;
    }

    public Set<ScdPalavraChave> getPalavrasChaves() {
        return palavrasChaves;
    }

    public void setPalavrasChaves(Set<ScdPalavraChave> palavrasChaves) {
        this.palavrasChaves = palavrasChaves;
    }

    public Set<ScdOrdem> getOrdens() {
        return ordens;
    }

    public void setOrdens(Set<ScdOrdem> ordens) {
        this.ordens = ordens;
    }

    public Set<ScdArquivoOs> getArquivosOs() {
        return arquivosOs;
    }

    public void setArquivosOs(Set<ScdArquivoOs> arquivosOs) {
        this.arquivosOs = arquivosOs;
    }

    public Set<ScdArquivoHistorico> getArquivosHistorico() {
        return arquivosHistorico;
    }

    public void setArquivosHistorico(Set<ScdArquivoHistorico> arquivosHistorico) {
        this.arquivosHistorico = arquivosHistorico;
    }

    public Set<ScdLocal> getLocais() {
        return locais;
    }

    public void setLocais(Set<ScdLocal> locais) {
        this.locais = locais;
    }    

    @Override
    public String getIdRef() {
        return nome;
    }

    @Override
    public String getDesc() {
        return tipo.getNome();
    }
}

导致问题的方法

图像使用者界面

private void loadDocumentTable(String situacao) {
    mapaDocumentos = new TreeMap<>();
    modelDocumentos.setRowCount(0);

    docdao.getCriteria("situacao", situacao).forEach((e) -> {
        mapaDocumentos.put(e.getNome(), e);
    });

    mapaDocumentos.entrySet().forEach((e) -> {
        String desc = e.getValue().getDocBlobNome();
        modelDocumentos.addRow(new Object[]{e.getKey(), desc.substring(0, desc.length() - 3), e.getValue().getRevisao()});
    });
}

通用刀

@Override
public List<T> getCriteria(String column, Object value){
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<T> cq = cb.createQuery(clazz);
    Root<T> root = cq.from(clazz);
    EntityType<T> ent = root.getModel();
    cq.where(cb.equal(root.get(ent.getSingularAttribute(column)), value.toString()));

    return em.createQuery(cq).getResultList();
}

表模型

坚持

将此添加到我的持久性.xml,但 eclipselink 仍然急切地获取 byte[] 字段。

Maven插件

         <plugin>
            <groupId>de.empulse.eclipselink</groupId>
            <artifactId>staticweave-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>weave</goal>
                    </goals>
                    <configuration>
                        <persistenceXMLLocation>META-INF/persistence.xml</persistenceXMLLocation>
                        <logLevel>FINE</logLevel>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
               <dependency>
                   <groupId>org.eclipse.persistence</groupId>
                   <artifactId>org.eclipse.persistence.jpa</artifactId>
                   <version>2.5.2</version>
               </dependency>
            </dependencies>
        </plugin>

最终编辑

staticweave-maven-plugin实际上是有效的,但每次我更改某些内容时都需要构建项目以提高性能。发生这种情况是因为编织是静态的,所以它是在构建时应用的,而不是在使用IDE运行项目时应用的。

共有1个答案

干宏邈
2023-03-14

JPA基础还允许指定LAZY的提取类型,这将阻止加载BLOB,直到您在实体中访问它。OneToOne、ManyToOne和basic映射需要对您的实体进行字节码增强,以便EclipseLink在您访问一个惰性属性并加载它时获得通知,这在这里被描述为编织。这将确保它在默认情况下不会被加载。

通过使用编织,您还可以使用实体图来指定加载什么以及何时加载。这可以允许在使用blob时将blob与实体的其余部分一起加载到单个查询中,并在默认情况下将其排除在其他地方。看看JPA实体图的获取和加载有什么区别?有关加载和获取图形的信息。

 类似资料:
  • 我从http://docs.oracle.com/javaee/7/tutorial/doc/servlets012.htm Java EE为servlet和过滤器提供异步处理支持。如果servlet或过滤器在处理请求时达到潜在的阻塞操作,它可以将该操作分配给异步执行上下文,并将与请求相关联的线程立即返回到容器,而不生成响应。阻塞操作在不同线程的异步执行上下文中完成,该线程可以生成响应或将请求分派

  • 问题内容: 在代码底部运行的示例需要很长时间才能在我的机器上解决: 这是代码: 每只只供三只骆驼。我想至少这样做4次。该测试用例仍在运行(现在:()已经大约5分钟了。如果完成,我将对其进行更新。 我应该怎么做才能改善这段代码?(通常以性能为依据,但也欢迎其他建议)。 问题答案: 我以前也被这个绊倒了。这里的瓶颈实际上是。 该in语句是如此易于使用,你忘记了它是线性搜索,而当你在列表上进行线性搜索时

  • 问题内容: 我有一个数据模型,该数据模型在一个实体和其他11个实体之间具有一对多关系。这12个实体一起代表一个数据包。我遇到的问题是与这些关系的“许多”方面发生的插入次数有关。其中一些可以具有多达100个单独的值,因此要将一个完整的数据包保存在数据库中,最多需要500次插入。 我正在将MySQL 5.5与InnoDB表一起使用。现在,通过测试数据库,我发现在处理批量插入时,它每秒可以轻松地每秒进行

  • 我第一次使用spring batch应用程序,由于框架太灵活了,我有几个关于性能和实现作业的最佳实践的问题,在spring文档中找不到明确的答案。 > 读取由第三方以先前指定的布局发送的具有固定列长值的ASCII文件(第1步读取器) 在oracle数据库上写入有效行(第1步写入器) 执行前一步后,使用第1步的finish时间戳更新数据库中的表(第2步tasklet) 当作业停止时,发送一封电子邮件

  • 我有一个名为Emails的列族,我正在将邮件保存到这个CF中,编写5000封邮件需要100秒。 我使用的是i3处理器,8gb内存。我的数据中心有6个节点,复制因子=2。 我们存储在卡桑德拉中的数据大小会影响性能吗?影响写入性能的所有因素是什么,如何提高性能? 预先感谢..

  • 我们正在快速开发一个应用程序,其中我们需要一次获取超过50K行(在应用程序加载时执行),然后数据将用于应用程序的其他部分进行进一步计算。我们正在使用Firebase实时数据库,我们面临一些严重的性能问题。 它目前需要大约40秒才能加载50K行(目前使用的是免费数据库版本,不确定这是否是原因),但我们也观察到,当多个用户使用该应用程序时,加载50K行开始需要大约1分20秒,Peak达到100%。 您