Re: Gerenciamento de transações. Porque não no DAO?

54 respostas
Mauricio_Linhares

Se você tá chamando “commit()” no Dao, qual a diferença de chamar “commit()” no banco? O que foi que você abstraiu fazendo isso? A lógica do banco de dados está vazando pro código cliente, que nem deveria saber que tem um banco relacional “do outro lado do espelho”.

Se você quer algo concreto, é só ver tudo o que já foi falado sobre ThreadLocal e filtros nos últimos dias, ou dar uma olhada no controle de transações do Spring:

http://static.springframework.org/spring/docs/1.2.x/reference/index.html

54 Respostas

Mauricio_Linhares

Usa o Spring ou então cria interceptors pra fazer do mesmo jeito que o filtro faria em uma aplicação web, usando AOP é barbada.

danieldestro

Não é correto colocar o controle dentro do seu DAO, mesmo pq, se você precisar de uma transação que envolva mais de um DAO, vc tá ferrado.

Eu fiz algo assim:

Transaction t = TransactionManager.beginTransaction(); try { dao1.save( x ); z =dao99.select( 1 ); dao666.update( z ); dao12345.delete( www ); t.commit(); } catch( Exception e ) { t.rollback(); } finally { t.end(); }

Internamente usei ThreadLocal. Meus DAOs pegam a conexão da transação que é compartilhada por eles, via ThreadLocal. Caso não exista uma transação, ele pega um conexão default do DAO.

A conexão retornada pela Transaction é uma casca sobre a Connection original, pois eu desativei coisas como commit(), rollback() e close(), delegando esta função para a Transaction. Por isso é obrigatório chamar o t.end().

Mauricio_Linhares

O código cliente tem que inicializar as transações Daniel? Não seria melhor que isso fosse feito externamente não? Usando interceptors?

O controle saiu de dentro do DAO mas foi parar no código que usa diretamente os DAOs, não parece melhorar muita coisa não.

danieldestro

O que você sugere, numa aplicação web, por exemplo, é que toda a ação do action, em um request, é uma transação, correto?

Ao meu ver isso prende demais a gente. Posso ter mais de uma transação ocorrendo no meu negócio e quero poder ter este controle.

Pelo menos meu código de negócio sabe onde começa e termina sua transação. O que fiz foi simplesmente achar uma forma de desacoplar e abstrair o uso de transação para um modelo mais genérico do que acessar recursos indevidamente, além de ser uma forma mais elegante de controle.

Como em EJB você pode criar um método que atenda a uma nova transação, mas como não uso EJB, fiz usando essa camada de controle.

Mauricio_Linhares

danieldestro:
O que você sugere, numa aplicação web, por exemplo, é que toda a ação do action, em um request, é uma transação, correto?

Ao meu ver isso prende demais a gente. Posso ter mais de uma transação ocorrendo no meu negócio e quero poder ter este controle.

Ora, o Spring dá esse controle sem deixar a transação aparecer pro código cliente :mrgreen:

danieldestro

Mas num sistema onde, nos recursos tecnologicos, não pode aplicar coisas como EJB, Spring e SuperSoluçãoInovadora ™, a melhor solução foi aquela.

Mauricio_Linhares

Nesse caso num tem muita escolha né :lol:

Mas ainda existem os iinterceptadores com AOP né, ninguém vai reclamar de um bytecode a mais (num vai nem perceber) :mrgreen:

danieldestro

heheehe… vc não sabe metada da história lá.
por isso já estou de saco cheio.
em 6 dias pego 40 dias de férias.

Mauricio_Linhares

danieldestro:
heheehe… vc não sabe metada da história lá.
por isso já estou de saco cheio.
em 6 dias pego 40 dias de férias.

Bem que eu queria ficar de saco cheio de férias :mrgreen:

Quer trocar por dois cursos superiores e um estágio miserável? :lol:

danieldestro

2 faculs + estágio? Você tá fudido. que estuda?

Mauricio_Linhares

Jornalismo e Desenvolvimento de Software.

O estágio pelo menos eu resolvo em casa mesmo (eles nem iam ter PC pra rodar o Eclipse mesmo…).

Mas pelo menos tá mais perto do que longe, ano que vem eu termino as duas :mrgreen:

O povo por aí proíbe de usar frameworks é?

danieldestro

Pelo que eu entendí você não trabalha, né?

Então, depende da empresa/gestor, é complicado. Se eles fecham um escopo de tecnologia, é bem difícil sair daquilo e usar outras coisas. Ainda mais em grandes empresas com grandes projetos. Eles têm de gerenciar os detalhes, e é aí que às vezes podem limitar nossa capacidade e inovação.

Lá eu consigo usar muita coisa nova. Eu, quando posso, fica colocando algo pra ajudar, mas não fico inventando muito fora daquilo, ainda mais pq usamos um framework in-house, que fede.

Como nunca usei AOP, não fico tentando inventar e, de repente, perder muito tempo aprendendo algo que pode fadar ao fracasso.

Mauricio_Linhares

Nops, só o estágio e um projeto de pesquisa mesmo.

Vixe, framework próprio é uma coisa complicada. Uns amigos fizeram um framework MVC pra o estágio deles mas no fim a coisa ficou muito complicada e quando eles saíram a galera que entrou “dançou beleza”, porque ficou amarrada a uma coisa não tão bem feita (agente ainda é estudante né :lol: ) e que só tem manutenção lá dentro.

Eu não acho que seja uma boa investir numa coisa dessas se for absolutamente necessário e não houver nenhuma outra opção decente que possa ser usada ou adaptada.

