Transação x DAO

32 respostas
skill_ufmt

Galera,

Vi alguns controles de transação em algumas aplicações por aqui, mas não estou concordando muito com a forma como estão.
Tem app que quando precisa-se criar mais de um DAO ou fazer mais de uma operação com o banco, simplemente passando a conexao via set, para dentro do VO, onde exixste uma váriavel de Connnection, passa-se esse VO para o método do DAO, inserir(VO), e lá dentro verificam se essa variávle está null ou não para criar ou não outra conexão.

Também tem outra app em que as conexões são passadas no cabeçalho do método, inserir(AlgumaCoisa, conexão).

E uma que fiquei mais intrigado, é que a conexão é passada na criação do DAO, new DAO(conexão, flag), onde passam true ou false no flag, pra saber se vão ou não fechar essa conexão.

Enfim,
Como você geralemtne gerenciam suas transações quando necessitam de numa mesma conexão efetuar mais de uma operaçao com o banco, mais de uma instanciação de DAO, JTS, JTA, conexão no cabeçalho mesmo?

Uma maneira elegante, simples e certa de preferência :slight_smile:

Agraço

32 Respostas

louds

Usando uma thread-bound Connection.

Em ambientes web tem um servlet-filter responsavel por gerenciar conexões e transações.

skill_ufmt

louds:
Usando uma thread-bound Connection.

Em ambientes web tem um servlet-filter responsavel por gerenciar conexões e transações.

seria uma aplicaçãozinha web, que vai rodar no tomcat por exemplo ou jetty como queiram.

louds

Eu faço isso porque é a forma mais facil…

public class ConnectionManager{

public static Connection get() {
   //retorna a conexão corrente ou abre uma nova e desabilita transação
}


public static Connection beginTx() {
   //retorna a conexão corrente, inicia transação ou abre uma nova e inicia transação 
}

}

public static void setRollbackOnly() {
  //proibe que um commit ocorra
}

public static void release() {
  //se rollback ou exception con.rollback(), senão con.commit()
  con.close();
}
}

É só colocar num servlet filter para sempre executar o release ao final do processamento e pronto. Veja que o exemplo tá bem simplificado pois não preve coisas como checkpointing, early commit/rollback e qualquer requisito de transacional que não seja o básico (1 con - 1 tx local - 0 cp).

Nos daos ai é só fazer assim:

public class LalalaDao {
  void insert(Lalala l) {
    PreparedStatement stmt = ConnectionManager.beginTx().prepareStatement("insert into lalala(?)");
    stmt.setInt(1, l.getXXX());
    stmt.execute();
    //FIXME liberar stmt
  }
}
skill_ufmt

louds:
Eu faço isso porque é a forma mais facil…

Valeu pela dica.

O pessoal ta querendo matar umas focas usando struts, sabe se ele implementa algo relacionado a autenticação? ou algo relacionado a essas transações?

skill_ufmt

louds:
Eu faço isso porque é a forma mais facil…

Esse exemplo seu é algo parecido com isso:

UserTransaction utx = Util.getUserTransaction();		
		
			
	
			utx.begin();
			
				
			dao.create("R", "1999", "Game Day");
			dao.create("G", "1999", "Tarzan");
			dao.create("R", "2005", "Blair Witch Project Reloaded");
			dao.create("PG-13", "2005", "Raiders of the Lost Ark Reloaded");
			dao.create("R", "2005", "Bridget Jones Diary Reloaded");
			
			utx.commit();

e com os devidos, rollback e closes ?

danieldestro

louds, como fica a concorrência, neste caso?

louds

daniel, a implementação usa uma ThreadLocal para manter o estado de cada thread, isso elimina problemas de concorrencia.

skill_ufmt, sim, bem parecido. A diferença é o local onde se inicia e termina a transação, no seu exemplo fica no meio do código de negocios, no meu fica em um servlet filter separado. A vantagem de fazer tudo de um lugar só é permitir compor código transacional sem se preocupar com criação espuria de múltiplas transações.

skill_ufmt

Se bem entedi, o modo do louds, poderia fazer assim que daria no mesmo:

