Descrevo neste post Projeto completo de interface gráfica (web) controlando placa Arduino, acionando o servo motor, colocando mensagens no LCD e ajustando cor de Led RGB, atuando sobre uma porta ligada a um relé para acender lâmpada, etc.
A Aplicação consiste numa página Web rodando sob um servidor GlassFish.
Esta envia/recebe comandos de uma aplicação Java RMI (RMIServer) que se comunica com a placa Arduino.
Abaixo, projeto completo, incluindo código para o hardware e as bibliotecas RTXcomm.jar para comunicação serial com o Arduino.
Podemos eventualmente, necessitar contar o tempo transcorrido entre dois valores de campos distintos de uma tabela (DATA_FINAL - DATA_INICIAL) ou determinado tempo passado até a data atual.
No Banco Oracle podemos utilizar de alguns artifícios para conseguirmos esta solução.
Utilizarei as tabelas e dados criados no post anterior:
Observação: Utilize o comando abaixo para ajustar o formato de hora para a sessão, a fim de evitarmos problemas de conversão:
--necessario alterar a sessao, utilizo aqui o formato 'DD/MM/YYYY HH24:MI:SS'
ALTER SESSION SET NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI:SS';
Baseando-se que já tenhamos uma tabela e uma pequena massa de dados na mesma, podemos executar a seguinte consulta, calculando a subtração do tempo transcorrido entre a data atual (SYSTIMESTAMP) e a data registrada no campo DATA1:
--demonstra valor de data 1 e suas diferencas
SELECT ID_TESTE
,SYSTIMESTAMP AS DATA_ATUAL
,DATA1
,(SYSTIMESTAMP --DATA ATUAL
-
DATA1
) AS DIFERENCA_ENTRE_DATAS
FROM TESTES_COM_DATA;
Obtendo um resultado semelhante ao demonstrado na figura:
Observe o campo DIFERENCA_ENTRE_DATAS. É demonstrado, dias/horas/minutos/segundos.
Mas e se desejarmos saber apenas os minutos transcorridos?
Podemos usar a cláusula WITH e a partir de um sub-query semelhante à demonstrada acima, extrair os valores desejados, no caso, os minutos transcorridos desde a hora atual até o momento da execução da consulta:
--SELECIONA MINUTOS TRANSCORRIDOS
WITH DIFERENCA AS (
--SELECIONA DIFERENCAS ENTRE A DATA ATUAL
-- E A DATA REGISTRADA NA TABELA
SELECT (
SYSTIMESTAMP --DATA ATUAL ou por ex.:TO_TIMESTAMP('22/04/2016 13:00:00', 'DD/MM/YYYY HH24:MI:SS')
-
DATA1
) AS DIFERENCA_ENTRE_DATAS
FROM TESTES_COM_DATA
)
--EXTRAI OS MINUTOS
SELECT (( EXTRACT (DAY FROM (DIFERENCA_ENTRE_DATAS)) *24*60*60
+ EXTRACT (HOUR FROM (DIFERENCA_ENTRE_DATAS)) *60*60
+ EXTRACT (MINUTE FROM (DIFERENCA_ENTRE_DATAS)) *60
+ EXTRACT (SECOND FROM (DIFERENCA_ENTRE_DATAS)) )/60) AS TOTAL
FROM DIFERENCA;
Observe o resultado
Podemos, através da função ROUND(<valor>,<casas_decimais>) arredondar este valor:
--SELECIONA MINUTOS TRANSCORRIDOS
WITH DIFERENCA AS (
--SELECIONA DIFERENCAS ENTRE A DATA ATUAL
-- E A DATA REGISTRADA NA TABELA
SELECT (
SYSTIMESTAMP --DATA ATUAL ou por ex.:TO_TIMESTAMP('22/04/2016 13:00:00', 'DD/MM/YYYY HH24:MI:SS')
-
DATA1
) AS DIFERENCA_ENTRE_DATAS
FROM TESTES_COM_DATA
)
--EXTRAI OS MINUTOS
SELECT ROUND((( EXTRACT (DAY FROM (DIFERENCA_ENTRE_DATAS)) *24*60*60
+ EXTRACT (HOUR FROM (DIFERENCA_ENTRE_DATAS)) *60*60
+ EXTRACT (MINUTE FROM (DIFERENCA_ENTRE_DATAS)) *60
+ EXTRACT (SECOND FROM (DIFERENCA_ENTRE_DATAS)) )/60)
,0) AS TOTAL_ARREDONDADO -- 0 CASAS DECIMAIS
FROM DIFERENCA;
Neste post procurarei utilizar exemplos de como inserir valores de datas, (campos TIMESTAMP) incrementando, minutos, segundos, etc, a partir da data atual.
Para começar, vamos criar uma tabela de exemplo, com campo identificador (ID_TESTE) dois campos (DATA1 e DATA2) representando as datas atuais e a data acrescida respectivamente.
Há também a criação (opcional) de uma sequence (TESTE_COM_DATA_SEQ) para facilitar a inserção de valores únicos o campo ID_TESTE.
--criação da tabela de testes
CREATE TABLE TESTES_COM_DATA(
ID_TESTE INTEGER,
DATA1 TIMESTAMP(6),
DATA2 TIMESTAMP(6),
PRIMARY KEY (ID_TESTE)
);
--criação de sequence (opcional) para atribuição de
--valores do campo ID_TESTE
CREATE SEQUENCE TESTES_COM_DATA_SEQ
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 20;
Para começarmos, temos que alterar o formato de exibição de TIMESTAMP para a sessão atual do usuário. Esta alteração não é permanente e é cancelada quando encerramos a sessão.
Observação: Sempre que formos utilizar este tipo de tratativas com datas, temos que utilizar o comando abaixo:
--necessario alterar a sessao, utilizo aqui o formato 'DD/MM/YYYY HH24:MI:SS'
ALTER SESSION SET NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI:SS';
Feito isso, vamos estudar os códigos para incremento dos valores de Horas, Minutos e Segundos
--TIMESTAMP ADICIONADO HORAS
SELECT SYSTIMESTAMP AS DATA_ATUAL
, TO_TIMESTAMP(
SYSTIMESTAMP + (
2 --QUANTIDADE DE HORAS ADICIONADAS
/24)
, 'DD/MM/YYYY HH24:MI:SS')
AS DATA_SOMADA_HORAS
FROM DUAL;
--TIMESTAMP ADICIONADO MINUTOS
SELECT SYSTIMESTAMP AS DATA_ATUAL
, TO_TIMESTAMP(
SYSTIMESTAMP + (
5 --QUANTIDADE DE MINUTOS ADICIONADOS
/(24*60))
, 'DD/MM/YYYY HH24:MI:SS')
AS DATA_SOMADA_MINUTOS
FROM DUAL;
--TIMESTAMP ADICIONADO SEGUNDOS
SELECT SYSTIMESTAMP AS DATA_ATUAL
, TO_TIMESTAMP(
SYSTIMESTAMP + (
25 --QUANTIDADE DE SEGUNDOS ADICIONADOS
/24/60/60)
, 'DD/MM/YYYY HH24:MI:SS')
AS DATA_SOMADA_SEGUNDOS
FROM DUAL;
Finalmente, podemos aplicar os conceitos aprendidos dentro de cláusulas de INSERT na tabela do banco:
--inserindo diferença de duas horas
INSERT INTO TESTES_COM_DATA (
ID_TESTE
,DATA1
,DATA2)
VALUES(
TESTES_COM_DATA_SEQ.NEXTVAL --busca proximo valor para a sequence
,SYSTIMESTAMP --data/hora atual
,(TO_TIMESTAMP(
SYSTIMESTAMP + (
2 --QUANTIDADE DE HORAS ADICIONADAS
/24)
, 'DD/MM/YYYY HH24:MI:SS')
) --inserção de SYSTIMESTAMP + 2 Horas
);
--inserindo diferença de quinze minutos
INSERT INTO TESTES_COM_DATA (
ID_TESTE
,DATA1
,DATA2)
VALUES(
TESTES_COM_DATA_SEQ.NEXTVAL --busca proximo valor para a sequence
,SYSTIMESTAMP --data/hora atual
,(TO_TIMESTAMP(
SYSTIMESTAMP + (
15 --QUANTIDADE DE MINUTOS ADICIONADOS
/(24*60))
, 'DD/MM/YYYY HH24:MI:SS')--inserção de SYSTIMESTAMP + 15 mins
)
);
INSERT INTO TESTES_COM_DATA (
ID_TESTE
,DATA1
,DATA2)
VALUES(
TESTES_COM_DATA_SEQ.NEXTVAL --busca proximo valor para a sequence
,SYSTIMESTAMP --data/hora atual
,(TO_TIMESTAMP(
SYSTIMESTAMP + (
30 --QUANTIDADE DE SEGUNDOS ADICIONADOS
/24/60/60)
, 'DD/MM/YYYY HH24:MI:SS')--inserção de SYSTIMESTAMP + 30 segs
)
);
Resultado final das linhas inseridas:
Podemos também adicionar simultaneamente HORAS/MINUTOS/SEGUNDOS à data atual, como no exemplo abaixo:
--inserindo diferenca de HORAS/MINUTOS/SEGUNDOS
INSERT INTO TESTES_COM_DATA (
ID_TESTE
,DATA1
,DATA2)
VALUES(
TESTES_COM_DATA_SEQ.NEXTVAL --busca proximo valor para a sequence
,SYSTIMESTAMP --data/hora atual
,(TO_TIMESTAMP(
SYSTIMESTAMP + (
2 --QUANTIDADE DE HORAS ADICIONADAS
/24)
+(
10 --QUANTIDADE DE MINUTOS ADICIONADOS
/(24*60))
+
(
30 --QUANTIDADE DE SEGUNDOS ADICIONADOS
/24/60/60) --inserção de SYSTIMESTAMP + 30 segundos
)
)
);
Eventualmente, por padrão, o banco de dados Oracle expira a senha de usuários.
Para reverter esta situação execute as linhas a seguir, com usuário SYS , e atribuição SYSDBA:
--desbloqueie o usuário
ALTER USER TESTES_LOCAIS ACCOUNT UNLOCK;
--atribua uma nova senha
ALTER USER TESTES_LOCAIS IDENTIFIED BY 123456;
--verifique a próxima data de expiração (EXPIRY_DATE)
SELECT USERNAME, ACCOUNT_STATUS, EXPIRY_DATE FROM DBA_USERS
WHERE USERNAME='TESTES_LOCAIS';
Se for de seu desejo que as contas de usuário nunca mais expirem, execute os comandos a seguir, também com usuário SYS , e atribuição SYSDBA:
--alterando perfil para não expirar mais
ALTER PROFILE DEFAULT LIMIT PASSWORD_REUSE_TIME UNLIMITED;
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
--verifique se não há mais data de expiração (EXPIRY_DATE)
SELECT USERNAME, ACCOUNT_STATUS, EXPIRY_DATE FROM DBA_USERS
WHERE USERNAME='TESTES_LOCAIS';
Em padrões de desenvolvimento, o "conceito de fábrica" nada mais é do que uma classe onde encapsulamos métodos muito utilizados, além da mesma ser capaz de retornar uma referência a um novo objeto.
Resumindo, no caso da conexão a um Banco de Dados, criamos uma "ConnectionFactory" para nos conectarmos ao banco de dados, nos retornando uma instancia do objeto de conexão com o banco de dados, de maneira a evitar codificação repetida em diversos locais do código.
Nesta caso, também implementaremos métodos para inicialização e fechamento desta conexão, evitando consumo desnecessário de recursos.
No código abaixo, criamos uma conexão para um Banco de Dados Oracle.
Nos próximos posts demonstrarei como criarmos uma classe com métodos para acesso às tabelas do banco. Esta classe, buscará uma instancia da conexão do banco, usando o metodo estáticoConnectionFactory.getConnection();
Abaixo, código comentado de uma Connection Factory:
package br.com.devfacil.factory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ConnectionFactory {
private static Connection conn;
public static Connection getConnection() {
// Connection Factoru de exemplo para Banco Oracle
try {
// Configurações para acesso ao Banco de dados
String driverName = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:XE";
String username = "TESTES_LOCAIS";
String password = "123456";
// Carrega o driver JDBC
Class.forName(driverName);
// Cria uma conexão com a base de dados
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
// Erro na conexão com o driver
System.out.println("Não foi localizado o driver Oracle.");
} catch (SQLException f) {
// Erro na conexão com o Banco de Dados
System.out.println("Não foi possível conectar ao banco.");
}
return conn;
}
// Fecha as conexões
public static void closeConnection(Connection conn, PreparedStatement pstm,
ResultSet rs) throws Exception {
close(conn, pstm, rs);
}
public static void closeConnection(Connection conn, PreparedStatement pstm)
throws Exception {
close(conn, pstm, null);
}
public static void closeConnection(Connection conn) throws Exception {
close(conn, null, null);
}
private static void close(Connection conn, PreparedStatement pstm,
ResultSet rs) throws Exception {
try {
if (rs != null)
rs.close();
if (pstm != null)
pstm.close();
if (conn != null)
conn.close();
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
}
Quando nosso Sistema Operacional utiliza uma grande porcentagem de memória RAM, para não travar, ele lança mão da Memória Virtual.
Explicando este termo resumidamente, "Memória Virtual" é quando o sistema operacional armazena em disco (acesso mais lento), dados que deveriam ser colocados na memória RAM, e isto não pôde ser feito, porque a mesma já estava muito cheia.
O fato da memória RAM estar muito cheia pode ser sinal de que seu sistema precisa ser fisicamente atualizado, adicionar mais 'pentes' de memória RAM pode ajudar.
Quando a memória virtual é alocada pelo sistema operacional, o computador se torna mais lento, pois como já disse anteriormente, o acesso aos dados no disco é muito mais lento do que o acesso à memória.
No Ubuntu, por padrão a memória virtual é acionada quando atinge-se 40% de memória RAM utilizada (60% de memória RAM livre); isto pode tornar o sistema lento rapidamente, no caso do uso mais extremo.
Para checar como seu Sistema Operacional está usando o recurso de swap (memória virtual) e também a memória em si, execute o comando na janela do Terminal (shell):
free -m
O resultado deve ser algo parecido com a tela abaixo:
Note que meu Sistema operacional, está consumindo 619 MB de memória virtual! Podemos mudar isto, ajustando o ponto de utilização da memória RAM em que o sistema operacional começará a alocar dados também em Memória Virtual.
Para saber como este ponto está configurado atualmente, digite o seguinte comando :
cat /proc/sys/vm/swappiness
O SO deve retornar o valor atualmente configurado para swap:
60
O valor a ser alterado é bastante subjetivo, para alterá-lo somente durante a sessão atual como forma de teste, execute o comando:
sudo sysctl vm.swappiness=30
Verifique que o valor está alterado, chamando novamente:
cat /proc/sys/vm/swappiness
Para alterá-lo efetivamente no Sistema Operacional, edite com permissão sudo o arquivo /etc/sysctl.conf e adicione ao final do arquivo a linha:
vm.swappiness = "VALOR_ESCOLHIDO_ENTRE 0 e 100"
Abaixo exemplo:
sudo gedit /etc/sysctl.conf
Adicionei a este arquivo a linha abaixo, no meu caso o valor de 30, que quer dizer que quando estiver com 70% da RAM ocupada, meu SO irá começar a utilizar Memória Virtual.