Acho que isso é até uma vantagem do meu estágio, o povo só quer a coisa pronta, não interessa como. Comecei com Struts/Hibernate/JSP/Velocity, agora tô terminando uma migração pro Hibernate 3, colocando o Spring junto com o Struts e eu espero anter de terminar migrar tudo pro Spring MVC. Lá eu to botando a teoria na prática e tá valendo muito a pena, esse negócio das transações “externas” eu botei em prática lá, são as minhas cobaias :mrgreen:

danieldestro:

Como nunca usei AOP, não fico tentando inventar e, de repente, perder muito tempo aprendendo algo que pode fadar ao fracasso.

Sei não velho, AOP não é a resolução pra todos os problemas, mas esse tipo de “interceptação” é uma das especialidades, dá uma olhada no AspectJ, pode ser que te ajude numa outra coisa que não tem nada haver com isso :smiley:

danieldestro

Esse FMK in-house foi feito em 99 ou 2000. Cara, é uma grande lástima da minha vida. O cara que o fez, simplementes fez uma versão para quase cada um dos projetos existentes. Isso que alguns migram de plataforma e temos que trocar o FMK. É um Deus nos acuda. Um saco!

Por isso já tô de saco cheio. Quero inovar, por coisas novas, inventar, e não me limitar. Para isso acho que preciso mesmo pôr em prática a minha consultoria e projetos próprios. Logo, logo!

Sobre o AOP, eu tô ligado, mas qdo se tem prazos e limitações, inovar não é a “melhor” solução.

Thiago_Senna

Maurício Linhares:
O código cliente tem que inicializar as transações Daniel? Não seria melhor que isso fosse feito externamente não? Usando interceptors?

O controle saiu de dentro do DAO mas foi parar no código que usa diretamente os DAOs, não parece melhorar muita coisa não.

Olá, desculpe por interromper a conversa de vocês sobre fmk, empresas e outras coisitas… mas queria aproveitar a colocação acima do Maurício para tirar uma dúvida!

Bom, a questão é a seguinte.

Se eu ficar amarrando o início da transação e o término dela em um interceptor, filtro, ou seja lá o que for acho super bacana. No entanto, e quando inicio uma transação que só irá fazer um select all?? Para isso eu não precisaria de uma transação!

Como vcs lidam com isso? Vcs iniciam um transação assim mesmo, ou em caso de consultas vcs não iniciam a transação?

Se Vocês não iniciam a transação, então como vcs fazer para controlar isso?

Abraços!
Thiago

Mauricio_Linhares

Thiago Senna:
Se eu ficar amarrando o início da transação e o término dela em um interceptor, filtro, ou seja lá o que for acho super bacana. No entanto, e quando inicio uma transação que só irá fazer um select all?? Para isso eu não precisaria de uma transação!

Como vcs lidam com isso? Vcs iniciam um transação assim mesmo, ou em caso de consultas vcs não iniciam a transação?

Eu sempre inicio uma transação, mesmo que seja pra um select.

danieldestro

Por isso não sou muito fã desta abordagem. Perda de recursos.

Mauricio_Linhares

Por isso não sou muito fã desta abordagem. Perda de recursos.

Será que faz diferença?

Nunca medi isso… mas é até uma boa não fazer em selects.

No fim, num tenho como saber, é o Spring que faz pra mim :mrgreen:

louds

Gerenciar as transações fora dos DAOs permite você usar mais de um DAO sem muita dor de cabeça.

E para evitar ficar repetindo o código de gerenciamento de transações faço o mesmo que com statements e resultsets, uso um Command.

Crio um TransactionalCommand e mando executar ele dentro de um contexto transacional ou não. Veja que é possivel inclusive proteger de ter uma action que deveria ser read-only modificando a base. Fazendo wrapping da Connection como o Destro sugeriu.

danieldestro

Não entendi muito bem o seu TransactionalCommand, Louds. Pode pôr um trecho de exemplo do uso? (pra clarear).

Mauricio_Linhares

louds:
Gerenciar as transações fora dos DAOs permite você usar mais de um DAO sem muita dor de cabeça.

Por isso que eu adoro o controle declarativo do Spring :smiley:

louds

Maurício, spring é legal, mas quase sempre só rola usar em projetos greenfield e sem nenhum “legado” como frameworks proprietarios e políticas corporativas. Eu nem pensei em usar springframework no atual projeto por que o trabalho que daria para ter ele homologado não ia valer o beneficio.

Tem muitos cenarios em que não usar transações, ou usar isolamentos diferente, é indispensavel.

Primeiro tem performance, uma transação é cara pro RDBMS manter. Segundo tem questões de locking e tosquisses de cada banco. Por último tem algumas operações que são melhores executadas sem transação nenhuma (um delete de 500mil registros por exemplo).

Por exemplo, o mysql com InnoDB não permite “select count(*) from x” executar em paralelo com “insert into x values(1)” até mesmo em read commited.
Outro exemplo é o sqlserver, algumas queries mais complexas nunca completam e podem fundir o servidor quando você tem muitas transações simultâneas (lock escalation acaba fazendo tuas queries tentarem table lock em metade do banco).
Por fim, emissão de relatorios ou consultas a maioria pode ser executada fora de um contexto transacional, read uncommited mesmo, sem problema. Alguns bancos reconhecem essa barbada e são muito mais eficientes.

Daniel, o transactional command é bem simples:

