Pegar int day, int month e int year de campo do Mysql

Olá. Neste tópico eu gostaria de saber qual é o problema desse código aqui:

Date start = rs.getDate(3);
Date end = rs.getDate(4);
Calendar cal = Calendar.getInstance();
cal.setTime(start);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
int year = cal.get(Calendar.YEAR);
cal.setTime(end);
int month2 = cal.get(Calendar.MONTH);
int day2 = cal.get(Calendar.DAY_OF_MONTH);
int year2 = cal.get(Calendar.YEAR);
Event i = new Event(rs.getString(2), year, month, day, year2, month2, day2, rs.getBoolean(6));

Aparentemente não há nada de errado, eu procurei VÁRIOS exemplos na internet, e todos eram da mesma forma. A data que esse código retorna pelo start é 31/11/2000, porém o que está no banco é 2017-03-04.

Posta o select e o retorno para o método que contém o código acima.

Esse é o método que faz o SELECT:

public static ArrayList<Event> getEvents() throws SQLException{
	Methods.verifyConnection();
	ArrayList<Event> toReturn = new ArrayList<Event>();
	final String query = "SELECT * FROM eventos WHERE usuario="+UserDAO.getCurrentUser().getId()+";";
	PreparedStatement st = (PreparedStatement) UserDAO.getConnection().prepareStatement(query);
    ResultSet rs = st.executeQuery(query);
    while(rs.next()){
    	try{
	    	Date start = rs.getDate(3);
	    	Date end = rs.getDate(4);
	    	Calendar cal = Calendar.getInstance();
	    	cal.setTime(start);
	    	int month = cal.get(Calendar.MONTH);
	    	int day = cal.get(Calendar.DAY_OF_MONTH);
	    	int year = cal.get(Calendar.YEAR);
	    	cal.setTime(end);
	    	int month2 = cal.get(Calendar.MONTH);
	    	int day2 = cal.get(Calendar.DAY_OF_MONTH);
	    	int year2 = cal.get(Calendar.YEAR);
	    	Event i = new Event(rs.getString(2), year, month, day, year2, month2, day2, rs.getBoolean(6));
	    	i.setId(rs.getLong(1));
	    	toReturn.add(i);
    	}catch(NullPointerException e){
	    	Event i = new Event(rs.getString(2), rs.getBoolean(6));
	    	i.setId(rs.getLong(1));
	    	toReturn.add(i);
    	}
    }
	rs.close();
	return toReturn;
}

O print 31/11/2000 eu fiz no construtor do Event:

	System.out.println(day+"/"+month+"/"+year);

E dando o SELECT desse método…

Vamos por partes.
Primeiro, embora seja bem útil, o * é uma má prática em se tratando de queries. Prefira descrever cada um dos campos que está pesquisando.
Algo como select id, evento, usuario, inicia, termina, feito, constante from eventos where usuario = 1.
Segundo, não sei se te falaram, mas, o ResultSet não tem índice iniciado em 0, mas, em 1, logo
Date start = rs.getDate(3); se refere ao valor vindo da coluna usuario e não à coluna inicia.
Provavelmente seja este o problema.
Terceiro, prefira utilizar Date start = rs.getDate("inicia"); ao invés de indicar o índice numérico.

1 curtida

Pode gerar algum erro? Porque se eu for implementar em todos os SELECT do meu projeto, as classes DAO vão ficar maiores, e mais poluídas de certa forma.

Eu trabalho com Java, e com JDBC há bastante tempo, então, já me falaram, mas na hora de escrever o código eu sempre confundo o índice dos parâmetros do PreparedStatement e do ResultSet. Mas eu quando eu mudo para rs.getDate(3), é pego o valor da coluna evento:

Caused by: java.lang.NumberFormatException: For input string: "Para o trigger 3"

Valeu pela dica, eu realmente não sabia que esse método tem um parâmetro de String. Eu alterei todo o código, aparentemente agora essa parte está certa, mas agora a data está vindo com o mês errado:

3/2/2017

