LOG no banco

Oi galera,

Preciso criar um LOG no banco de dados. Nesse log preciso cadastrar o usuário (da aplicação) que alterou a informação. Contudo minha aplicação utiliza pool de conexão e o usuário é interno do sistema e não ao banco.
Criar uma classe para registrar cada alteração em cada coluna, registrando valor antes e depois da alteração faria a aplicação ficar muito lento (acredito eu) pois qualquer 1s de diferença na peformance da aplicação e notada.
O ideal seria usar trigger, mas como vou fazer a trigger pegar o usuário que está alterando? Alguma sugestão? Ideias ou arquiteturas?
Hoje uso jsp acessando servlets que acessa session que podem ir ou não para os CMPs ou BMPs.
Em resumo, qual a melhor maneira de fazer um log de aplicação no banco, o qual informa o usuário do sistema que alterou a informação?

Bem, se você executa suas queries dentro de transações ou batchs, adicionar um insertizinho de nada não iria prejudicar aumentar o tempo em um custo segundo.

Mas mesmo assim não é tarefa fácil a se fazer do jeito correto (leia: sem inserir a linha de código em todos os métodos que alteram o banco). A não ser que esteja usando Hibernate.

Oi LIPE,

Antes quero agradecer pela resposta.
Não uso Hibernante. Gostaria de fazer por trigger (Oracle) pois preciso do valor anterior e posterior e fazer isso na aplicação geraria muitas mudanças no código.
A principio pensei em usar uma tabela temporaria, mas ainda usamos oracle 8 e não existe esse recurso. Nessa tabela gravaria o login do usuário que está alterando a informação e depois a trigger pegaria dessa tabela. :shock: Como não existe tabela temporaria pensei em uma variavel de packge, e a trigger pegaria dessa vairavel. Será que funcionaria?
A questão com essa solução seria como gravar o usuário que está usando o EJB Stataless? O create não aceita parametro, então teria que setar essa variavel depois de cada create()… imagina a o trabalho!!!
To querendo trocar ideias e soluções… por isso qualquer ajuda e bem vinda… e o pior disso e que o prazo para implementar isso está passando!!!

Abraços

pq vc nao cria/atualiza o campo “usuario” da tabela junto com as demais colunas ? seria mais simples do que esses esquemas de tabelas auxiliares, trigger, etc…

só que vc teria que alterar todas as queries das tabelas que vc precisa logar o usuario, e acrescentar a coluna usuario.

Carbald, entendi o seu problema perfeitamente, pois precisamos implementar quase isso no sistema atual.

Sobre o EJB Stateless, bem, se você não consegue pegar o Usuario que está fazendo a requisição quando bem entender, alguma coisa está errada na sua arquitetura. Tem certeza que nem via session consegue fazer isso?

Fica difícil de sugerir uma solução boa pois não sabemos como que está fazendo o controle de transações e/ou batchs.

Se você instancia seus DAOs dentro de um contexto transacional, pode fazer algo semelhante a um interceptor, ou usando AOP. Desta maneira, seria realmente muito simples inserir mais uma query (a que faz o insert) na transação antes de sofrer o commit.

Mas, já que o prazo está chegando, aconselho a fazer do jeito que der, mesmo que seja macarrônico hehe

Oi Lipe e Ricardo,

Ricardo… o motivo de querer usar trigger é que preciso armazenar o valor new e old. Se for fazer por aplicação teria que fazer uma query antes de atualizar os valores só para armazenar o LOG.
Exemplo disso: updateEmpresa(Empresa). O JavaBean Empresa teria só as informações que devem ser alteradas, as que estão no banco eu deveria pegar (isso se o metodo nao usar CMP).
No caso do CMP podeira gravar o old e new em cada set.

Lipe,

Vc comentou sobre pegar o usuario no EJB quando quiser. Como seria a arquitetura correto para fazer isso. Eu tenho o usuário logado em sessão para servlet. Para o session receber o usuario logado não teria que ser por parametro? Ou tem outra maneira?
To aceitando sugestões por que se poder implementar algo que melhore a arquitetura ficaria muito feliz tmb.
Quem faz o controle da transação e o container. Não existe commit na aplicação.

Mais uma vez obrigado as resposta dos dois.

Bem, se você guarda o usuário na sessão com o servlet, então pode sim pegar o valor dele quando bem entender :smiley:

Te pergunto uma coisa: todos os seus métodos de Update tem um formato padrão? Só assim penso que seria possível automatizar a coisa toda, pois poderia pegar o valor velho e o novo sem problemas.

Usando AOP (o que não manjo quase nada), poderia interceptar, por exemplo, todos os métodos que possuem a palavra “update”, contidos em classes que contém a palavra “DAO”. Então por reflection conseguiria pegar todas os nomes das propriedades e salvar na tabela de log.

public class ReflectionTest
{
	public static void main( String[] args )
	{
		new ReflectionTest();
	}

	public ReflectionTest()
	{
		Pessoa velha = new Pessoa();
		velha.setNome( "lipe" );
		velha.setCep( "04111001" );

		Pessoa nova = new Pessoa();
		nova.setNome( "lipe" );
		nova.setCep( "04222002" );
		
		update( velha, nova );
	}

	public void update( Object velho, Object novo )
	{
		Map changeds = new HashMap();
		
		try
		{
			Class clazz = velho.getClass();
			Method[] methods = clazz.getDeclaredMethods();
			Field[] fields = clazz.getDeclaredFields();

			for( int i = 0; i < fields.length; i++ )
			{
				String fieldName = fields[ i ].getName();
				
				Method method = clazz.getMethod( "get" + getFirstUpper( fieldName ), null );
				Object oldFieldValue = method.invoke( velho, null );
				Object newFieldValue = method.invoke( novo, null );
				
				if( !oldFieldValue.equals( newFieldValue ) )
					changeds.put( fieldName, new Object[] { oldFieldValue, newFieldValue } );
			}
		}
		catch( Exception e )
		{
			e.printStackTrace();
		}
		
		for( Iterator iter = changeds.keySet().iterator(); iter.hasNext(); )
		{
			String key = ( String ) iter.next();
			Object[] values = ( Object[] ) changeds.get( key );
			System.out.println( "propriedade: " + key + ", oldValue: " + values[ 0 ] + ", newValue: " + values[ 1 ] );					
		}
	}
	
	private String getFirstUpper( String s )
	{
		return s.substring( 0, 1 ).toUpperCase().concat( s.substring( 1 ) );
	}
}

class Pessoa
{
	private String nome;
	private String cep;

	public String getCep()
	{
		return cep;
	}

	public String getNome()
	{
		return nome;
	}

	public void setCep( String cep )
	{
		this.cep = cep;
	}

	public void setNome( String nome )
	{
		this.nome = nome;
	}
}

Desta maneira você consegue saber quais são as propriedades que sofreram modificação. Ali no laço que itera pelo mapa entraria o código para inserir as linhas na tabela de Log, bem como pegar o nome do usuário que está na sessão.