class TransactionManager {

public void executeWithTransaction(Runnable r)  { //
 Transaction t = session.beginTransaction();
 boolean commited = false;
 try {
  r.run();
  t.commit();
  commited = true;
 } finally {
   if(!commited) 
     t.rollback();
 }
}

}

Dai você simplesmente envolve o teu código em um Runnable e pronto.

Coisas como transações aninhadas e junção de transação exigem um pouco mais de esforço, mas o básico é isso ae.

Mauricio_Linhares

louds:
Maurício, spring é legal, mas quase sempre só rola usar em projetos greenfield e sem nenhum “legado” como frameworks proprietarios e políticas corporativas. Eu nem pensei em usar springframework no atual projeto por que o trabalho que daria para ter ele homologado não ia valer o beneficio.

Cara, acho que quando eu começar a trabalhar vou me matar :shock:

danieldestro

èééééé amigo, como eu disse, você não viu metada ainda.
Pensou quando te empurrarem o TosquiceFramework ™? Ou então a SoluçãoIn-HouseQueÉUmDrogaEUmaBombaGrande ?

louds

Sem contar que você vai ter que aprender ele por osmose do código existente. Afinal, ainda tá para ser criado o framework caseiro com documentação razoavel.

danieldestro

A maior bizarrice que eu já ví. “Framework de Mensagens XXX*” (XXX = nome da empresa).

O esquema “funciona” assim:

