Como Recuperar a Data Atual do Banco de Dados
Uma das informações que com alguma frequência preciso é a data e a hora atuais. Você sabe que não podemos confiar na data da máquina do cliente e particularmente considero uma má prática utilizar a data da máquina onde está o servidor de aplicação. O ambiente onde está a aplicação pode ser formado por um cluster onde as máquinas não necessariamente compartilham da mesmas data e hora. Se tempo é crítico para sua apicação, você precisa que ela venha de um local centralizado e confiável.
Não sou fã de utilizar SQL nativo e nem de criar coisas no banco de dados que me retornem alguma informação pontual, como procedures e views, mas se você não tem uma central horária (servidor NTP), o banco de dados acaba se tornando um caminho válido, pois teoricamente há DBAs e um pessoal de infraestrutura cuidando de vários aspectos técnicos desse ambiente, como o hardening, o monitoramento dos processos, o gerenciamento de patches, provisionamento de recursos, etc. É claro que tanto zelo com um servidor tão estratégico dá crédibilidade às informações que queiramos extrair de lá.
Vamos utilizar a nossa já conhecida interface ReturningWork para acessar a Connection através da Session do Hibernate* e de lá extrair o nome do banco de dados utilizado consultando a instância de um DatabaseMetadata, que é uma interface implementada pelo fabricante do driver JDBC. Se você sabe qual é o banco de dados, e isso em geral é verdade, não é necessário fazer isso:
Session hibernateSession = entityManager.unwrap(Session.class); String databaseName = hibernateSession.doReturningWork( new ReturningWork<String>() { @Override public String execute(Connection connection) throws SQLException { return connection.getMetaData().getDatabaseProductName(); } });
Nesse ponto é interessante que você crie uma enum para mapear a forma de se fazer a consulta que retorna a data em cada um dos SGBDs que você utiliza. Criei uma para o Oracle e outra para o MySQL, mas omiti o método que determina qual é a enum correta assim como os getters:
public enum DBDialect { ORACLE("Oracle", "SELECT TO_CHAR(SYSDATE, 'dd/MM/yyyy HH24:mi:ss') FROM DUAL"), MYSQL("MySQL", "SELECT DATE_FORMAT(SYSDATE(),'%d/%m/%Y %H:%i:%s')"); // (...) demais métodos para recuperar o dialeto correto }
Sabendo o nome do banco de dados, podemos utilizar a sintaxe de consulta correta para extrair a data através de uma Native Query:
DBDialect dbDialect = DBDialect.find(databaseName); Query query = entityManager.createNativeQuery(dbDialect .getCurrentDateQuery()); String valorData = (String) query.getSingleResult(); SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); Date dataAtual = dateFormat.parse(valorData);
Notas
* Essa implementação é dependente do framework ORM, mas cada decisão que você toma deve ter prós que superem os contras segundo algum critério. Em um mundo ideal, deveríamos depender das abstrações e não das implementações. Em outras palavras, trata-se do “D” (Dependency inversion principle) do SOLID.
Referências
1. http://www.coderanch.com/t/622811/ORM/databases/createNativeQuery-JPA
2. http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/jpa_overview_sqlquery_obj.html
3. http://stackoverflow.com/questions/6707115/get-hold-of-a-jdbc-connection-object-from-a-stateless-bean
4. http://stackoverflow.com/questions/20629523/how-to-know-database-type-programmatically-in-jpa
5. http://stackoverflow.com/questions/16994226/how-to-get-datasource-or-connection-from-jpa2-entitymanager-in-java-ee-6