Misael Pereira Diaz
Braian Peña
¿Cómo podemos persistir el estado de las películas vistas en nuestra aplicación?
En una aplicación donde gestionamos bibliotecas de medios, como películas, series y libros, una funcionalidad crucial es la de guardar el estado de los elementos visualizados para recordar qué contenido ya ha sido consumido. Este estado debe ser persistente, es decir, debe almacenarse de manera que no se pierda al cerrar la aplicación. En este artículo, exploraremos cómo implementar esta lógica utilizando SQL y estructuras de tabla para asegurar que el marcado de "visto" de una película sea persistente.
¿Cuál es la estructura de la tabla necesaria?
Para lograr la persistencia de los datos, necesitamos una tabla en nuestra base de datos capaz de almacenar información acerca de qué contenido ha visto el usuario. Aquí presentamos los campos básicos que debe tener la tabla viewed:
Estos datos nos permitirán identificar exactamente qué material ha sido visualizado por cada usuario.
¿Cómo manejar las consultas SQL para recuperar el estado de los elementos vistos?
Una parte crítica del proceso es ejecutar consultas SQL que permitan verificar si un elemento ya ha sido visto. Para lograr esto, podemos implementar un método en nuestro código que recupere el estado desde la tabla viewed. Utilizaremos declaraciones preparadas (prepared statements) para evitar problemas de inyección SQL y asegurar el funcionamiento adecuado de las consultas.
boolean getMovieViewed(int movieId) { boolean isViewed = false; // Variable bandera String query = "SELECT * FROM viewed WHERE id_material = ? AND id_element = ? AND id_user = ?"; try (PreparedStatement preparedStatement = connection.prepareStatement(query)) { preparedStatement.setInt(1, 1); // Material type for movies preparedStatement.setInt(2, movieId); // Movie identifier preparedStatement.setInt(3, 1); // User identifier ResultSet rs = preparedStatement.executeQuery(); if (rs.next()) { isViewed = true; } } catch (SQLException e) { e.printStackTrace(); // Manejo de errores } return isViewed; }
¿Cómo asegurar que el estado del elemento sea visible al usuario?
Para que los cambios se reflejen adecuadamente en la aplicación, debemos actualizar el objeto que representa la película, serie o libro, usando el método setViewed y llamar al método getMovieViewed siempre que se incite a mostrar el estado "visto" de un elemento.
movie.setViewed(getMovieViewed(movie.getId()));
Implementando esta lógica, cada vez que abramos la aplicación, el estado de visión del usuario sobre el contenido estará correctamente cargado, mejorando la experiencia del usuario y facilitando la gestión de contenido visto.
¿Qué debemos hacer para insertar datos a la tabla Vuido?
Para completar el proceso, es necesario implementar formas de agregar entradas a la tabla viewed cuando un usuario vea un nuevo contenido. Esto nos asegurará que la visualización del contenido se registre correctamente para futuras referencias y filtros. En nuestro siguiente paso, exploraremos cómo implementar esa funcionalidad.
Misael Pereira Diaz
Braian Peña
Jesús Flor Farias
Omar Orjuela Rodríguez
Juan Ramirez
Diego Ballesteros
Justine Briceño Cortez
Justine Briceño Cortez
César David Ramírez Dimaté
Daniel Alejandro Contreras Suárez
Elizabeth López Sanchez
Elizabeth López Sanchez
Braian Peña
Paul Cortes
Leonardo Vanegas
Edinson Padrón
Rafael Carrillo
Cristhian Franco
Diego Ballesteros
TransaNext Team
Diego Forero
Team PlatziJULIAN DAVID SOTO SALAZAR
Noe de Jesus Muñoz Martinez
Norman Erick Estrada Vargas
Jhosmar Parra Montaño
Ariel Eduardo Grahl Chamorro
Yossijaki Jorge Astilleros Chávez
Johan Charris
Daniel Alejandro Contreras Suárez
Yordanis Cobas Lobaina
Francisco Javier Suarez Verdugo
Marco Antonio Jimenez Soto
Diego Forero
Team PlatziSi quieren entender mejor esto de las bases de datos recomiendo ir al curso de fundamento de bases de datos de platzi como yo lo hice y entenderán mejor de lo que habla ann.
Tienes razón da una buena base.
Vamos bien, entendí perfecto, gracias anncode
Si tienen problemas con el error acerca de la zona horaria pueden configurarla en MySQL con
SET GLOBAL time_zone = “-5:00”
-5 para Colombia.
¿en qué momento se cierra la conexión? o ¿ya no es necesario hacerlo ?
tengo problemas con persistencia, no mantiene la informacion vista
yo también
Lo pude resolver, revisa que tengas bien configurada la ruta de makefiile.jar, eso resolvio mi problema.
Cambios que le hice a la clase
movie.getId() para obtener el id que ya fue asignado en el objeto.return en el finally.getString() y los getInt().close().MovieDAO.java
package com.platzi.amazonviewer.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import com.platzi.amazonviewer.db.IDBConnection; import com.platzi.amazonviewer.model.Movie; import static com.platzi.amazonviewer.db.DataBase.*; public interface MovieDAO extends IDBConnection { default Movie setMovieViewed(Movie movie) { return movie; } @SuppressWarnings("finally") default ArrayList<Movie> read() { ArrayList<Movie> movies = new ArrayList<>(); try (Connection connection = connectToDB()) { String query = "SELECT * FROM " + TMOVIE + ";"; PreparedStatement preparedStatement = connection.prepareStatement(query); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { Movie movie = new Movie( resultSet.getString(TMOVIE_TITLE), resultSet.getString(TMOVIE_GENRE), resultSet.getString(TMOVIE_CREATOR), resultSet.getInt(TMOVIE_DURATION), resultSet.getShort(TMOVIE_YEAR)); movie.setId(resultSet.getInt(TMOVIE_ID)); movie.setViewed(this.getMovieViewed(preparedStatement, connection, movie.getId())); movies.add(movie); } preparedStatement.close(); } catch (Exception e) { e.printStackTrace(); } finally { return movies; } } @SuppressWarnings("finally") private boolean getMovieViewed(PreparedStatement preparedStatement, Connection connection, int idMovie) { boolean viewed = false; String query = "SELECT * FROM " + TVIEWED + " WHERE " + TVIEWED_IDMATERIAL + " = ?" + " AND " + TVIEWED_IDELEMENT + " = ?" + " AND " + TVIEWED_IDUSUARIO + " = ?;"; ResultSet resultSet = null; try { preparedStatement = connection.prepareStatement(query); preparedStatement.setInt(1, TMATERIALS_ID[0]); preparedStatement.setInt(2, idMovie); preparedStatement.setInt(3, TUSER_IDUSUARIO); resultSet = preparedStatement.executeQuery(); viewed = resultSet.next(); preparedStatement.close(); } catch (Exception e) { e.printStackTrace(); } finally { return viewed; } } }
Tengo un par de dudas que espero me respondan:
Hay algun problema en declarar un nuevo PreparedStatement dentro del metodo getViewed()? Ya que no veo la razon de pasar por paramtro si se inicializa nuevamente dentro del metodo.
Mi otra duda es, Cuando se agrego el metodo setID() a la clase Movie?, Ann habia dicho que no se debia asignar el id de manera manual y quito todos los metodos setID(). Esto no incurre en alguna falla de diseno?
No hay problema de crear nuevos statements, o connections cuando tu aplicación vaya a trabajar con 1000 usuarios por ejemplo.
Pero es buena práctica disminuir el número de instancias que se pudiesen crear en la aplicación ya que cada instancia es memoria consumida.
Entonces conviene reutilizar esto para 1000 conexiones, crearías 1000 instancias de conexion y 1000 de statements por todos tus 1000 usuarios, pero imagina que no reutilizaces las instancias.
Esto equivale que en algún momento estás creando 2000 y 2000 instancias respectivamente, lo que consume memoria. Ahora imagina que no tienes 1000 usuarios sino unos 500 mil... uy!
Esto profesionalmente se soluciona con inyección de dependencias, microservicios y más detalles que como compañía en gran crecimiento puedes implementar donde trabajes o en tu propia empresa.
Pénsandolo bien, en java los parámetros son pasados por valor siempre, entonces habrían dos instancias del objeto aun cuando pases por parámetro a un método,entonces no hay diferencia. Lo siento, en C++ esa situación sí aplica...
Recomiendo usar mysql Workbench y pasar por el curso de fundamentos de base de datos.
Excelente clase muy buena explicación
Una ayuda gente. Estoy tratando de compilar el proyecto en IntelliJ con java 11.06 pero me arroja el siguiente error.
Information:java: Errors occurred while compiling module 'AmazonViewer' **Information:javac 11.0.6 was used to compile java sources** Information:3/3/2020 4:56 PM - Build completed with 1 error and 0 warnings in 1 s 335 ms D:\Platzi\JavaSEBasicoAvanzado\AmazonViewer\src\com\anncode\amazonviewer\dao\MovieDAO.java **Error:(41, 35) java: private interface methods are not supported in -source 8 (use -source 9 or higher to enable private interface methods)**
Estás haciendo uso de una característica existente a partir de Java9 (método privado en interfaces), sin embargo, estás usando Java8 como el dialecto para el código fuente. Sin importar la versión de la JDK, el compilador permite definir la versión del código fuente así como también del bytecode a producir. Mira la configuración para dichas versiones en tu configuración (gradle o maven) así como en tu IDE.
tengo un problema lo que pasa es que al dejar la versión de java 8 puedo usar las array list como las teníamos definidas, pero no puedo implementar el método boolean en las interfaces, y cuando pongo java 9 no puedo usar el las array lis pero si puedo usar el método defaul
Puede que sea un problema con la version que bajaste. La forma en que funcionan las versiones de Java es que usualmente hay una Long Term Support(LTS), en este caso Java 8 es una de ellas, asi que incluye las funciones que salieron en Java 9 y 10, la siguiente version LTS es la 11.
Si puedes mostrar la parte del codigo que no esta funcionando seria de gran ayuda para solucionar tu problema.
double check the fields on MovieDAO , i used one more extra field and thats the reason that it wasn't updating on my program.
private boolean getMovieViewed(PreparedStatement preparedStatement, Connection connection, int id_movie ) { boolean viewed = false; String query = "SELECT * FROM " + TVIEWED + //generating query " WHERE " + TVIEWED_IDMATERIAL + "= ?" + // start working with filters " AND " + TVIEWED_IDELEMENT + "= ?" + " AND " + TVIEWED_IDUSER + "= ?" ;
Tengo el siguiente problema quie me explica por favor
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column ‘id_viewed’ in 'where clause’
De igual manera no me reconoce el private boolean getMovieViewed
Asegúrate que el nombre de la columna es id_viewed y no solo id o algo similar ya que es el error que esta presentando estas intentando filtrar por un nombre de columna que no existe.
Como solucionaste el problema tengo el mismo error!
Muy buena clase.
excelente clase !!!1
cual es la funcion que realiza la instruccion setID(…), dentro de la funcion read() de la clase MovieDao ?
Como ahora trae los datos de la DB, necesita ese método al construir el objeto y define así el ide según la base de datos.
Excelente curso
Hola tengo problemas con el metodo private boolean getMovieViewed(), me dice que private is not allowed here. Utilizo netbeans 8.1 y jdk1.8.0_91
import static db.DataBase.*; import java.util.ArrayList; import model.Movie; import db.IDBConnection; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public interface MovieDAO extends IDBConnection{ default Movie setMovieViewed(Movie movie){ return movie; } default ArrayList<Movie> read(){ ArrayList<Movie> movies = new ArrayList(); try(Connection connection = conectToDB()){ String sql = "SELECT * FROM "+TMOVIE; PreparedStatement preparedStatement = connection.prepareStatement(sql); ResultSet result = preparedStatement.executeQuery(); while(result.next()){ System.out.println("title"+result.getString(TMOVIE_TITLE)); Movie movie = new Movie( result.getInt(TMOVIE_DURATION), result.getString(TMOVIE_TITLE), result.getString(TMOVIE_CREATOR), result.getString(TMOVIE_GENERE), result.getShort(TMOVIE_YEAR) ); movie.setId(result.getInt(TMOVIE_ID)); movies.add(movie); } }catch(SQLException e){ System.out.println("Error:"+e.getSQLState()+" "+e.getMessage()); } return movies; } private boolean getMovieViewed(){ return false; } }
Los metods private dentro de los interfaces son validos a partir de java 9.
QUizás tengas instalada una version de Java inferior a Java 9.
Estupenda clase instructora Anahí, que claro el uso de parámetros a través de este tipo de consulta.
@anncode me quede varado en en este video debido a que a mi el xampp no me funciona como a ti, toco poner el puerto localhost:8080 , pero mi duda seria en esta linea .
public static final String URL = "jdbc:mysql://localhost:8080:3306/";
al tener el puerto 8080 y no el 8000 como hago la conexión y estoy usando java 11 esta linea estaría correcta??
Class.forName("com.mysql.cj.jdbc.Driver");
Quedo atento a tus respuestas.
Hola si revisas dos clases anteriores https://platzi.com/clases/1236-java-avanzado/10984-generando-conexion-a-la-base-de-datos-y-creando-cl/?time=604 la conexión va con el puerto 3306 unicamente, el que tu servidor web de xampp corra en el puerto 8080 solo afecta al php my admin tu conexión a la base de datos solo va con el puerto 3306 jdbc:mysql://localhost:3306/