Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Estratégia para Trabalhar com arquivos de texto grandes

Olá, Tenho uma aplicação que consiste de colar um arquivo (.doc | .docx | .odt) em um editor Fckeditor ou fazer upload de um arquivo de texo das extensões supracitadas, aplicar uma conversão para html (docx4j) e jogar no editor e mandar salvar no banco de dados, na verdade deveria funcionar parecido com um google docs. Acontece que esporadicamente temos algumas publicações grandes(um arquivo .docx de 200KB após convertido para html ficou com 3MB) e o mysql chiou. Então estou procurando alternativas para trabalhar com estes textos grandes para melhorar o consumo de memória e também a performance do banco de dados. No momento de carregar o texto existe a possibilidade de carregamento sob demanda? No momento de salvar eu vou lendo o texto e a cada 10000 linhas eu dou um update, essa estratégia é bacana? alguma dica?

código no managed bean

    public String salvar() {


        try {
            Path path = FileSystems.getDefault().getPath(System.getenv("HOME"),"temp");
            String filePath = path.toAbsolutePath().toString() + FileSystems.getDefault().getSeparator() + UUID.randomUUID()+".txt";
            FileOutputStream fos =  new FileOutputStream(filePath);
            fos.write(materia.getTexto().getBytes());
            fos.close();
            Scanner sc = new Scanner(new File(filePath));
            int numeroLinhas = 0;
            StringBuffer sb = new StringBuffer();
            while(sc.hasNextLine()) {
                String linha = sc.nextLine();
                sb.append(linha);
                if(numeroLinhas == 10000) {
                    String conteudo = StringEscapeUtils.unescapeHtml4(sb.toString());
                    materiaService.updateIncremental(materia.getMateriaId(), conteudo);
                    sb =  new StringBuffer();
                    numeroLinhas = 0;
                }
                numeroLinhas++;
            }
            if(!sc.hasNextLine()) {
                String conteudo = StringEscapeUtils.unescapeHtml4(sb.toString());
                materiaService.updateIncremental(materia.getMateriaId(), conteudo);
            }
            sc.close();    
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "ListaDiarios";
    }

implementação no repository



    public void alterarMateriaIncremental(Integer materiaId,String texto) {

        Query updateQuery =  manager.createNativeQuery("UPDATE materia SET texto = CONCAT(texto,:texto) WHERE materia_id =:id ");
        updateQuery.setParameter("texto", texto);
        updateQuery.setParameter("id",materiaId);
        updateQuery.executeUpdate();

    }
2 respostas
solução!

Eu salvaria o arquivo no disco e guardaria só o caminho no banco. Geralmente tenho feito nos projetos que participo... Penso que qualquer solução que você tente fazer para otimizar a leitura e gravação vai adicionar uma complexidade que talvez não valha a pena. Já pensou em guardar eles num S3 da vida?

Normalmente faço isso, mas acredito que cometi erro de dimensionamento mesmo, pois já tenho esse mesmo sistema para um outro cliente mas as publicações eram pequenas, para esse cliente a maioria das matérias são pequenas também mas as vezes eles divulgam resultados de seletivos de concursos, geralmente os problemas só ocorrem com este tipo de publicação e como já tenho bastante coisa já em banco acredito que seja um pouco complicado mudar tudo nesta versão. Mas é isso ai, vivendo e aprendendo.

Agora mais uma dúvida, caso eu mude para salvar o arquivo em um Amazon S3 , Ftp ou mesmo em uma pasta do servidor, os dados da matéria ainda serão persistidos no banco, existe alguma forma de garantir a atomicidade desta operação? só salvar no banco se conseguir gravar o arquivo ou só gravar o arquivo se a matéria for modificada no banco?

public Materia salvar(){

gravarArquivoNoservidor(materia.getCaminhoArquivo,materia.getTexto());
materiaService.alterar(materia);
}