Aí a gente entra em outro ponto, o valor numérico que representa os meses, retornado pelo método int month = cal.get(Calendar.MONTH); retorna algo entre 0 e 11 (onde 0 representa o mês de janeiro e 11 o mês de dezembro). Logo, o mês retornado não está errado, apenas não foi interpretado da maneira adequada, pois, se a data salva no banco se refere ao mês de março, o valor correspondente devolvido pelo objeto de Calendar é 2.

1 curtida

Não e sim. Não vai, necessariamente, resultar em erro, mas, você já ouviu falar em produto cartesiano? Teoricamente, toda query deveria passar pelo crivo de um DBA ou um desenvolvedor focado em performance de banco de dados. Certamente ele reprovaria todas as queries com * como alvo das pesquisas.

1 curtida

Eu respondi não e sim para a pergunta anterior. Talvez o índice das colunas trazidas pelo ResultSet seja diferente do que você imagina e do que a consulta direto na ferramenta visual do banco de dados mostre. Como curiosidade, deixo um link de um exemplo do uso de ResultSetMetadata, que dá meios para operar com os metadados do banco, incluindo o nome das colunas numa consulta e o total de registros retornados. Veja

1 curtida

Valeu. Eu adicionei um ao mês e ao dia e a data agora é a mesma do banco, muito obrigado pela ajuda.

Tem ideia se isso influenciaria MUITO em performance no caso de muitos usuários?

Valeu mesmo. Eu não conhecia o ResultSetMetadata. Eu estava procurando há algum tempo atrás como saber a quantidade de linhas de um ResultSet, então eu fiz uma “gambiarra”, indo ao último resultado e voltando para o primeiro. Se eu soubesse que ResultSetMetadata tinha um método só pra isso, polparia trabalho.

Bom, na verdade, não interfere. É uma soma simples.
De qualquer forma, eu preferiria passar a data completa para o objeto da classe, ao invés de quebrar os valores e passá-los isoladamente.

Eu estou fazendo assim porque eu realmente preciso dos valores separados para fazer algumas tomadas de decisões.

E por que não manda como Date ou Calendar e cria uma classe utilitária para fazer a conversão? Assim você poderia ter algo como
public class CalendarUtils { public int[] getDayMonthAndYearFromCalendarInstance(Calendar cal) { int[] dma = new int[3]; int month = cal.get(Calendar.MONTH); int day = cal.get(Calendar.DAY_OF_MONTH); int year = cal.get(Calendar.YEAR); dma[0] = year; dma[1] = month; dma[2] = day; return dma; } }
Assim você tem acesso aos dados que necessita, em qualquer ponto do teu sistema, melhora a estrutura do POJO e a funcionalidade do DAO. Apenas uma sugestão.

2 curtidas

Você está começando, até aí é válido sua forma de manipular os dados devido o aprendizado, mas a medida que for ganhando experiência, verá que qualquer tomada de decisão pode ser feita extraindo os dados da informação, nesse caso um campo data transformando em objeto etc…

Digo isso pelo simples fato de você ter que dar manutenção no código e na base, concorda que cuidar de 3 campos dá mais trabalho que cuidar de 1 só?

Outra coisa, comece a treinar o longo prazo dos projetos, se precisar gerar um relatório, enviar um json, etc, vai ter que juntar os campos toda vez?

Hoje você trabalha/estuda sozinho, mas imagine-se em equipe, você precisa dar manutenção nisso, como ficar? E se sair de férias e outra pessoa for cuidar do seu código, como ele saberá a regra de negócio que você colocou?

São muitas variantes, com o tempo se pega prática…

1 curtida

Complementando o @LostSoldier disse, uma coisa que pouca gente ensina, comenta ou mesmo aprende é sobre a responsabilidade da classe: uma classe deve ser capaz de realizar apenas as tarefas que lhe cabem (até mesmo o termo “tarefas”, no plural, está errado). Todos os métodos de uma classe devem permitir que ela atenda a razão pela qual ela existe.
Quando uma classe começa a fazer coisas que não seriam da responsabilidade dela, é sinal de que a lógica empregada está errada e você deve, urgentemente, criar uma nova classe para resolver isso.

2 curtidas

Valeu pela ideia, vou fazer assim, vai diminuir muitas linhas de código.