Aplicação Embedded Server

Para a api do db4o não existe diferença entre transações executando de forma concorrente na mesma JVM ou transações executadas em um servidor remoto. Para executar transações concorrentes em uma mesma JVM (conceito de Embedded) você deverá abrir o seu banco diretamente na porta 0, para identificar que não será necessário utilizar a rede. Exemplo:

 
package br.com.tutorial;

import com.db4o.Db4o;

import com.db4o.ObjectContainer;

import com.db4o.ObjectServer;

public class Main {

      public static void main(String[] args) {

            ObjectServer server = Db4o.openServer("arquivo.yap", 0);

            try {

                  ObjectContainer client = server.openClient();

                  client.close();             

 

            } finally {

                  server.close();

            }

      }

}
            

Aplicação Client/Server

Para trabalhar com o db4o via TCP é necessário escolher uma porta maior que 0 para instanciar um ObjectServer do tipo Client/Server. Segue o exemplo:

 
package br.com.tutorial;

import java.io.IOException;

import com.db4o.Db4o;

import com.db4o.ObjectContainer;

import com.db4o.ObjectServer;

public class Main {

      public static void main(String[] args) {

            Integer porta = 8000;

            String usuario= "user";

            String senha = "123";

            ObjectServer server=Db4o.openServer("banco.yap",porta);

            server.grantAccess(usuario,senha);

            ObjectContainer client = null;

            try {

                  client = server.openClient();

            } catch (Exception e) {

                  client.close();

                  e.printStackTrace();

            }

            finally {

            server.close();

            }

      }

}
            

O ObjectServer fornece instancias do ObjectContainer que será aberto por algum cliente. Definimos um usuário e uma senha para que o client possa abrir uma conexão com o banco, além de passarmos como parâmetro a porta do servidor. No parâmetro localhost poderia ser qualquer endereço TCP/IP válido.

Garantindo somente uma instância de Servidor

Para garantir que haja somente uma instância do ObjectServer, vamos utilizar o Pattern Singleton, evitando que a sua aplicação crie diversos ObjectServers sem necessidade.

A minha sugestão seria criar uma classe que forneça o mesmo ObjectServer para qualquer outra classe que a solicite. Vejamos o exemplo:

 
package br.com.tutorial;

import com.db4o.Db4o;

import com.db4o.ObjectServer;

public class MeuServer {

      private static ObjectServer server;

      private MeuServer(){

            this.server = Db4o.openServer("arquivo.yap", 8000);

            this.server.grantAccess("usuario", "senha");

      }

      public synchronized static ObjectServer getServer(){

            if (server==null){

                  server = Db4o.openServer("arquivo.yap", 0);                

            }
          
            return server;

      }

}
            

O método stático getServer() é o responsável por fornecer uma única instância de server, conforme o Pattern Singleton.

Segue o trecho de código utilizando a classe MeuServer:

 
package br.com.tutorial;

 

import com.db4o.ObjectContainer;

import com.db4o.ObjectServer;

 

public class Main {

      public static void main(String[] args) {

            ObjectServer server = MeuServer.getServer();

            ObjectContainer client = null;

            try {

                  client = server.openClient();

                  client.set(new Cliente(222,"Jaqueline"));

                  client.close();

            } catch (Exception e) {

                  client.close();

                  e.printStackTrace();

            } finally {

                  server.close();

            }

      }

}
            

Tunning

  • Configuração do FreeSpace
    Obs: A configuração deve ser feita sempre antes da abertura do banco para todos os comandos citados neste tópico.

    O db4o possui um controle de espaço livre no banco, mantendo um registro de um objeto que foi excluído. Esse espaço será reaproveitado por outro objeto que será inserido futuramente. Existem dois tipos de controle de espaço livre:

    • IndexSytem: O controle do freespace não é perdido caso o sistema fique fora do ar. Isso acontece porque a cada commit o índice é atualizado, ocasionando também uma certa lentidão comparado com o próximo método que veremos a seguir.
    • RamSystem: Este método de controle armazena as informações de espaço livre na memória Ram, mas não garante a sua integridade caso haja uma queda no sistema. Outra desvantagem é o cosumo de RAM que é bem superior. Em compensação possui um desempenho bem maior comparado ao IndexSystem.
    • Configurando:

      RamSystem:

      Db4o.configure().freespace().useRamSystem(); 

      IndexSystem:

      Db4o.configure().freespace().useIndexSystem();  
  • Índice

    Para melhorar a busca dos objetos no banco, o db4o implementa índices nos campos dos objetos. Nós podemos definir um índice para o atributo nome da Classe cliente da seguinte forma:

    Db4o.configure().objectClass(Cliente.class).objectField("nome").indexed(true); 

    Só precisamos definir o índice uma vez. Para desabilitar o índice é só mudar o parâmetro para false.

  • DetectSchemaChanges

    Eu aconselho desabilitar esta configuração somente quando o seu banco entrar em produção. O DetectSchemaChanges detecta se houve alguma alteração em suas classes. O aumento de performance é considerável quando desabilitado.

    • Configurando:
      Db4o.configure().detectSchemaChanges(false); 
  • Defragment

    Regularmente é interessante utilizar este comando para aumentar a performance do banco, eliminando espaços vazios, deletando Id’s que já foram removidos, classes que não são mais utilizadas (não possui mais nenhum objeto dela no banco), restauração de indices, entre outros. Antes de efetuar o comando de defrag faça uma cópia do seu arquivo original. Exemplo:

     
    package br.com.tutorial;
    
    import java.io.IOException;
    
    import com.db4o.defragment.Defragment;
    
    public class Main {
    
          public static void main(String[] args) {
    
                Defragment defrag = new Defragment();
    
                try {
    
                      defrag.defrag("arquivo.yap","arquivo.bak");
    
                } catch (IOException e) {
    
                      e.printStackTrace();
    
                }           
    
          } 
    
    }
                        

    Passamos como parâmetro duas strings, a primeira informando o caminho do arquivo original e a segunda o caminho da cópia de segurança do mesmo.

  • ObjectManager 6.0

    O ObjectManager é uma interface criada para navegar nos objetos inseridos no banco. O Defragment pode ser utilizado pela interface de forma mais amigável. Também é possível efetuar querys a partir do ObjectManager.

    ScreenShot
    Figura 1. ScreenShot
    Banco aberto
    Figura 2. Banco aberto
    Query executada
    Figura 3. Query executada

    Esta é a ultima parte do artigo do Db4o. Ainda existem muitos conceitos, utilitários e features que eu não comentei no artigo, mas podem ser encontradas na documentação.

Leia também