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

Tabela de Ativos - Saldo atual

estou desenvolvendo uma tela de movimentacao financeira, onde sera inserido no banco um registro a cada transação, informando o nome, data tipo de transação(se e entrada ou saida) e o valor da transação. Eu quero saber em tempo real os ativos da empresa, que seria o saldo atual, e não quero ter que fazer um loop para calcular em todos os registros, então minha duvida é, o que seria melhor, criar um campo de saldo atual, e pegar sempre o ultimo valor do banco como saldo atual, ou criar uma tabela com nome de ativos, onde seria inserido apenas 1 registro, e atualizado (update) esse saldo atual a cada transação?

8 respostas

Douglas, bom dia.

Eu, particularmente criaria uma tabela

Oi Douglas! Excelente pergunta!

Pode parecer estranho o que vou te explicar. Não é tão simples decidir que caminho seguir sem ter visão de alguns demônios chamados requisitos não funcionais. Eles interferirão no desenho de sua solução.

Eu utilizo 4 informações para desenhar uma solução dessas, podendo desde a mais simples até a mais complexa. Assim, basicamente eu faço perguntas:

1) Quantos movimentos são esperados? Isso pode crescer? Existe um limite?

2) Com qual frequência esses movimentos são atualizados?

3) Quantas pessoas precisam consultar o saldo atual ao mesmo tempo?

4) Com que frequência as pessoas precisam do saldo.

5) Qual é o impacto do saldo estar desatualizado, por exemplo alguns segundos, minutos, horas e dias?

Agora trabalhando essas informações:

SOLUÇÃO 1: Em se tratar de poucas pessoas, chamando poucas vezes e precisam sempre da informação mais atual, sugiro ir ao mais simples, que é fazer uma JPQL com SUM no banco de dados.

SOLUÇÃO 2: cenários onde muita informação precisa ser carregada, muitas vezes, para muitas pessoas ao mesmo tempo, eu sugiro que implemente soluções de cache por conta, invalidado a cada evento de inserir ou remover registros.

SOLUÇÃO 3: Caso seu sistema seja de missão crítica, tipo um banco, trader ou coisa similar, eu proporia uma solução mista. Todo dia um job calcula o saldo de todas as contas com as movimentações até ontem. Ao final basta somar esse valor ao JPQL com SUM(VALOR) apenas das movimentações apenas do dia de hoje.

De qualquer forma, se você não tem clara as respostas para as perguntas acima neste momento, sugiro seguir a solução 1.

Bom, espero ter ajudado,

Abraço e sucesso,

Rodrigo

Guilherme, porque vc criaria uma tabela? quais pontos vc destaca que te levou a tomar essa decisão?

Rodrigo, interessante a questão do SUM, o projeto a principio e pequeno com poucas pessoas, mais a questão do SUM, executaria uma consulta a cada carregamento da pagina? poderia me dar um link de consulta, ou exemplo da opção 2?

e vi que você não considerou nem a criação da nova tabela nem a criação de um campo na própria tabela movimento pegando sempre o saldo atual do ultimo registro inserido, no seu ponto de vista essas opções não são viáveis?,

Douglas,

1) O SUM é uma boa solução quando em geral não estamos otimizando um problema de performance existente. Lembre-se de criar indice na tabela de movimentos, de forma a não ter problemas de performance.

2) Essa idéia de colocar um campo com o saldo no último registro pode ser uma boa estratégia, desde que:

Não se permitirá que sejam removidos movimentos ou isso quebraria o seu saldo.

Deveria se garantir que não haverão duas pessoas inserindo movimentos ao mesmo tempo.

3) Vou compartilhar 2 cursos que falam de cache. Um de JPA e outro usando Spring:

https://cursos.alura.com.br/course/springmvc-2-integracao-cache-seguranca-e-templates/task/40393

https://cursos.alura.com.br/course/jpa-avancado/task/48647

Espero ter ajudado,

Abraço,

Rodrigo

blz Guilherme, se nao for abusar da boa vontade, pode me indicar um caminho tambem, ou como eu criaria esse índice na tabela para utilizar o SUM? e também como eu consigo garantir que nao existam duas pessoas inserindo registro ao mesmo tempo?

solução!

Olá Douglas,

Eu não sou o Guilherme mas se você e ele não se importarem, eu vou responder.

Se seus registros são tipados: entrada e saída (colunas diferentes) então você deve.

Somar todas as entradas e subtrair as saídas na mesma query

select sum(m.entrada) - sum(m.saidas) from Movimento m where m.conta = :conta

Se seus registros são sem tipo: Entrada e saída é uma mera variação de sinal presente no valor (positivo ou negativo em uma coluna apenas)

Somar todos os registros na mesma query e o resultado esta pronto.

select sum(m.valor) from Movimento m where m.conta = :conta

E os índices?

Imagine que vc tem uma tabela única de movimentos, ok?

Quando o usuário X entrar, ele vai ver movimentações sobre alguns filtros, como no exemplo:

1) Empresa

2) Setor ou departamento

3) Por estado do movimento

4) Por tipo ou status de movimento ...

Se esses são exemplos de pesquisas que podem ser feitas, é fundamental criar um índice com os campos em que lhe fizerem sentido.

Não precisa ser indice individual, os bancos de dados relacionais já são espertos o suficiente para aproveitar o índice por todas as colunas, no caso de não haver um índice específico para sua query.

Recomendo não se preocupar com pessoas inserindo registros ao mesmo tempo. Se sua solução utilizar o SUM, isso não seria um problema.

Caso queira saber mais sobre controle de concorrência, estude estratégias de lock. Elas existem no JPA/Hibernate (Lock Otimista e Pessimista) e no Banco de Dados (Locks de Tabela, Página, Bloco e Registro).

@Entity
@Indices({
   @Index(members={"idMovimento"}, unique = true),
    @Index(members={"idConta"}),
    @Index(members={"idConta", "tipoMovimento"}
}
public class Movimento {
    String idMovimento;
    String idConta;
    String tipoMovimento;
}

Espero ter ajudado,

Abraço,

Rodrigo

Ola Rodrigo, clareou bem aqui, muito obrigado pela ajuda amigo.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software