Um programa que eu fiz, estilo o Javalee (http://javalee.sf.net), gerou milhares de classes e stored procedures baseado nas tabelas do banco.

Esse Framwork de Mensagens (aka MI) recebe umas mensagens textuais para interpretar e executar certa lógica.

Explico. Para telas de cadastro simples, é bem fácil. Você tem uma tela com os campos (id e nome), para a tabela pessoa.

Aí, no request você manda os dados e mais a msg=“Pessoa;create|Pessoa;insert”. O MI insere a pessoa no BD.

Só que é só isso. Não tem ajuda pra jogar dados na tela e etc.

O único bem disso é em telas de cadastro BEM simples, pois você não programa em Java, apenas manda a menagem. Mas quando envolve processos mais complicados, FOD$U!!!

louds

noel,

ThreadLocal não elimina o uso de pool, apenas elimina o passa-passa de objetos entre os varios layers da aplicação. Com TL, eu faço +/- assim:

try {
  threadLocal.put(pool.getConnection());
} finaly{
 ((Connection)threadLocal.get()).close();
  threadLocal.put(null);
}

Quanto a Runnable, você tá confundindo a interface Runnable com a classe Thread. Usar a interface não implica em criar threads.

Veja que se você usa uma conecção por DAO, tuas operações não são transacionais, afinal todos precisam todas usar a mesma conecção.

louds

Normalmente uma ThreadLocal é uma variavel estática com getter público e setter não-público. Ou seja, todo mundo pode pegar.

Mauricio_Linhares

Dentro da mesma thread.

danieldestro

Já me perguntaram em PM, como eu implementei meu controle transacional. Vou colocar o código aqui. É bem simples!

Transaction.java
package my.trans;

import java.sql.*;
import java.util.Map;
import javax.sql.DataSource;

public class Transaction {
    private Connection conn;
    private boolean oldAutCommit;
    
    public Transaction() {
    }
    
    public void end() {
        TransactionManager.endTransaction();
        if (this.conn != null) {
            try { this.conn.setAutoCommit( this.oldAutoCommit );  } 
            catch (SQLException e) {}
            try { this.conn.close(); } 
            catch (SQLException e) {}
        }
    }
    
    public Connection getConnection(String dataSource) throws Exception {
        if (this.conn == null) {
            try {
                synchronized (this) {
                    this.oldAutoCommit = this.conn.getAutoCommit();
                    this.conn = pegaAConexaoDeAlgumLugar();
                    //seja de um POOL, via JNDI etc...
                    this.conn.setAutoCommit(false);
                }
            }
        }
        return new TransactionConnection(this.conn);
    }

    public void rollback() throws Exception {
         this.conn.rollback();
    }
    
    public void commit() throws Exception {
         this.conn.commit();
    }
}
TransactionConnection.java
package my.trans;

import java.sql.*;

protected class TransactionConnection implements Connection {
    private Connection conn;
    
    protected TransactionConnection(Connection conn) {
        if (conn == null) {
            throw new IllegalArgumentException();
        }
        this.conn = conn;
    }

    public int getHoldability() throws SQLException {
        return conn.getHoldability();
    }

    public int getTransactionIsolation() throws SQLException {
        return conn.getTransactionIsolation();
    }

    public void clearWarnings() throws SQLException {
        conn.clearWarnings();
    }

    public void close() throws SQLException {
        //conn.close();
    }

    public void commit() throws SQLException {
        //conn.commit();
    }

    public void rollback() throws SQLException {
        //conn.rollback();
    }

    public boolean getAutoCommit() throws SQLException {
        //return conn.getAutoCommit();
        return false;
    }

    public boolean isClosed() throws SQLException {
        return conn.isClosed();
    }

    public boolean isReadOnly() throws SQLException {
        return conn.isReadOnly();
    }

    public void setHoldability(int arg0) throws SQLException {
        conn.setHoldability(arg0);
    }

    public void setTransactionIsolation(int arg0) throws SQLException {
        conn.setTransactionIsolation(arg0);
    }

    public void setAutoCommit(boolean arg0) throws SQLException {
        //conn.setAutoCommit(arg0);
    }

    public void setReadOnly(boolean arg0) throws SQLException {
        conn.setReadOnly(arg0);
    }

    public String getCatalog() throws SQLException {
        return conn.getCatalog();
    }

    public void setCatalog(String arg0) throws SQLException {
        conn.setCatalog(arg0);
    }

    public DatabaseMetaData getMetaData() throws SQLException {
        return conn.getMetaData();
    }

    public SQLWarning getWarnings() throws SQLException {
        return conn.getWarnings();
    }

    public Savepoint setSavepoint() throws SQLException {
        return conn.setSavepoint();
    }

    public void releaseSavepoint(Savepoint arg0) throws SQLException {
        conn.releaseSavepoint(arg0);
    }

    public void rollback(Savepoint arg0) throws SQLException {
        //conn.rollback(arg0);
    }

    public Statement createStatement() throws SQLException {
        return conn.createStatement();
    }

    public Statement createStatement(int arg0, int arg1) throws SQLException {
        return conn.createStatement(arg0, arg1);
    }

    public Statement createStatement(int arg0, int arg1, int arg2) throws SQLException {
        return conn.createStatement(arg0, arg1, arg2);
    }

    public Map getTypeMap() throws SQLException {
        return conn.getTypeMap();
    }

    public void setTypeMap(Map arg0) throws SQLException {
        conn.setTypeMap(arg0);
    }

    public String nativeSQL(String arg0) throws SQLException {
        return conn.nativeSQL(arg0);
    }

    public CallableStatement prepareCall(String arg0) throws SQLException {
        return conn.prepareCall(arg0);
    }

    public CallableStatement prepareCall(String arg0, int arg1, int arg2) throws SQLException {
        return conn.prepareCall(arg0, arg1, arg2);
    }

    public CallableStatement prepareCall(String arg0, int arg1, int arg2, int arg3) throws SQLException {
        return conn.prepareCall(arg0, arg1, arg2, arg3);
    }

    public PreparedStatement prepareStatement(String arg0) throws SQLException {
        return conn.prepareStatement(arg0);
    }

    public PreparedStatement prepareStatement(String arg0, int arg1) throws SQLException {
        return conn.prepareStatement(arg0, arg1);
    }

    public PreparedStatement prepareStatement(String arg0, int arg1, int arg2) throws SQLException {
        return conn.prepareStatement(arg0, arg1, arg2);
    }

    public PreparedStatement prepareStatement(String arg0, int arg1, int arg2, int arg3) throws SQLException {
        return conn.prepareStatement(arg0, arg1, arg2, arg3);
    }

    public PreparedStatement prepareStatement(String arg0, int[] arg1) throws SQLException {
        return conn.prepareStatement(arg0, arg1);
    }

    public Savepoint setSavepoint(String arg0) throws SQLException {
        return conn.setSavepoint(arg0);
    }

    public PreparedStatement prepareStatement(String arg0, String[] arg1) throws SQLException {
        return conn.prepareStatement(arg0, arg1);
    }
    
}
TransactionManager .java
package my.trans;

public class TransactionManager {
    private static final ThreadLocal threadLocal = new ThreadLocal();
    
    private TransactionManager() {}
    
    public static synchronized Transaction beginTransaction() {
        Transaction t = (Transaction) threadLocal.get();
    	if (t != null) {
    	    throw new RuntimeException("Já existe uma transação ativa");
    	}
    	t = new Transaction();
    	threadLocal.set(t);
        return t;
    }
    
    public static synchronized Transaction getTransaction() {
        return (Transaction) threadLocal.get();
    }
    
    protected static synchronized void endTransaction() {
    	if (threadLocal.get() == null) {
    	    throw new RuntimeException("Não existe uma transação ativa");
    	}
        threadLocal.set(null);
    }
}

No DAO:

public class MeuDAOLegal {
  private Connection getConnection() {
    if( TransactionManager.getTransaction() != null ) {
       return TransactionManager.getTransaction().getConnection();
    } else {
      return pegarConexaoDeOutroLugar();
    }
  }

  public void save( Object o ) {
    conn = getConnection();
    // catch the video mothafucker...
    conn.close();
  }
}

E para usar:

Transaction t = TransactionManager.beginTransaction();
try {
   /* chamada(s) para o(s) Dao(s) */
   t.commit();
} catch (Exception e) {
   t.rollback();
} finally {
   t.end();
}

Pode ser mais abstraído, mas basicamente é isso.

dukejeffrie

Louds, como vc faz com Exceptions que seu runnable tem que lançar? Tudo unchecked?

O esqueminha do Tiny Marbles é exatamente assim, mas ainda não consegui inventar um esquema decente de lançar exceções arbitrárias.

F

po… sinceramente…
codigo de infra-estrutura é chato pra caramba,

porque nao usar um EJB session bean ou uma fachada pojo com Spring?

na forma declarativa fica muito mais facil de resolver problemas mais complexos, pois voce seta 1 tipo de atributo de comportamento pra cada componente ou chamada (required, required new, supported etc,)

falow

louds

dukejeffrie:
Louds, como vc faz com Exceptions que seu runnable tem que lançar? Tudo unchecked?

O esqueminha do Tiny Marbles é exatamente assim, mas ainda não consegui inventar um esquema decente de lançar exceções arbitrárias.

O runnable empacota todas exceptions como unchecked. Até pouco tempo a maioria dos casos eram “ou funcionou ou deu pau”, então não existia um tratamento mais apurado para as exceptions lançadas.

Recentemente tive que implementar um caso no qual eu precisava executar transações aninhadas, tinha que diferenciar o tipo de erro ocorrido por uma unit-of-work para tomar uma decisão abort/retry/change.

Nesse caso eu passei a usar EDU.oswego.cs.dl.util.concurrent.Callable e a tratar exceptions usando uma Chain Of Responsibility com filtros que ou assimilavam a exception ou convertiam ela para uma mais util.

Felipe, usar EJB só para ter gerênciamento de transações é loucura, muita pentelhação e tralha por pouca coisa. Spring é legal, use no lugar de fazer na mão sempre que possivel, mas infelizmente o framework de suporte a Hibernate e transações precisa ser alterado (leia editar os fontes do Spring) se você quer suportar coisas como replicação, particionamento, fail-over ou stop/resume. Além do fato que em vários projetos usar Spring simplesmente não é uma opção (cliente não quer, equipe não sabe usar, gerênte cagou regra sobre…).

F

louds:

Felipe, usar EJB só para ter gerênciamento de transações é loucura, muita pentelhação e tralha por pouca coisa. Spring é legal, use no lugar de fazer na mão sempre que possivel, mas infelizmente o framework de suporte a Hibernate e transações precisa ser alterado (leia editar os fontes do Spring) se você quer suportar coisas como replicação, particionamento, fail-over ou stop/resume. Além do fato que em vários projetos usar Spring simplesmente não é uma opção (cliente não quer, equipe não sabe usar, gerênte cagou regra sobre…).

só para isso é exagero mas nao loucura 8)
e tb session beans sao moleza de implementar… diferente dos entity… e alem do controle de transação trazem outras facilidades, que as vezes sao uteis

