Interceptando comandos SQL gerados pelo EntityManager em um ambiente Java EE

246 views
Skip to first unread message

ishiuaua

unread,
Jul 22, 2009, 7:01:18 AM7/22/09
to JUG-MS
Olá a todos,

sou muito novo em programação Java EE e estou começando a aprender,
primeiramente, Jsp, servlets e EJBs.

Mais especificamente, tenho um problema na parte de persistência.
Realizo a persistência utilizando JPA (mas acho que aqui poderia ser o
Hibernate também! Me corrijam se estiver errado). O problema é que eu
devo ser capaz de capturar um comando SQL logo antes de ele ser
executado e enviá-lo para um outro processo em um outro computador.

Preciso apenas da solução para a primeira parte - antes de um comando
SQL ser executado, é necessário obtê-lo. (estou utilizando a classe
EntitiManager para acessar uma base de dados que está especificada
como uma persistence-unit em persistence.xml).

O mais perto que cheguei, foi criar um interceptor para interceptar
PreparedStatements:

public class MyInterceptor extends org.hibernate.EmptyInterceptor {
@Override
public String onPrepareStatement(String sql) {
System.out.println("Executando o sql: " + sql); //apenas teste para
ver se tá interceptando...
return sql;
}


Isto realmente funcionou, mas, infelizmente, a string sql que vem como
parâmetro para este método do interceptor é uma sql que representa um
prepared statement... Exemplificando, o interceptor imprime algo deste
tipo:
[STDOUT] Executando o sql: insert into Usuario (nome, login) values
(?, ?)

O que deveria ocorrer seria substituir os '?' por dados reais... e
este método parece ser chamado ao realizar o PreparedStatement, não
antes de realmente executar a query no banco de dados...




Tentei criar uma proxy dinâmica que envolvia a interface Entity
Manager, de modo que cada método de consulta era interceptado por um
outro interceptador (que derivava de MethodInterceptor, cglib), mas
creio que essa solução não é muito boa, pois se o acesso acontecer
fora do EntityManager, não haverá essa interceptação (até com objetos
gerenciados por um EntityManager interceptado não deu certo!).



Tentei também utilizar o p6spy, mas não obtive muito sucesso...


Alguém já mexeu mais ou menos com isso e pode dar um caminho?? Acho
que o p6spy pode resolver o problema, vou procurar googlear mais, mas
aparentemente parece um projeto meio descontinuado, onde a
documentação oficial explica a configuração de p6spy para o JBoss 2.x
e 3.x e parece não funcionar para versões mais recentes que esta...

João Guilherme

unread,
Jul 22, 2009, 9:22:22 AM7/22/09
to jug...@googlegroups.com
Bom, a não ser que você precise desses interceptors, eu recomendo você a usar a saída do hibernate, persistence.xml: <property name="hibernate.show_sql" value="true"/>

Vai continuar a imprimir os (?, ?) por que até onde eu sei, isso realmente não dá pra ver, pois o PrepareStatement não possui os valores, que serão setados depois.

Sobre o JPA, você pode usar ele com o Hibernate ou o Toplink, é como uma camada a mais, pesquisa sobre Provedor de Persistencia.



2009/7/22 ishiuaua <ishi...@gmail.com>



--
João Guilherme
Analista Desenvolvedor Java - SCJP 1.5


Douglas Piva

unread,
Jul 22, 2009, 2:03:52 PM7/22/09
to jug...@googlegroups.com
Vc, deseja capturar o sql para alterar o mesmo antes de enviar para o banco....?

Se for só pra verificar o comando sql , no MS SQL Server vc pode utilizar o profiler,
o mesmo mostra o comando a ser executado seguido pelos valores dos parametros.

Douglas

Leandro Ishi

unread,
Jul 23, 2009, 2:09:12 AM7/23/09
to jug...@googlegroups.com
Olá João Guilherme,

já ativei o logging de comandos sql do hibernate utilizando exatamente isso:

<property name="hibernate.show_sql" value="true"/>

mas realmente não fornece a saída exata


2009/7/22 João Guilherme <jgba...@gmail.com>

Leandro Ishi

unread,
Jul 23, 2009, 2:12:06 AM7/23/09
to jug...@googlegroups.com
Na verdade, desejo capturar o sql, e, ao invés de mandar apenas para o banco, enviar para uma lista de bancos especificada em algum arquivo (podendo ser de fornecedores diferentes)... mas fazer isso de forma mais transparente possível, sem fazer com que o cliente tenha que alterar seu código para ativar essa funcionalidade...

2009/7/22 Douglas Piva <dou...@gmail.com>

João Guilherme

unread,
Jul 23, 2009, 9:06:25 AM7/23/09
to jug...@googlegroups.com
Realmente ele não mostra todo o SQL as interrogações ainda aparecem. Se vc quer armasenar as operações de banco, usa o LOG4J, mas se você quer replicar o banco, via aplicação não é muito recomendado. A maioria dos bancos mais robustos tem ferramentas próprias para replicação.

É isso ou entendi errado seu problema?

2009/7/23 Leandro Ishi <ishi...@gmail.com>

Castilho

unread,
Jul 23, 2009, 10:39:26 AM7/23/09
to jug...@googlegroups.com
Pq vc precisa enviar os SQLs para outro(s) bancos? É para replicar dados? 

2009/7/23 João Guilherme <jgba...@gmail.com>



--
Att,
Castilho
(67) 8125-5445
http://www.bacarin.com.br

Leandro Ishi

unread,
Jul 23, 2009, 2:12:01 PM7/23/09
to jug...@googlegroups.com
Sim, é para replicar o banco, mas de uma forma que não exija que o banco em questão tenha essa robustez de replicação e possibilitar a replicação com bancos de fornecedores diferentes....

2009/7/23 João Guilherme <jgba...@gmail.com>

Leandro Ishi

unread,
Jul 23, 2009, 2:13:11 PM7/23/09
to jug...@googlegroups.com
Sim... mas creio que uma ferramente para replicação de bancos nesse nível tem que ser muito robusta para ser aplicada comercialmente... a que tenho que desenvolver não precisa ser tanto, eu acho... é para fins acadêmicos...

2009/7/23 Castilho <cast...@bacarin.com.br>

Leandro Ishi

unread,
Jul 23, 2009, 2:17:49 PM7/23/09
to jug...@googlegroups.com
Só uma dúvida, o LOG4J no caso logaria os comandos SQL específicos do JPA ou do HIBERNATE?? Se tiver uma aplicação que utiliza nenhum framework de persistência (utiliza JDBC mesmo) como esses ou outros frameworks? Ele ainda loga?

2009/7/23 Leandro Ishi <ishi...@gmail.com>

Humberto Pereira

unread,
Jul 23, 2009, 2:49:41 PM7/23/09
to jug...@googlegroups.com
Eu nao sei como funciona o JPA internamente, mas acredito que voce
tenha que trabalhar diretamente com o driver JDBC p/ conseguir isso.
Com qualquer um dos 2 dificilmente voce vai conseguir ter uma query
limpa ("insert into Usuario (nome, login) values ('blah', 'blah')"),
pq uma Prepared Statement costuma ser criada diretamente no servidor
pelo JDBC.

Entao, pra resolver isso, vc tem que criar um driver JDBC que
sobrescreva o Statement e o PreparedStatement inteiro e vc mesmo
montar a query no execute*();

2009/7/23 Castilho <cast...@bacarin.com.br>:

Leandro Ishi

unread,
Jul 23, 2009, 3:36:26 PM7/23/09
to jug...@googlegroups.com
Sim!!!.. também penso da mesma maneira... já estou fazendo isso... mas na verdade, eu não faço um driver JDBC, mas estou tentando modificar as classes Statement e PreparedStatement de um fornecedor de um driver JDBC utilizando o JavaAssist e interceptadores com o cglib...

Basicamente, minha idéia é antes de o Statement ou o PreparedStatement executar um comando SQL, eu posso capturá-lo. Tento fazer isso interceptando os métodos execute(), executeUpdate() e executeQuery() dessas duas classes... alguém sabe mais ou menos se são esses métodos mesmo que realmente devo interceptar??... se qualquer comando SQL que pode ser gerado (inclusive comandos que modificam a definição do banco de dados (create, drop, etc)) é passado para o banco de dados por algum desses métodos? Eu acho que sim... mas isso é apenas uma suposição... nada muito concreto...

Já realizei alguns testes e parece que o caminho é por aí mesmo... mas como eu não tenho acesso nem ao fonte da classe Driver do fornecedor e nem as partes do código de um framework que utiliza o JDBC (por ex., hibernate), estou tendo que utilizar JavaAssist para modificar o .class do Driver do fornecedor para implementar essa funcionalidade de forma transparente (apesar do hibernate ser um projeto open-source, seria legal modifica no .class do Driver do fornecedor, assim, qqr aplicação que utilizar este driver seja com hibernate, jpa, jdbc, já estará com essa funcionalidade acoplada). Ainda estou com problema nessa parte (Java Assist), mas se alguém puder confirmar que é por aí mesmo que eu devo mexer, já está muito bom... Ou existe uma outra maneira melhor para interceptar os métodos das classes do fornecedor?

2009/7/23 Humberto Pereira <beg...@gmail.com>

Leandro Ishi

unread,
Jul 23, 2009, 3:52:13 PM7/23/09
to jug...@googlegroups.com
ahh.. a propósito, alguém sabe algum lugar que dá pra baixar o java assist?... na página oficial, http://www.csg.is.titech.ac.jp/~chiba/javassist/, o link para download para o sourceforge não existe mais... e eu procurei um pouco no google e muitas páginas apontam para esse link no sourceforge... achei um .jar do javaassist em uma outra página, mas parece que é uma versão anterior...

é impressão minha ou esse projeto tá descontinuado? =/

2009/7/23 Leandro Ishi <ishi...@gmail.com>

Humberto Pereira

unread,
Jul 23, 2009, 3:53:27 PM7/23/09
to jug...@googlegroups.com
O ideal nao seria mudar o driver JDBC e sim encapsular ele (acho que o
nome do design pattern eh Proxy). Vc insere via POA uma modificacao no
java.sql.DriverManager p/ que te retorne uma conexao sua
sobreescrevendo o metodo getConnection().

A sua conexao por sua vez vai ter que servir PreparedStatement's e
Statement's proprios seus, que encapsulam os statements do driver,
entao voce loga primeiro e chama o driver depois. Assim vc cria uma
camada entre o driver JDBC real e a aplicacao alterando apenas uma
funcao da aplicacao real. Ae eh soh logar todos os metodos e pronto.

Eu acredito que tenha solucoes melhores p/ isso mas pra usar como
prova de conceito, eh o suficiente.

2009/7/23 Leandro Ishi <ishi...@gmail.com>:

Leandro Ishi

unread,
Jul 23, 2009, 4:12:32 PM7/23/09
to jug...@googlegroups.com
Sim, eu uso proxies para as classes Connection, Statement e PreparedStatement... mas, para fazer isso eu tenho que fazer com que o Driver do fornecedor retorne uma conexão "proxiada" no método connect() do Driver... essa conexão proxiada apenas pega os SQLs antes de realizá-los e depois invoca o método real...

Posso tentar modifica a java.sql.DriverManager, mas modificando a classe Driver do fornecedor não seria melhor? No meu teste, eu estava trabalhando com o JDBC do MySQL, então, eu teria que modificar a classe com.mysql.jdbc.Driver. Essa classe implementa java.sql.Driver e, logo, tem o seguinte método que devo modificar:
  Connection connect(String url, Properties info)

O que eu faço com o JavaAssist é renomear esse método para privateConnect e criar um novo método connect idêntico, ficando assim:

  Connection connect(String url, Properties info) //meu método
  Connection privateConnect(String url, Properties info) //método do fornecedor do Driver


O método connect que eu defino apenas chama o privateConnect e encapsula a conexão (Connection) retornada em um proxy. Esse proxy para Connection apenas encapsula os Statement e PreparedStatement quando a aplicação requisitar (por meio dos métodos createStatement() e prepareStatement() da classe Connection). E, por fim, as proxies para Statement e PreparedStatement pegam a string SQL antes de ela ser executada...


Por enquanto está dando problema quando utilizo o Javassist... mas isso dá para resolver...


O empecilho aqui está sendo modificar esse método connect do Driver... está dando erro em tempo de execução... mas isso vai ser consertado... é que não sei muito bem usar o javassist...

De qualquer maneira, vc disse: "Vc insere via POA uma modificacao no java.sql.DriverManager p/ que te retorne uma conexao sua  sobreescrevendo o metodo getConnection()". Posso inserir via POA uma modificação em com.mysql.jdbc.Driver, retornando uma conexao minha que sobreescreva o método connect()??... inserir essa modificação via POA é melhor do que editar o .class da classe via javassist??

Obrigado!




2009/7/23 Humberto Pereira <beg...@gmail.com>

Humberto Pereira

unread,
Jul 23, 2009, 8:09:25 PM7/23/09
to jug...@googlegroups.com
2009/7/23 Leandro Ishi <ishi...@gmail.com>:

> Sim, eu uso proxies para as classes Connection, Statement e
> PreparedStatement... mas, para fazer isso eu tenho que fazer com que o
> Driver do fornecedor retorne uma conexão "proxiada" no método connect() do
> Driver... essa conexão proxiada apenas pega os SQLs antes de realizá-los e
> depois invoca o método real...

Sim, a conexao proxiada vai pegar os SQL no formato da
PreparedStatement (com ? no lugar dos valores). Eh bem provavel que em
nenhum momento o driver JDBC mande para o servidor ou monte a SQL do
formato que a gente monta (substituindo ? pelos valores), pq a
prepared statement, por motivos de performance eh gerada e guardada no
servidor e o usuario apenas seta os parametros (valores) p/ ela, algo
parecido com uma chamada de funcao. Voce pode ver um ex. de prepared
statement no MySQL no manual
(http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-prepared-statements.html).

Resumindo, voce quem deve parsear a SQL e substituir os ? por valores
e imprimir depois. Nao eh nda complicado, se voce procurar o codigo da
PreparedStatement do MySQL p/ versoes antigas (que nao suportavam
prepared statement no servidor ainda) voce vai ver como eles faziam e
pode copiar o codigo deles.

> Posso tentar modifica a java.sql.DriverManager, mas modificando a classe
> Driver do fornecedor não seria melhor? No meu teste, eu estava trabalhando
> com o JDBC do MySQL, então, eu teria que modificar a classe
> com.mysql.jdbc.Driver. Essa classe implementa java.sql.Driver e, logo, tem o
> seguinte método que devo modificar:
>   Connection connect(String url, Properties info)

Veja bem, o grande problema de trabalhar diretamente com o driver JDBC
eh pq vc vai ter que ter que lidar com as particularidades de cada
implementacao para cada driver para cada versao do JDBC (ufa). E a
interface com o JDBC eh bem definida e documentada, jah a dos drivers
eh, digamos, mais criptica.

> O que eu faço com o JavaAssist é renomear esse método para privateConnect e
> criar um novo método connect idêntico, ficando assim:
>
>   Connection connect(String url, Properties info) //meu método
>   Connection privateConnect(String url, Properties info) //método do
> fornecedor do Driver
>
>
> O método connect que eu defino apenas chama o privateConnect e encapsula a
> conexão (Connection) retornada em um proxy. Esse proxy para Connection
> apenas encapsula os Statement e PreparedStatement quando a aplicação
> requisitar (por meio dos métodos createStatement() e prepareStatement() da
> classe Connection). E, por fim, as proxies para Statement e
> PreparedStatement pegam a string SQL antes de ela ser executada...

Eh exatamente essa a ideia, esse o melhor caminho a ser seguido.

> O empecilho aqui está sendo modificar esse método connect do Driver... está
> dando erro em tempo de execução... mas isso vai ser consertado... é que não
> sei muito bem usar o javassist...
>
> De qualquer maneira, vc disse: "Vc insere via POA uma modificacao no
> java.sql.DriverManager p/ que te retorne uma conexao sua  sobreescrevendo o
> metodo getConnection()". Posso inserir via POA uma modificação em
> com.mysql.jdbc.Driver, retornando uma conexao minha que sobreescreva o
> método connect()??... inserir essa modificação via POA é melhor do que
> editar o .class da classe via javassist??

Vc jah tah usando POA com JavaAssistant, eu que nao conhecia ele. Qto
a dificuldade, eu nao conheco JavaAssistant, mas jah mexi com bcel da
apache (http://jakarta.apache.org/bcel/) e ele eh bem facil de usar.

Leandro Ishi

unread,
Jul 24, 2009, 2:45:42 AM7/24/09
to jug...@googlegroups.com

Sim, a conexao proxiada vai pegar os SQL no formato da
PreparedStatement (com ? no lugar dos valores). Eh bem provavel que em
nenhum momento o driver JDBC mande para o servidor ou monte a SQL do
formato que a gente monta (substituindo ? pelos valores), pq a
prepared statement, por motivos de performance eh gerada e guardada no
servidor e o usuario apenas seta os parametros (valores) p/ ela, algo
parecido com uma chamada de funcao. Voce pode ver um ex. de prepared
statement no MySQL no manual
(http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-prepared-statements.html).

Também tenho essa idéa sobre a PreparedStatement, mas eu n sei porque uma vez testei imprimir uma Prepared Statement quando interceptei algum de seus métodos que mandam comando para o banco de dados (método que começam com "execute" que eu interceptei, na verdade)... o que é impresso qdo vc imprime um PreparedStatement dessa forma tem duas partes: a primeira é aquele treco estranho que o método toString() de Object imprime (o nome da classe @ posição de memória ... algo assim) e, depois, imprime a string SQL que corresponde ao Prepared Statement com os valores já bindados, ou seja, sem '?' e com os valores de verdade... programaticamente fica mais fácil rsrs:

if (method.getName().startsWith("execute")) {
           
            if (statement instanceof PreparedStatement) { //o statement que estou interceptando é um PreparedStatement
                String str = statement.toString(); //pego a "impressão" do PreparedStatement
                int pos = str.indexOf(' '); //str é +- assim: Object.toString(): SQL. Pego o primeiro ' ' pois é o caractere exato antes da string SQL e não haverá outro ' ' antes desse primeiro ' '
                System.out.println(str.substring(pos+1)); //imprime a string SQL
            }
            else { //supomos que o statement é um Statement
                System.out.println(args[0]); //imprime o primeiro argumento, que sempre é uma string SQL
            }
        }


O engraçado é que isso funcionou... e ainda funcionou com o JPA em um projetinho web que tenho aqui... apenas substitui o driver MySQL que o servidor JBoss usava pelo driver criado com conexões proxiadas...
Também achei que teria que fazer o bind dos valores do PreparedStatement na mão, mas o toString() resolveu aqui rsrs (e pelo pouco que pesquisei, não consegui fazer isso de outra maneira!)...
Contudo, precisa de muito mais testes... o projetinho web aqui apenas cria tabelas para as Entitys, se elas não existem (comando SQL create table também é interceptado e logado) e faz uns selects, inserts e deletes básicos...







Veja bem, o grande problema de trabalhar diretamente com o driver JDBC
eh pq vc vai ter que ter que lidar com as particularidades de cada
implementacao para cada driver para cada versao do JDBC (ufa). E a
interface com o JDBC eh bem definida e documentada, jah a dos drivers
eh, digamos, mais criptica.
 
Sim... tentei implementar algo em cima da interface com o JDBC e não da implementação do JDBC que com certeza é muito mais criptica já que o fornecedor pode ter implementado o driver como ele quiser... Falta fazer testes também com outros fornecedores.





Talvez essa também não tenha sido a melhor abordagem pra solucionar o problema mas já deu pra fazer um início da solução... obrigado pelas orientações

 
2009/7/23 Humberto Pereira <beg...@gmail.com>

Rodrigo G. M. Catto

unread,
Jul 24, 2009, 9:21:25 AM7/24/09
to jug...@googlegroups.com
Bom dia, Leandro Ishi!

Tenta esse link aqui...

http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/j/jb/jboss/javassist-3.11.GA.zip

Atenciosamente,
Rodrigo G. M. Catto [Iskigow]

2009/7/23 Leandro Ishi <ishi...@gmail.com>

--
Frase aleatória do e-mail:
Mike Ditka  - "If God had wanted man to play soccer, he wouldn't have given us arms."

Rodrigo G. M. Catto

unread,
Jul 24, 2009, 9:23:40 AM7/24/09
to jug...@googlegroups.com
Só completando...
neste link:
http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/j/jb/jboss/[page=0]

tem outras versões do Javassist também.

Abraços,

Rodrigo G. M. Catto [Iskigow]

2009/7/24 Rodrigo G. M. Catto <isk...@gmail.com>
Pablo Picasso  - "Computers are useless. They can only give you answers."

Paulo Vieira Milreu

unread,
Jul 24, 2009, 12:03:28 PM7/24/09
to jug...@googlegroups.com
Olá a todos,


Veja bem, o grande problema de trabalhar diretamente com o driver JDBC
eh pq vc vai ter que ter que lidar com as particularidades de cada
implementacao para cada driver para cada versao do JDBC (ufa). E a
interface com o JDBC eh bem definida e documentada, jah a dos drivers
eh, digamos, mais criptica.

Aproveitando o parágrafo acima, que aponta muito bem algumas dificuldades técnicas que o Ishi deverá encontrar rumo à empreitada dele, vou aproveitar para dar uns pitacos sobre outros pontos, também técnicos, mas não relacionados à obtenção do SQL em si.

Ou seja, supondo que vc conseguiu obter satisfatoriamente os SQLs gerados pela sua aplicação e tratá-los satisfatoriamente para enviar para serem aplicados em outros bancos, capturando apenas as instruções que alterem dados e ignorando consultas (SELECTs), já que o propósito é de replicação e mesmo que isso te obrigue a eventualmente alterar essa sintaxe para adequá-la a esses outros SGBDs. Enfim, suponha que esse passo já foi vencido.

Ainda assim, você terá uma montanha de trabalho após isso, para garantir que sua replicação entregará a funcionalidade esperada. Pense nos tratamentos de exceções: e se, na hora, vc não conseguir conectar ao outro banco para aplicar seu script? E se, quando aplicar, ele falhar? O que fazer com os comandos seguintes até que aquele seja aplicado (em geral, replicações exigem que as instruções sejam executadas sequencialmente, de acordo com a ordem que são executadas no servidor primário, para garantir a consistëncia dos dados).

Provavelmente, vc terá que criar um sub-sistema de replicação, que tem como uma das partes essa obtenção do comando (SQL) válido para cada servidor replicado e outras partes sendo o gerenciamento da fila de comandos e seus status (falha;sucesso), os tratamentos de exceção em caso de falha, o controle da versão dos dados, etc.

Em geral, as aplicações de hoje em dia subutilizam recursos nativos de bancos, como triggers e procedures. Mas, se não for esse o caso de suas aplicações, o que fazer quando uma alteração na base principal acionar triggers que modificam dados? Garantir que também esse meta-dado esteja identico em todos os demais bancos, mesmo sendo talvez outros SGBDs? Ou chamadas a procedures do banco que também alteram dados. Será que também deveriam ser monitoradas.

Enfim, o meu propósito aqui é só levantar esses questionamentos sem qualquer intenção que não a de alertar que o que me parece que vc está procurando fazer é um trabalho considerável e que exigirá um esforço também considerável para que seja estável e confiável. Se se tratar de um projeto com fins de estudo ou até um projeto open-source para a comunidade de desenvolvedores, muito legal e parabéns pela iniciativa. Se tratar-se de um sistema comercial, com prazos apertados e comprometimento com resultados confiáveis, acredito que você possa ter problemas e/ou prejuízos, dependendo de como foi esse acerto comercial com seu cliente.

Para finalizar, o recado seria: sempre que deixamos de utilizar recursos existentes (ex: SGBDs e o seu recurso nativo de replicação, mapeamento objeto relacional, etc.) para resolver um problema "no braço", temos que estar muito seguros de que essa é a ÚNICA estratégia para atender nossos objetivos, pois fora isso, ela não será a melhor estratégia.

Abraços,

Paulo V. Milreu

Leandro Ishi

unread,
Jul 24, 2009, 5:42:32 PM7/24/09
to jug...@googlegroups.com
cara... não consegui baixar... eu aperto em Download Zip File mas n acontece nada... e ah... logo abaixo desse botão para fazer o download tá escrito "Sorry, there is a problem accessing this item. It may not exist."... talvez este link também esteja quebrado, como o oficial do sourceforge...

2009/7/24 Rodrigo G. M. Catto <isk...@gmail.com>
Bom dia, Leandro Ishi!

Leandro Ishi

unread,
Jul 24, 2009, 6:01:32 PM7/24/09
to jug...@googlegroups.com
Olá Paulo,

Esta solução que estou desenvolvendo é para fins acadêmicos sim... no entanto, a idéia é legal - fazer uma replicação de banco de dados independente do fornecedor do banco de dados, não importando se este fornecedor implementa ou não essa funcionalidade de replicação, além de que a replicação não exige que as bases de dados sejam as mesmas ou do mesmo fornecedor. Contudo, para concretizar isso para um sistema comercial funcional deve requerer muito, mas muito trabalho mesmo... deve ser um projeto bem grande rsrs... concordo plenamente.

Na verdade, o projeto que devo fazer é tolerar falhas em um sistema por replicação ativa. O algoritmo que implementarei é um algoritmo de ordem total, que assegura que todas as réplicas recebam a mesma seqüência de entrada... neste caso em particular, não importa qual réplica do banco de dados realizou um comando SQL, todas elas receberam a mesma sequência de comandos  e executaria a mesma sequência, mantendo a consistência entre as réplicas (como se nós pegássemos todos os comandos SQL gerados por todas as réplicas, ordenasse e mandava de volta para as réplicas e daí sim elas executariam todos os comandos na mesma ordem - tá certo que é mais complexo que isso.. tem algumas peculariedades... algumas réplicas podem quebrar mas o serviço ainda continuará disponível, etc... mas isso não vem muito ao caso...).

Mas o foco mesmo é a implementação desse algoritmo de ordenação total, estou utilizando esse exemplo de capturar os SQLs apenas como uma aplicação exemplo da implementação do algoritmo... mas se fosse realizar isso comercialmente, o ideal mesmo seria utilizar um sgbd que implementa a replicação de dados de forma nativa...
É só para reforçar que por enquanto é apenas para fins acadêmicos mesmo e sigo o que vc disse nesse parágrafo como um mandamento:


Para finalizar, o recado seria: sempre que deixamos de utilizar recursos existentes (ex: SGBDs e o seu recurso nativo de replicação, mapeamento objeto relacional, etc.) para resolver um problema "no braço", temos que estar muito seguros de que essa é a ÚNICA estratégia para atender nossos objetivos, pois fora isso, ela não será a melhor estratégia.


Abraços


 
2009/7/24 Paulo Vieira Milreu <paulo...@milreu.com.br>

Thiago Moretto

unread,
Jul 24, 2009, 7:49:38 PM7/24/09
to jug...@googlegroups.com
Eu sei que é pra fins academicos, mas existe o Sequoia:

http://www.continuent.com/community/lab-projects/sequoia

Voce pode pegar algumas ideias. Pode ver o codigo-fonte e ter base.

Mas JDBC é Spec, é API, voce pode implementar um driver JDBC, nao todo
ele claro, e voce delega para um driver de verdade. A aplicacao usa
sua implementacao, la dentro voce tem os parametros e o comando SQL.
Acredito que uma solucao nesse sentido seria mais eficiente, e se nao
me engano, o sequoia é assim.


2009/7/24 Leandro Ishi <ishi...@gmail.com>:

Leandro Ishi

unread,
Jul 24, 2009, 8:06:03 PM7/24/09
to jug...@googlegroups.com
Olá Thiago...

pensei em criar um driver JDBC apenas para delegar chamadas aos drivers JDBC de verdade dos fornecedores, mas não sei.. achei que daria muito trabalho...

O que eu faço é mudar o .class do Driver do fornecedor (por exemplo, para o driver JDBC do mysql, a classe Driver é a classe com.mysql.jdbc.Driver... e então, eu modifico o método connect() dessa classe apenas para empacotar a conexão retornada pelo connect() original em uma proxy minha que captura os SQLs gerados). É mais fácil por aqui:

//método original
Connection connect (...) { ... }


//novo método
Connection connect (...) {
    return new ConnectionDynamicProxy ( connectOriginal (...));
}


Não é exatamante assim, uso cglib e etc... mas a idéia é essa... apenas encapsula a Connection que o Driver do fornecedor gera em uma proxy e essa proxy então vai conseguir registrar os SQLs...

Vou por esse caminho, caso não dê certo, provavelmente a criação de um driver JDBC que delega aos drivers JDBC verdadeiros será uma boa solução...


O Sequoia apresentado parece ser muito bom e aparentemente parece implementa bem o que eu tava querendo fazer =/... Valeu por apresentá-lo... qqr coisa dá pra recorrer a ele... mas a idéia é mais para estudo acadêmico e para a facilidade de fazer uma replicação... basicamente, substitua a classe Driver do fornecedor JDBC em seu .jar pela mesma classe Driver mas proxiada e inicie um processo que irá escutar e executar comandos SQLs enviados pelas proxies... então está bem longe de ser algo complexo e que pode ser aplicado comercialmente como o Sequoia...






2009/7/24 Thiago Moretto <thiago....@gmail.com>

Rodrigo G. M. Catto

unread,
Jul 25, 2009, 3:35:45 PM7/25/09
to jug...@googlegroups.com
Pois é eu vi... eles estão mundano a estrutura desse site o tempo inteiro...

Agora você baixa o arquivo no link:

http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/j/project/jb/jboss/javassist-3.11.GA.zip

Mas acho que não por muito tempo... Então vou mandar um email direto pra você com o arquivo em anexo.

[]'s

2009/7/24 Leandro Ishi <ishi...@gmail.com>
Stephen Leacock  - "I detest life-insurance agents: they always argue that I shall some day die, which is not so."
Reply all
Reply to author
Forward
0 new messages