Salvar objeto pai e filho usando a mesma transação

17 respostas
mateusviccari

Bom dia, vamos supor que tivesse uma tabela venda e outra itens de venda, nessa tabela de itens teria o codigo da venda pra guardar a referencia. Pra cada uma das tabelas eu tenho um bean la no java, e crio uma instancia de Venda com código 10 e varios itens que seriam os itens dessa venda.
Um problema que enfrento no banco firebird é que ao tentar gravar os 2 na mesma transação, mesmo fazendo o insert da venda antes dos itens, na hora de inserir os itens vai me dar “constraint violation exception” visto que na verdade a venda de código 10 ainda não existe fisicamente no banco.

Tem como contornar esse problema no java? ou vou ter que gravar fisicamente a venda usando o commit e depois gravar os itens?

17 Respostas

igor_ks

ta usando hibernate ou jdbc puro?

e pq nao persiste tudo ao mesmo tempo?

drsmachado

Isso não é um problema do java, é do banco de dados.
As constraints violations dizem respeito à regras que estão sendo quebradas.
No caso, sim, será preciso confirmar (commit) a transação.
Se estiver usando JDBC, será preciso obter a PK da venda e, então, inserir junto a cada elemento item de venda.

mateusviccari

É porque na verdade o caso não e simples assim como venda e itens, é um sistema de geração de conhecimentos de frete a partir de notas fiscais eletronicas, e é um processo que as vezes pode demorar pois pede varias coisas pro usuario, e por isso o usuario deve ter uma opção de cancelar todo o processo, entao seria so dar um rollback na transação e estaria feito o negocio, ja depois de ter dado o commit em um objeto so posso remover com novas transações…

rmendes08

drsmachado:
Isso não é um problema do java, é do banco de dados.
As constraints violations dizem respeito à regras que estão sendo quebradas.
No caso, sim, será preciso confirmar (commit) a transação.
Se estiver usando JDBC, será preciso obter a PK da venda e, então, inserir junto a cada elemento item de venda.

Não necessariamente. O problema é a demarcação de transação mesmo, se as operações de inserção na tabela pai são feitas na mesma transação que a inserção nas tabelas filhas, então o banco deveria “enxergar” o insert mesmo sem o commit. O problema pode ser que a sua regra de negócio esteja sendo executada dentro de mais de uma transação. Isso pode ser tanto erro de lógica, quanto erro de configuração no JDBC ou ainda pode ser falta de suporte do banco de dados mesmo.

mateusviccari

é… acredito que o problema é no firebird mesmo pois eu uso apenas uma transação pra inserir pai e filho

rmendes08

tem certeza ? como você acessa o banco ? JDBC puro ou usa algum framework ?

mateusviccari

Nesse caso estou usando hibernate…
O algoritmo funciona assim, usando a session do hibernate

Session session=criarSession();
session.getTransaction().begin();
/**
*
*Fazer todo o processo
*
*/
session.getTransaction().commit();
rmendes08

mateusviccari:
Nesse caso estou usando hibernate…
O algoritmo funciona assim, usando a session do hibernate

Session session=criarSession();
session.getTransaction().begin();
/**
*
*Fazer todo o processo
*
*/
session.getTransaction().commit();

Cara, nesse caso, eu acho que deve ser algum erro no mapeamento, ou então, o Id da entidade pai não está sendo setado nas entidades filhas … só olhando o caso mais de perto mesmo.

rimolive

rmendes08:
drsmachado:
Isso não é um problema do java, é do banco de dados.
As constraints violations dizem respeito à regras que estão sendo quebradas.
No caso, sim, será preciso confirmar (commit) a transação.
Se estiver usando JDBC, será preciso obter a PK da venda e, então, inserir junto a cada elemento item de venda.

Não necessariamente. O problema é a demarcação de transação mesmo, se as operações de inserção na tabela pai são feitas na mesma transação que a inserção nas tabelas filhas, então o banco deveria “enxergar” o insert mesmo sem o commit. O problema pode ser que a sua regra de negócio esteja sendo executada dentro de mais de uma transação. Isso pode ser tanto erro de lógica, quanto erro de configuração no JDBC ou ainda pode ser falta de suporte do banco de dados mesmo.

Se não me engano, isso depende da configuração de isolamento de transação. Se no caso dele o isolamento de transação for READ_COMMITED então não acho que irá funcionar.

mateusviccari