qto ao particionamento, replicação… os DB´s deveriam cuidar disso pra nos de forma transparente não? a nao ser q vc replique ou fragmente na mao… mas eu nunca vi isso

oq eu quis dizer… é que escrevendo o codigo de transação (o controle dela), um caso um pouquinho mais elaborado, como usar + de 1 componente, ja pode ficar chato e com muito “codigozinho” pra implementar e dar manutencao…

tendo ferramentas que cuidam desse controle transacional pra nos… pra que ficar implementando codigo pra isso? hehehe

:smiley:

louds

Sim, mas te obriga a usar um AS, eu não escrevo aplicações web/online a meses, entretanto tenho necessidades transacionais muito chatas. SLSB são uteis somente quando você tem um cenario que eles se encaixam, senão são um enorme entrave.

Replicação quem cuida de fazer é o banco mesmo, mas eu ainda tou para ver um driver JDBC que de forma transparente acesse as réplicas quando preciso fazer consultas apenas. Replicar o RDBMS faz, mas acessar as réplicas é problema da aplicação.

Particionamento em todos os casos que eu vi era gerenciado pela aplicação. Existem RDBMS que fazer isso, mas ou ainda são produtos beta (mysql), ou o custo é insanamente caro (imagine um deployment de 40 servidores oracle rac?), ou simplesmente não escalam (oracle rac tem um limite baixo no número de nós).

A maioria dos lugares que conheço que faz particionamento de dados, faz na camada de aplicação. Tou falando de sites como flickr e livejournal, por exemplo. A escalabilidade e os custos são muito boas como você pode verificar.

felipecruz:

oq eu quis dizer… é que escrevendo o codigo de transação (o controle dela), um caso um pouquinho mais elaborado, como usar + de 1 componente, ja pode ficar chato e com muito “codigozinho” pra implementar e dar manutencao…

tendo ferramentas que cuidam desse controle transacional pra nos… pra que ficar implementando codigo pra isso? hehehe
:smiley:

Como menCionei, nem todos os casos existem ferramentas que atendem, ou então simplesmente não é possivel usá-las. Fora isso, concordo com você, não faz sentido escrever código de infra, que é chato e dificil, se já existem implementações por ai.

F

concordo com voce… hehe mas oq vc descreveu são 20% dos casos no maximo

pra maioria das pessoas um spring ou EJB ja é suficiente!

o particionamento q vc menciono… é logico e nao fisico… por isso eles tao na camada de aplicação… o particionamento fisico TEM q ser transparente… se nao for tem algo de errado…

mas ai ja é fugir mto do topico ahuehua

A

Também acho que o gerenciamento de transações NÃO deve estar nos DAOs. Caso vc precise de dois ou mais DAOs para executar uma mesma transação, a implementação fica difícil.

Nesse caso, eu também optaria por usar um AS com EJBs. As vantagens são enormes!!!

O AS abstrai as funcionalidades de gerenciamento de transação. Além disso, a aderência aos padrões J2EE permite que vc escolha o AS que mais adeque-se às suas necessidades (hoje, os players fornecem o básico, descrito na especificação, e vão muito além quando o assunto é otimização).

Se vc precisar de segurança, ela está lá, é só ativar.
Se vc precisar de clusterização, ela está está lá, é só ativar.
Se vc precisa de load balancing, ele está lá, é só ativar.
Se vc precisar de transações distribuídas, sejam quão chatas elas forem, elas estão, é só ativar.
Se vc precisar trocar de AS, outros estarão lá, com suas vantagens e desvantagens.

Pq que reinventar a roda? Depois o pessoal fica reclamando das bombas que pegam de outros desenvolvedores que criam frameworks proprietários.

louds

Taz:
Também acho que o gerenciamento de transações NÃO deve estar nos DAOs. Caso vc precise de dois ou mais DAOs para executar uma mesma transação, a implementação fica difícil.

Nesse caso, eu também optaria por usar um AS com EJBs. As vantagens são enormes!!!

