Caros colegas venho há muitos dias tentando implementar uma rotina de restauração de backup no sistema que estou desenvolvendo.
Estou utilizando Firebird 2.5 + JPA e para o backup/restore a api FBBackupManager.
Meu problema é apenas na opção de restauração, pode sempre é retornada a mensagem de que o banco de dados pode estar em uso.
Postarei a seguir os métodos que implementei, peço aos colegas que me dêem alguma dica de como resolver esse problema.
/*Este método deve ser chamado na tela de login, no momento em que o usuário tentar logar no sistema.*/
public static EntityManager getConexao(Map properties) throws PersistenceException, GDSException {
try {
if (fabrica == null) {
fabrica = Persistence.createEntityManagerFactory("fluxocaixaPU", properties);
}
return fabrica.createEntityManager();
} catch (ClassCastException erro) {
JOptionPane.showMessageDialog(null, "Erro ao gerar a conexão!\n\n" + erro.getMessage());
return null;
}
}
public static void fecharEntityManagerFactory() {
fabrica.close();
fabrica = null;
}
método responsável por disparar a rotina de backup
private void jbtRestaurarActionPerformed(java.awt.event.ActionEvent evt) {
Map<String, String> dados = new HashMap();
fecharConexoes();
try {
//pegar login e senha do usuário que tem poderes para fazer restore do banco de dados.
FBBackupManager backup = new FBBackupManager();
backup.setUser(DadosUsuario.getInstanceOf().getUsuario().getNome());
backup.setPassword(DadosUsuario.getInstanceOf().getUsuario().getSenha());
backup.setPort(3050);
backup.setHost("127.0.0.1");
backup.setDatabase("C:/bd/FluxoCaixa.FDB");
backup.setBackupPath(getRestaurado());
backup.setVerbose(true);
backup.setRestoreReplace(true);
backup.restoreDatabase();
JOptionPane.showMessageDialog(null, "Restauração concluída com sucesso!");
jtxCaminhoRestauracao.setText("");
} catch (SQLException | NullPointerException | PersistenceException e) {
JOptionPane.showMessageDialog(null, "Erro: " + e.getMessage());
e.printStackTrace();
} finally {
try {
dados.put("javax.persistence.jdbc.user", DadosUsuario.getInstanceOf().getUsuario().getNome());
dados.put("javax.persistence.jdbc.password", DadosUsuario.getInstanceOf().getUsuario().getSenha());
//conectando novamente ao banco de dados
FabricaConexao.getConexao(dados);
ConexaoRelatorio.getConexaoNova(dados);
} catch (PersistenceException | GDSException ex) {
JOptionPane.showMessageDialog(null, "Erro: " + ex.getMessage());
}
}
}
private void fecharConexoes() {
//desconecta o banco de dados
FabricaConexao.fecharEntityManagerFactory();
}
Por algum motivo sua conexão ainda está aberta quando você tentar restaurar o banco. Como o Firebird não restaura se houverem conexões ativas, dá esse erro.
Tente rever se seu método de fechar a conexão está fechando realmente (faça um teste: abre e feche a conexão e veja o status). Pode tentar usar uma ferramenta como sugerido aqui ou através dessa tela (no Windows):
Com o sistema ativo, clique em Refresh. Se houverem conexões, aparecerão em Number of attachments e number of databases.
Abraço.
TerraSkill, vc poderia me dar alguma dica sobre o fechamento da conexão?
Estou trabalhando com o padrão Singleton, simplesmente faço um close e atribuo nulo a variável que retornaria uma estância de entitymanager.
Não sei o que precisa ser feito, já pesquisei na internet mas não consegui resolver.
Tem muito tempo que não uso Firebird e Java, então não conseguirei ser muito preciso.
Aqui é sugerido que o uso de close() não é suficiente pois o JayBird usa um pool de conexões, e o ideal é usar shutdown(). Você pode investigar algo nesse sentido.
Se a aplicação e o FBBackupManager estão usando a conexões diferentes, pode ser que a conexão de um dos dois esteja ativa (o FBBackupManager deveria ser esperto o suficiente para saber que não pode estar conectado ao tentar restaurar, mas não conheço essa API para afirmar). Se você faz o backup e logo em seguida o restore, pode ser que a conexão do backup ainda esteja aberta.
Pode também tentar fazer o restore pela linha de comando (gbak), sem ativar em momento nenhum o FBBackupManager. Isso ajuda a definir se a conexão ativa é no FBBackupManager ou na sua aplicação.
Abraço.
Agradeço muito pelo seu comentário, não fazia nem ideia de que o jaybird usava um pool internamente. E muito menos onde mais poderia fazer uma possível alteração no meu código.
Já baixei o manual do jaybird (versão 2.1) e acredito que vai ser extremamente útil, na verdade, obrigatório.
Enfim, fiz o seguinte procedimento: dentro do método que dispara a rotina de restauração, antes de invocar os métodos do objeto FBBackupManager, instanciei um objeto do tipo FBWrappingDataSource e chamei o método shutdown. O fato é que antes eu não conseguia restaurar minha base de dados (e depois da super dica que você me passou), depois de alterar conforme citei acima a restauração acontece perfeitamente.
Valeu mesmo, muito obrigado pela dica!
private void jbtRestaurarActionPerformed(java.awt.event.ActionEvent evt) {
Map<String, String> dados = new HashMap();
fecharConexoes();
try {
FBWrappingDataSource wds = new FBWrappingDataSource();
/*este método fechará todas as conexões, independentes de estarem ou não em uso.*/
wds.shutdown();
//pegar login e senha do usuário que tem poderes para fazer restore do banco de dados.
FBBackupManager backup = new FBBackupManager();
backup.setUser(DadosUsuario.getInstanceOf().getUsuario().getNome());
backup.setPassword(DadosUsuario.getInstanceOf().getUsuario().getSenha());
backup.setPort(3050);
backup.setHost("127.0.0.1");
backup.setDatabase("C:/bd/FluxoCaixa.FDB");
backup.setBackupPath(getRestaurado());
backup.setVerbose(true);
backup.setRestoreReplace(true);
backup.restoreDatabase();
JOptionPane.showMessageDialog(null, "Restauração concluída com sucesso!");
jtxCaminhoRestauracao.setText("");
// pool.bringDatabaseOnline();//coloca o banco online novamente
} catch (SQLException | NullPointerException | PersistenceException e) {
JOptionPane.showMessageDialog(null, "Erro: " + e.getMessage());
e.printStackTrace();
} finally {
try {
dados.put("javax.persistence.jdbc.user", DadosUsuario.getInstanceOf().getUsuario().getNome());
dados.put("javax.persistence.jdbc.password", DadosUsuario.getInstanceOf().getUsuario().getSenha());
//conectando novamente ao banco de dados
FabricaConexao.getConexao(dados);
ConexaoRelatorio.getConexaoNova(dados);
} catch (PersistenceException | GDSException ex) {
JOptionPane.showMessageDialog(null, "Erro: " + ex.getMessage());
}
}
}
Que bom que funcionou. Como disse, faz tempo que não mexo em Firebird+Java. Só sei do problema da conexão estar ativa porque isso realmente enche o saco no caso do Firebird, daí juntei uma coisa com a outra.
Abraço.
A falta de experiência atrapalha bastante.
Agora só uma última dúvida, essa é uma particularidade do Firebird apenas? Se eu usar por exemplo o PostgreSql (ou qualquer outro banco de dados) não teria esse inconveniente?
Sinceramente, não sei. Nunca mexi com backup em Postgre. O esquema de backup do Firebird é simples: ele apaga o banco original e “descompacta” o backup no mesmo lugar. Não é o que chamaria de genial
, mas funciona.
Se tiver a oportunidade de testar outros bancos, acho que vale o teste. Ainda mais se puder deixar sua aplicação independente do banco (algo positivo, se não aumentar muito a complexidade).
Abraço.