try {
con.getConnection();

con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.executeUpdate(
"UPDATE INVENTORY SET STOCK = (STOCK – 10) WHERE PRODUCTID = 7");
stmt.executeUpdate(
"UPDATE SHIPPING SET SHIPPED = (SHIPPED + 10) WHERE PRODUCTID = 7");


algumMétodo(); 

con.commit();

}

Mas como o Daniel disse, como fica a concorrência neste caso? coloco syncronized no método?

danieldestro

Hummmm… mto interessante. E eu sempre me perguntava como isso era feito… hahahhahhahaaa

skill_ufmt

louds:

skill_ufmt, sim, bem parecido. A diferença é o local onde se inicia e termina a transação, no seu exemplo fica no meio do código de negocios, no meu fica em um servlet filter separado. A vantagem de fazer tudo de um lugar só é permitir compor código transacional sem se preocupar com criação espuria de múltiplas transações.

ah ta, concordo, então estes dois exemplos que coloquei aqui, estão certos, só faltando mesmo refinar no quesito de favorecer composição.

louds

Sim, nunca manipule a transação dentro de um DAO. Existem alguns muito poucos cenarios que justifica fazer isso.

skill_ufmt

louds:
daniel, a implementação usa uma ThreadLocal para manter o estado de cada thread, isso elimina problemas de concorrencia.

Poderia postar um código exemplo dessa sua Thread?
Você abre uma Thread para cada conexão? cada método? cada transação, jogando a conexão nessa thread?

louds

skill_ufmt:
Poderia postar um código exemplo dessa sua Thread?
Você abre uma Thread para cada conexão? cada método? cada transação, jogando a conexão nessa thread?

Não… O problema de concorrencia é quando varias threads acessam o mesmo recurso, se eu criasse mais threads, só pioraria. :wink:

Em vez disso uso a class java.lang.ThreadLocal. Ela permite de forma facil guarda uma variavel que o valor depende da thread acessando.

skill_ufmt

louds:
Sim, nunca manipule a transação dentro de um DAO. Existem alguns muito poucos cenarios que justifica fazer isso.

vo usar um método do mister_m hehe
me diga um caso de uso exemplo, onde justifica este uso?

Lembrando que a equipe quer usar usar struts, esse controle de trheads teu, ficaria onde neste cenário? Action? uma clase para que as Action usem? no Tomcat?

LuizAvila

Louds

Achei muito interessante, e simplificada sua solução.

Podes colocar mais um exemplo disso aqui pra gente visualizar lega?

Tipo implementação no Filter, onde é criada, e como o DAO “enxerga essa classe”?

Acho que se for usado o Filter não importa muito se é implementado direto em Servlet/JSP ou Struts né?

louds

Eu acho que usar um Servlet Filter tem a vantagem de ser facil e não atrapalha no código dos teus servlets/actions/JSF events…

Uma alternativa, para quem usa Struts, é estender uma das classes de processamento do framework, só não me perguntem qual, porque não sei. Com webwork 2 isso pode ficar em um interceptor.

O único problema de usar um servlet filter é o tratamento de erro quando o commit falha, fica um pouquinho mais chato.

Os DAOs acessam essa classe normalmente ue… são métodos estáticos.

Um bom exemplo? Acho que um bom exemplo é o Servlet Filter que o SpringFramework tem que faz exatamente isso que eu tou sugerindo :wink:

danieldestro

RequestProcessor

skill_ufmt

Aproveitando o ensejo dos DAOs,

Eu vi em algum lugar só não me recordo onde, em que se falava ser ruim utilizar StringBuffer + append(""), para formar as query, mas sim deveria-se usar PreparedStatement.

se a afirmativa é verdadeira, porque ela é? qual o problema que pode ocorrer?

danieldestro

Porque é mais fácil e prático usar PreparedStatement. Mas você pode usar em conjunto com StringBuffer sim, apenas deixando os locais dos valores com “?”.

skill_ufmt

quanto ao “?” sem problemas, só queria ver o caso mesmo de usar StringBuffer.

mas valeu Daniel

mister_m

skill_ufmt:
Aproveitando o ensejo dos DAOs,