O AS abstrai as funcionalidades de gerenciamento de transação. Além disso, a aderência aos padrões J2EE permite que vc escolha o AS que mais adeque-se às suas necessidades (hoje, os players fornecem o básico, descrito na especificação, e vão muito além quando o assunto é otimização).

Se vc precisar de segurança, ela está lá, é só ativar.
Se vc precisar de clusterização, ela está está lá, é só ativar.
Se vc precisa de load balancing, ele está lá, é só ativar.
Se vc precisar de transações distribuídas, sejam quão chatas elas forem, elas estão, é só ativar.
Se vc precisar trocar de AS, outros estarão lá, com suas vantagens e desvantagens.

Pq que reinventar a roda? Depois o pessoal fica reclamando das bombas que pegam de outros desenvolvedores que criam frameworks proprietários.

Cara, segurança definida no J2EE é muito, muito ruim. Qualquer coisa que não seja ‘área protegida + form de login’ não existe padrão, você é obrigado a utilizar extensões proprietárias. O clássico exemplo de implementar login programático na aplicação continua impossivel de forma padronizada.

Você não precisa de EJB ou um AS para usar clustering e load balancing, normalmente você está melhor usando outras soluções que não um application server para isso.

Se você precisar de transações distribuidas, usar um AS vai ser o menor dos teus problemas, então é melhor mesmo usar um. :wink:

Quanto a trocar de AS, esse teu argumento é brincadeira, nunca vi a migração de qualquer aplicação de media complexidade entre AS diferentes ser menos que um INFERNO. Normalmente já um problema enorme trocar a versão, de fornecedor então…

A

louds:

Cara, segurança definida no J2EE é muito, muito ruim. Qualquer coisa que não seja ‘área protegida + form de login’ não existe padrão, você é obrigado a utilizar extensões proprietárias. O clássico exemplo de implementar login programático na aplicação continua impossivel de forma padronizada.

Acho que não. Autenticação é um dos aspectos de segurança (e talvez o mais simples!!!) tratados na J2EE. :wink:

louds:

Você não precisa de EJB ou um AS para usar clustering e load balancing, normalmente você está melhor usando outras soluções que não um application server para isso.

Quais soluções? Como vc implementou?

louds:

Quanto a trocar de AS, esse teu argumento é brincadeira, nunca vi a migração de qualquer aplicação de media complexidade entre AS diferentes ser menos que um INFERNO. Normalmente já um problema enorme trocar a versão, de fornecedor então…

Se foi um INFERNO é pq foram utilizados recursos proprietários. Se um arquiteto trabalha com o requisito de que a aplicação deve ser portável entre ASs, obviamente ele não vai deixar que o time de desenvolvimento utilize recursos proprietários. Além disso, a troca de AS tb não é muito frequente e, geralmente, as empresas estão contentes com os fornecedores que possuem atualmente.

louds

Taz:
louds:

Cara, segurança definida no J2EE é muito, muito ruim. Qualquer coisa que não seja ‘área protegida + form de login’ não existe padrão, você é obrigado a utilizar extensões proprietárias. O clássico exemplo de implementar login programático na aplicação continua impossivel de forma padronizada.

Acho que não. Autenticação é um dos aspectos de segurança (e talvez o mais simples!!!) tratados na J2EE. :wink:

Bom, então me mostra como faço para implementar autenticação programática com j2ee 1.4? Não vou nem falar de autorização, pq o modelo é tão ruim que não permite, por exemplo, definir políticas de acesso por instância. Resumindo, o modelo de autenticação e autorização não é nenhum pouco plugavel ou extensivel.

Taz:

Load balancing é muito melhor feito por uma solução de hardware ou um software especializado como o PLB. Clustering depende muito da arquitetura do projeto, como a maioria dos sistemas que trabalhei eram share-nothing, não utilizamos nada de especial. No resto o máximo que usamos foi um cache distribuido.

Taz:

Negativo, toda migração de versões/fornecedores é um inferno pelos seguintes motivos:

:arrow: A spec possui partes não especificadas, ou mal especificadas.
:arrow: Containers diferentes, bugs diferentes.
:arrow: Ninguém desenvolve aplicação J2EE, todo mundo desenvolve J2EE implementação xyz.

Moral da história, aplicações J2EE são muito mais facilmente portaveis que uma escrita em C++ e DCOM, por exemplo, mas não são a panaceia para o assunto.

A

O assunto já perdeu o foco. Portanto, se vc tem dúvidas abra outros tópicos. Estou aqui para ajudar as pessoas e, com isso, tb aprender. Não estou aqui para me envolver em disputas de egos.

Existem pencas de artigos, livros e gurus que defendem a abordagem J2EE (Até Rod Jonhson, um grande opositor da J2EE, defende EJB como uma opção!!!). Se vc quer reinventar a roda, essa é uma decisão sua. Esteja preparado para adotar o lado “programático” das coisas e implementar infra-estrutura.

Se não usou é porque leu isso em algum lugar e foi convencido. Cite as fontes. :wink:

louds

Não lemos coisa alguma. Não existiu convencimento. Usamos simplesmente aquilo que melhor solucionava o problema.

Clustering, por exemplo, é a uma das coisas mais raras de você encontrar em qualquer empresa, pois implica em Single System Image. A norma são server farms com load balancers, uma arquitetura que normalmente escala muito mais.

Hempx

Eu não li essa discussão toda então não sei do que vocês estão falando. Mas você falou alguns conceitos que eu ainda não entendo bem. Sem querer abusar da sua boa vontade queria esclarer algumas dúvidas com você louds ou qualquer outra pessoa que tenha conhecimento sobre.