rimolive:
rmendes08:
drsmachado:
Isso não é um problema do java, é do banco de dados.
As constraints violations dizem respeito à regras que estão sendo quebradas.
No caso, sim, será preciso confirmar (commit) a transação.
Se estiver usando JDBC, será preciso obter a PK da venda e, então, inserir junto a cada elemento item de venda.

Não necessariamente. O problema é a demarcação de transação mesmo, se as operações de inserção na tabela pai são feitas na mesma transação que a inserção nas tabelas filhas, então o banco deveria “enxergar” o insert mesmo sem o commit. O problema pode ser que a sua regra de negócio esteja sendo executada dentro de mais de uma transação. Isso pode ser tanto erro de lógica, quanto erro de configuração no JDBC ou ainda pode ser falta de suporte do banco de dados mesmo.

Se não me engano, isso depende da configuração de isolamento de transação. Se no caso dele o isolamento de transação for READ_COMMITED então não acho que irá funcionar.

Esse isolamento de transação é um recurso do banco de dados? ou é alguma configuração no JDBC?

rmendes08

mateusviccari:
rimolive:
rmendes08:
drsmachado:
Isso não é um problema do java, é do banco de dados.
As constraints violations dizem respeito à regras que estão sendo quebradas.
No caso, sim, será preciso confirmar (commit) a transação.
Se estiver usando JDBC, será preciso obter a PK da venda e, então, inserir junto a cada elemento item de venda.

Não necessariamente. O problema é a demarcação de transação mesmo, se as operações de inserção na tabela pai são feitas na mesma transação que a inserção nas tabelas filhas, então o banco deveria “enxergar” o insert mesmo sem o commit. O problema pode ser que a sua regra de negócio esteja sendo executada dentro de mais de uma transação. Isso pode ser tanto erro de lógica, quanto erro de configuração no JDBC ou ainda pode ser falta de suporte do banco de dados mesmo.

Se não me engano, isso depende da configuração de isolamento de transação. Se no caso dele o isolamento de transação for READ_COMMITED então não acho que irá funcionar.

Esse isolamento de transação é um recurso do banco de dados? ou é alguma configuração no JDBC?

As 2 coisas! Você pode configurar o isolamento de transações pelo JDBC. O suporte depende do banco de dados que você está usando. De qualquer maneira, se todas as operações são realizadas dentro de uma única transação você não deveria ter esse tipo de problema.

mateusviccari

Ok, descobri que pelo JDBC da pra usar o seguinte comando:

Que faz com que as transações dessa conexão consigam enxergar registros ainda não “commitados”.

Porém como o hibernate não trabalha com connection(na verdade descobri que existe um método connection() que supostamente retorna a connection atribuída a esta sessão, mas está deprecated) não descobri nada que pudesse ser feito pra setar o isolation mode das conexões do hibernate.

Alguém sabe como posso fazer isso no hibernate?

rmendes08

mateusviccari:
Ok, descobri que pelo JDBC da pra usar o seguinte comando:

Que faz com que as transações dessa conexão consigam enxergar registros ainda não “commitados”.

Porém como o hibernate não trabalha com connection(na verdade descobri que existe um método connection() que supostamente retorna a connection atribuída a esta sessão, mas está deprecated) não descobri nada que pudesse ser feito pra setar o isolation mode das conexões do hibernate.

Alguém sabe como posso fazer isso no hibernate?

Você deve setar a propriedade hibernate.connection.isolation no persistence.xml. O valor da propriedade deve ser o valor inteiro da constante correspondente no JDBC.

drsmachado

Como está o relacionamento entre a classe pai e as filhas? Herança mesmo? Ou composição?

mateusviccari

Na verdade não tem relacionamento na classe, eu tenho direto a chave estrangeira, por exemplo na classe itemVenda eu tenho uma variavel Integer codVenda, que é exatamente como está definido la na tabela do banco.

drsmachado

Explicado!
Se você tivesse, ao invés deste atributo integer um objeto que representasse a classe “pai”, você não teria este problema.
Pois, assim que o objeto que representa a classe pai fosse persistido, o id do mesmo estaria visível à todos os filhos que o possuem como atributo.

mateusviccari

esse “persistido” que você diz, significa quando você dá o commit no objeto, ou quando você faz o save no objeto?

Criado 17 de outubro de 2012
Ultima resposta 22 de out. de 2012
Respostas 17
Participantes 5