Eu vi em algum lugar só não me recordo onde, em que se falava ser ruim utilizar StringBuffer + append(""), para formar as query, mas sim deveria-se usar PreparedStatement.

se a afirmativa é verdadeira, porque ela é? qual o problema que pode ocorrer?

SQL Injection.

Se você tem uma query como:

"SELECT * FROM TABELA WHERE X = '" + parametro+  "'"

o usuário pode entrar com o parâmetro assim:

' OR 1=1 OR '' = '

e ver tudo que não deveria ver :mrgreen:

louds

Sem PreparedStatements você vai tem montes de bugs no tratamento de strings.

skill_ufmt

ae, é isso que o mister_m falou, num tava lembrando o nome da paradinha.

Concordo com você também louds

Então realmente é uma má prática usar StringBuffer :wink:

danieldestro

O mau não está em usar StringBuffer, mas sim em deixar de usar PreparedStatement.

LuizAvila

mister__m:
skill_ufmt:
Aproveitando o ensejo dos DAOs,

Eu vi em algum lugar só não me recordo onde, em que se falava ser ruim utilizar StringBuffer + append(""), para formar as query, mas sim deveria-se usar PreparedStatement.

se a afirmativa é verdadeira, porque ela é? qual o problema que pode ocorrer?

SQL Injection.

Se você tem uma query como:

"SELECT * FROM TABELA WHERE X = '" + parametro+  "'"

o usuário pode entrar com o parâmetro assim:

' OR 1=1 OR '' = '

e ver tudo que não deveria ver :mrgreen:

Mas o problema então é usar Statment não StringBuffer…

Pois StringBuffer é pra tratar String. Correto?

danieldestro

Tostines vende mais porque é fresquinho
ou é fresquinho porque vende mais?

skill_ufmt

danieldestro:
Tostines vende mais porque é fresquinho
ou é fresquinho porque vende mais?

Ta certo Daniel, então eu uso stirngBuffer, e jogo le eno PreparedStateman e ta resolvido o problema do injection :wink:

louds

Além do problema de SQL Injection, você pode ter problema com o conteúdo da String, que se não for devidamente “escapada” vai causar erros de execução.

O segundo insert vai dar erro, coisa que com prepared statement não ocorre.

LuizAvila

Louds;

Voltando ao assunto da transação:

Não consegui visualizar o esquema de onde fica a conexão corrente.

Tô viajando? Demais né?

skill_ufmt

LuizAvila:
Louds;
Voltando ao assunto da transação:
Não consegui visualizar o esquema de onde fica a conexão corrente.
Tô viajando? Demais né?

Pelo que entendi, quem gerencia isso, é o container, tu irá configurar as transações no container e ele cuida disso para você.
Agora como fazer isso é que to tentando descobrir hehe

danieldestro

http://javaalmanac.com/egs/java.lang/TLocal.html?l=rel

skill_ufmt

Pessoal, aidan estou com problemas, seguindo sugestões aqui, tentei fazer com que o tomcat controle as transações, então implementei o dataSource e tudo tá perfeito, porém não consigo fazer ele pegar um lookup do Resource de Transaction.

Tentei utilizar uma lib Jotm que usa-se no Jonas para esse fim, porém não tive sucesso.

Declarie isso no server.xml do tomcat, no meu web.xml só tem o datasource.

<Resource name="UserTransaction" auth="Container"
    type="javax.transaction.UserTransaction"/>
  <ResourceParams name="UserTransaction">
    <parameter>
      <name>factory</name>
      <value>[color=red]org.objectweb.jotm.UserTransactionFactory[/color]</value>
    </parameter>
    <parameter>
      <name>jotm.timeout</name>
      <value>60</value>
    </parameter>
  </ResourceParams>

ocorre este erro:
Could not create resource factory instance, org/objectweb/transaction/jta/TMService
at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:146)

Ele não consegue pegar a instancia :frowning:

Existe um UserTransaction já do Tomcat? ou posso usar o que está em javax.transaction.UserTransaction?

outra lib? ou é impossível fazer isso no tomcat?

uma luz : )

Criado 26 de abril de 2005
Ultima resposta 27 de abr. de 2005
Respostas 32
Participantes 5