:arrow: Clustering então pelo que entendi sempre requer replicação de dados? Ou seja, Clustering é quando precisamos de confiabilidade?

:arrow: Eu pensava que balanceamento de carga já era Clustering. Pelo visto então não é!?!

:arrow: Eu trabalhei num sistema EJB que foi colocado em cluster, eu não participei dessa tarefa porque nesse projeto trabalhei apenas como programador e já existiam os budas do JBoss que fizeram essa tarefa. Lembro-me de ter perguntado como eles fizeram essa clusterização(como se eu fosse entender, mas perguntei :shock: ) e lembro do cara ter me respondido que colocou numa maquina a parte de venda e outra a parte de fechamento de caixa(simplificando as coisas). O sistema era apenas um EAR. Isto parece mais com balanceamento de carga então? Será que ele colocou duas maquinas cada uma com o mesmo EAR e faz o balanceamento de carga entao?

:arrow: Tem como explicar melhor esses conceitos Single System Image,farms, load balancers.

:arrow: Como o JBoss(ou um sistema EJB em geral se não existe diferença entre servidores diferentes) implementa Clustering?? Isso na verdade só funcionaria para SessionBeans?

:arrow: O pagina de pesquisa do Google é o sistema em Clustering mais famoso que existe, que tipo de cluster esses fdp estão falando(essa se você não souber eu perdoo) ?

Vlw :wink:

Rubem_Azenha

louds:

Quanto a trocar de AS, esse teu argumento é brincadeira, nunca vi a migração de qualquer aplicação de media complexidade entre AS diferentes ser menos que um INFERNO. Normalmente já um problema enorme trocar a versão, de fornecedor então…

Olha, o pessoal que migrou de JBoss <-> WebSphere disse q deu um pouco de trabalho, mas não foi tão caótico assim…

urubatan

e o pessoal do TheServerSide roda a aplicação do portal em 4 ou 5 app servers ao mesmo tempo (faz tempo que li, agora não tenho certeza)

louds

Bem lembrado Urubatan. Você chegou a ver algum deles falando do inferno que era? A primeira versão usava o core patterns do começo ao fim, e eles tiveram uma penca de problemas:

:arrow: Não tinha como usar CMP, apenas BMP funciona quando vc tem AS diferentes.
:arrow: Devido a arquitetura da aplicação, eles não implementaram edição de posts.
:arrow: Eles falavam que no geral a aplicação era um inferno de manter rodando.

Mas não vale muito já que ninguém vai fazer isso em produção, não vai, por exemplo, ter WebLogic falando via EJB com OC4J e se ferrar pq um desses dois não tem a mesma semântica em transações distribuidas.

O TSS hoje é feito com Tapestry e JDO, tanto pelos pobres EJBs de antes.

Microfilo, o povo migrou uma aplicação que tinha montes de EJBs que faziam tudo quanto é coisa mirabolante.

Isso me lembra de um projeto que eu quase embarquei em 2004, o povo tava migrando de versão do AS, depois de 2 meses de trabalho ajustando e testando o sistema inteiro, descobriram que um connector simplesmente não funcionava naquela versão que seria usada.

Hempx, lê o livro de Sistemas distribuidos do Tannebaum, lá tem resposta para quase todas as suas perguntas.

A

Clusterização é algo muito comum por aí, até pq os ASs tornam ela muito fácil de ser implementada. O problema é que alguns desenvolvedores enxergam requisitos extraterrenos :shock: na hora de gerenciar transações e partem para soluções independentes… Afinal, que credibilidade têm fornecedores de produtos J2EE como IBM, JBoss e BEA? Eles não sabem nada de Java para mundo corporativo, não eh?

Hempx,

Não precisa ler o livro do Tannebaum para responder de maneira simples suas dúvidas. Mas, se vc quiser detalhes, sempre vale a pena, é claro… :wink:

A clusterização pode tanto ocorrer na camada de dados (recurso do BD) quanto na de processos (recurso do AS). Obviamente, se ela ocorrer nas duas seu sistema pode ser considerado mais tolerante à falhas e mais confiável. Mas tudo tem um custo, e este é o de atualizar as cópias de dados e/ou de processos em seu cluster.

Uma aplicação que contém o componente X em um servidor A e o componente Y em outro servidor B, rodando de maneira independente e separada, só pode ser considerada clusterizada se o AS estiver configurado para transferir a carga de A para B e vice-versa caso um deles caia. A IBM chama isso de nó (node) na plataforma Websphere. Um nó pode ter 1, 2, 3, n máquinas. Dessa maneira a clusterização também resolve o problema do balanceamento de carga (load-balancing). Um Case Study muito comentado pela IBM é o do eBay (um site com 65 milhões de usuários, 18000 categorias de produtos e que realiza 800000 transações por minuto)

“In September 2001, eBay went on a major software revamp to improve its site availability and make it more dynamic and interconnected. After reviewing more than 20 vendors, the company finally opted for IBM and its WebSphere application server and began to put in place its ‘V3’ application architecture. eBay also revamped its server-side application development architecture to support the Java 2 Enterprise Edition (J2EE)[3] and Enterprise JavaBeans[4] The company replaced a C++[5] object framework that required a lot of structural programming. Though the C++ environment was more flexible than Cobol, it couldn’t compete with J2EE, which was becoming the de facto application development framework. J2EE’s objects could handle a much higher level of abstraction than C++. The new applications were more widely distributed, running across multiple machines (both Windows and Solaris) and relied on data-dependent routing, which utilized server cache[6] more efficiently.” (http://icmr.icfai.org/casestudies/ebay%20IT4.htm)

Outras fontes:
http://www-304.ibm.com/jct03001c/services/learning/us/pdfs/onsite/ebaybrief.pdf
http://investor.ebay.com/news/20010906-57994.cfm?ReleaseID=57994&FYear=

eBay powered by J2EE!!! Precisa falar mais alguma coisa?

Luca

Olá

Taz, uma dúvida pois estou um tanto desatualizado com a plataforma Websphere > 4.0. Antigamente a IBM vendia um monte de coisas não JEE para suportar o JEE do Websphere e não sei se isto mudou. No exemplo que você citou bastou comprar o Websphere ou foi necessário HACMP (High Availability Cluster Multiprocessing) e MQseries (para o HACMP)?

[]s
Luca

A

Não conheço esse HACMP. Mas, quanto ao MQ Series, ele foi rebatizado como “Websphere MQ”.

http://www-306.ibm.com/software/integration/wmq/support/

Parece ser uma estratégia de marketing da IBM o agrupamento das soluções para desenvolvimento debaixo do guarda-chuva Websphere.

Luca

Olá

Citei o HACMP porque antigamente a IBM não parecia confiar muito só no Websphere para cluster e preferia sua solução própria (que parece muito boa).

Fazer cluster com o JBoss é brincadeira de criança. Só não sei como se comporta em ambiente de produção exigente. Com o Websphere também era muito fácil. O problema é que o Websphere às vezes (raro mas acontecia) dava uns paus meio do nada. Não sei como andam as versões recentes.

Weblogic nunca usei. Aliás, esta semana ouvi no Theserverside, uma entrevista do Bob Pasker, que é um dos maiores especialistas em transações com mais de 25 anos de experiência. Ele fundou a Weblogic que depois foi vendida a BEA e hoje tem a Azul Systems que vende um clusterzinho de 384 processadores. Vale a pena ouvir. O link está em:
http://www.theserverside.com/talks/index.tss

[]s
Luca

noelrocha

Me falaram e ja li nesse forum quem um erro que muitos cometem é colocar no DAO o gerenciamento de transações …

Nao consigo ver o que existe de errado nisso:

Produto prod = new Produto() ;
prod.setNome("Produto teste") ;
DAOProduto daoProduto = new DAOFactory().getDAOProduto() ;
daoProduto.save(prod) ;
daoProduto.commit() ;

no meu caso, não uso DAOs sigleton e não uso ThreadLocal, cada dao pega uma sessão e faz oq tem q fazer …

Me falaram p/ colocar o controle de transaçoes em outra camada da aplicação …

mas aonde? Algo concreto …

i pq assim não é aconselhavel?

noelrocha

Isso eu entendo …

oq faço, não sei se eh certo, eh colocar algo do tipo no save do meu DAO:

public void save(Entidade e) {
		Transaction tx;
		try {
			tx = this.session.beginTransaction();
			this.session.save(e);
			tx.commit() ;
		} catch (Exception e) {
			tx.rollback();
		}        
	}

é certo isso?

e se eu precisar ter o controle da transação ??

aonde eu colocaria isso?

numa aplicação web, filtros p/ controlar as transações eu concordo e uso quando estou trabalhando com ThreadLocal…

mas e p/ aplicações desktop?

noelrocha

Gostei da ideia de criar um TransactionManager ou algo do tipo porem, quando não uso threadlocal e sim pego uma sessão do pool, como controlo se não dentro do DAO??

Gosto da ideia de ThreadLocal mas acho estranho pois ao meu ver você joga no lixo o pool de conexões (quando se usa um) …

não entendi!!! :?

quando vc der um run() vai disparar a thread certo? logo depois vc da um commit(), mas quem garante que eu terminei a execução da minha thread? desculpem minha ignorancia … hehehe…

Entendi a ideia de tirar o controle do DAO, porem não sei como fazer quando não uso ThreadLocal …

posso criar um TransactionManager que recebe um tipo DAO e uma sessão referente a ele e eu controlo a transação apartir dai … (pensei agora)

pode ser util pois quando eu tiver diversos DAOs e diversas transações, consigo manipula-las em um lugar só …

mas mesmo assim me cheira a gambiarra …

Usando ThreadLocal p/ controlar as transações eh tranquilo …
mas quando não uso ThreadLocal e sim uso uma sessão (vinda do pool) p/ cada DAO?

noelrocha

louds:
noel,

ThreadLocal não elimina o uso de pool, apenas elimina o passa-passa de objetos entre os varios layers da aplicação. Com TL, eu faço +/- assim:

try {
  threadLocal.put(pool.getConnection());
} finaly{
 ((Connection)threadLocal.get()).close();
  threadLocal.put(null);
}

Quanto a Runnable, você tá confundindo a interface Runnable com a classe Thread. Usar a interface não implica em criar threads.

Veja que se você usa uma conecção por DAO, tuas operações não são transacionais, afinal todos precisam todas usar a mesma conecção.

Com relação ao Runnable me abstenho tamanha a minha ignorancia …

e com relação a ThreadLocal, tudo resolvido, entendi … hehehe …

DAO e Transações não da certo, estou convencido … hehehe …

mas ficou uma duvida sobre ThreadLocal …

qualquer um pode pegar a sessão q eu coloquei na ThreadLocal?

Criado 17 de julho de 2005
Ultima resposta 18 de jul. de 2005
Respostas 54
Participantes 12