irwin laguado
Diego Forero
Team PlatziIsrael Gutierrez Salazar
¿Cómo insertar registros en una base de datos usando Java y SQL?
En el mundo del desarrollo de software, interactuar con bases de datos es una habilidad esencial. Hoy, exploraremos cómo podemos llevar a cabo una tarea común: insertar registros. En este caso, nos centraremos en cómo marcar una película como vista por un usuario utilizando Java y SQL.
¿Cómo funciona la sentencia INSERT en SQL?
El comando INSERT es una de las declaraciones SQL más utilizadas para agregar nuevos datos a una tabla. En nuestro ejemplo específico, no insertamos una película directamente, sino que marcamos en una tabla denominada viewed qué elementos fueron vistos por un usuario específico.
Para esto, usamos un método en Java que construye y ejecuta un query SQL a través del uso de PreparedStatement y Connection. Siguiendo una estructura similar, podríamos adaptar este método para realizar tareas UPDATE, lo único que cambiaría sería el query. La estructura básica de un INSERT se vería así:
INSERT INTO nombre_tabla (columna1, columna2) VALUES (valor1, valor2);
En el contexto de nuestro código en Java, esto se aplicaría a través de un query almacenado en una cadena de texto y ejecutado con un objeto statement.
¿Cómo implementamos el método INSERT en Java?
La correcta implementación en Java del método para marcar películas vistas implica varios pasos importantes. Aquí se resume el proceso:
Inicio de la conexión:
Utilice un bloque try-with-resources para asegurar que los recursos se cierren adecuadamente después de ser usados.
Construcción del Statement:
Cree un objeto Statement para poder ejecutar queries en la base de datos.
Query de inserción: Construya la cadena de texto que representa el query de SQL usando concatenación. Es importante establecer claramente los valores y las columnas objetivo. Esto sería algo similar a:
String query = "INSERT INTO viewed (material, element, userId) VALUES (1, " + movie.getId() + ", " + userId + ")";
Ejecución y verificación:
Ejecute el query usando executeUpdate. Si el resultado es mayor a cero, significa que se afectó al menos una fila y el proceso fue exitoso.
Captura de excepciones: Asegúrese de manejar adecuadamente las excepciones SQL para prevenir cualquier cierre inesperado del programa.
¿Cómo verificamos si el registro fue exitoso?
Para asegurarse de que el proceso fue exitoso, podríamos verificar directamente en la base de datos o implementarlo como un método que devuelva un booleano positivo si se insertó correctamente. Además, podríamos analizar la cantidad de filas afectadas por la ejecución del query para dar seguimiento al resultado.
Consejos para gestionar usuarios y sus interacciones
Cuando trabajamos con identificadores de usuario, es recomendable no dejarlos hardcodeados. En su lugar, implemente un sistema de gestión de sesiones que asocie una sesión activa con el ID del usuario. Esto provee mayor flexibilidad y seguridad en el manejo de datos y usuarios.
Implementación práctica en un entorno similar a Netflix
Al pensar en grandes bases de datos como las que usaría una plataforma de streaming como Netflix, estos métodos se escalan mediante sistemas distribuidos y manejo intensivo de sesiones. Nuestro ejemplo es una pequeña representación local de lo que sería mantener un historial de visualización de películas para cada usuario, y cómo asegurar que esa información se resguarde adecuadamente en una base de datos estructurada.
Recuerda, la práctica hace al maestro. Te animo a profundizar en este tema mediante la implementación propia de estos métodos en tus proyectos. ¡Sigue adelante y nunca dejes de aprender!
irwin laguado
Diego Forero
Team PlatziIsrael Gutierrez Salazar
Daniel Alejandro Contreras Suárez
Juan Esteban Cardona Patiño
César Espitia
Ricardo Coronado
Miguel Angel Martheyn Berbesi
Miguel Angel Martheyn Berbesi
Miguel Angel Martheyn Berbesi
Jesús Flor Farias
Daniel Alejandro Contreras Suárez
Jonatan Lazo
Luis Guzmán
Israel Gutierrez Salazar
Rafael Carrillo
Mario Ignacio Ledesma Merino
Jaime Ortiz
Marco Bottino Poittevin
Fabian Silva
Willy León
Noe de Jesus Muñoz Martinez
Edgardo Velasquez Gutierrez
Carlos Uriel de Jesus Sánchez González
Daniel Garrido
Edgar Tasayco
Lázaro Bucio Marín
Norman Erick Estrada Vargas
Yossijaki Jorge Astilleros Chávez
Alexander Gomez Espinosa
Santiago Asmal
Gerald Zamora
Gerald Zamora
No me queda muy claro a que hace referencia la palabra reservada this, al momento de ejecutar
movie.setMovieViewed(this);
Primero movie es una instancia de Movie. La clase Movie tiene un método llamado setMovieViewed que implementa desde MovieDAO, este método recibe como parámetro una movie y es llamado en el método view que es public, para poder usar el método view debe ser desde una instancia entonces this hacer referencia a esa instancia.
this hace referencia a la propia clase donde se encuentra el método view.
Por que el método setMovieViewed() no es void? No sirve de nada que regrese un objeto de tipo movie, de hecho en el vídeo ni siquiera se guarda esa respuesta en una variable.
De acuerdo, debería ser void el método setMovieViewed().
Acá dejo mi versión de la interface MovieDAO
package com.erosennin.amazonviewer.dao; import com.erosennin.amazonviewer.db.IDBConnection; import com.erosennin.amazonviewer.model.Movie; import java.sql.*; import java.util.ArrayList; import static com.erosennin.amazonviewer.db.DataBase.*; public interface MovieDAO extends IDBConnection { default ArrayList<Movie> read() { ArrayList<Movie> movies = new ArrayList<>(); try(Connection connection = connectDB()) { String query = String.format("SELECT * FROM %s", TMOVIE); PreparedStatement preparedStatement = connection.prepareStatement(query); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { Movie movie = new Movie( resultSet.getInt(TMOVIE_ID), resultSet.getInt(TMOVIE_DURATION), resultSet.getString(TMOVIE_TITLE), resultSet.getString(TMOVIE_GENRE), resultSet.getString(TMOVIE_CREATOR), resultSet.getShort(TMOVIE_YEAR)); movie.setViewed(getMovieViewed(connection, resultSet.getInt(TMOVIE_ID))); movies.add(movie); } } catch(SQLException e) { e.getMessage(); } return movies; } default void setMovieViewed(Movie movie) { String query = String.format("INSERT INTO %s (%s, %s, %s) VALUES (" + "(SELECT %s FROM %s WHERE %s = '%s'), %s," + "(SELECT %s FROM %s))", TVIEWED, TVIEWED_ID_MATERIAL, TVIEWED_ID_ELEMENT, TVIEWED_ID_USER, TMATERIAL_ID, TMATERIAL, TMATERIAL_NAME, TMOVIE,movie.getId(), TUSER_ID,TUSER); try(Connection connection = connectDB()) { Statement statement = connection.createStatement(); statement.executeUpdate(query); } catch (SQLException e) { e.getMessage(); } } private boolean getMovieViewed(Connection connection, int idMovie) { String query = String.format("SELECT * FROM %s WHERE %s = " + "( SELECT %s FROM %s WHERE %s = '%s' ) " + "AND %s = ? AND %s = " + "( SELECT %s FROM %s )", TVIEWED, TVIEWED_ID_MATERIAL, TMATERIAL_ID, TMATERIAL,TMATERIAL_NAME, TMOVIE, TVIEWED_ID_ELEMENT, TVIEWED_ID_USER, TUSER_ID, TUSER); boolean viewed = false; try { PreparedStatement preparedStatement = connection.prepareStatement(query); preparedStatement.setInt(1, idMovie); ResultSet resultSet = preparedStatement.executeQuery(); viewed = resultSet.next(); } catch (SQLException e) { e.getMessage(); } return viewed; } }
Usé el metodo String.format() para facilitar la lectura de los queries e hice uso de queries anidados para recuperar el id_material y el id_user de la bases de datos en vez de tenerlos "quemados "en el código.
Buen aporte solamente no entendí el query, este es mas corto
< private boolean getMovieViewed(Connection connection, Movie movie){ boolean isViewed = false; try { String query = "SELECT * FROM "+TVIEWED+ "WHERE "+TVIEWED_IDMATERIAL+" = " +ID_TMATERIALS[0]+" AND "+ TVIEWED_IDELEMENT+" = "+movie.getId(); PreparedStatement preparedStatement = connection.prepareStatement(query); ResultSet rs = preparedStatement.executeQuery(); isViewed = rs.next(); }catch (SQLException e){ e.printStackTrace(); } return isViewed; }>
Bueno el codigo me compila todo muy bien, pero no se guardan los datos en visto. Incluso si agrego en el localhost, no se me refleja cuando corro el codigo.
Bueno, encontre el error: Tengan en cuenta su DataBase, yo tenia esto erroneo:
public static final String TVIEWED_IDUSUARIO = "id_usuario";
ya todos sabemos que es:
public static final String TVIEWED_IDUSUARIO = "id_user";
Ademas, como ella indico: Ojo con los espacios, coloque el WHERE pegado a los " y me daba error.
private boolean getMovieViewed(PreparedStatement preparedStatement, Connection connection, int id_movie) { boolean viewed = false; String query = "SELECT * FROM " + TVIEWED + " WHERE " + TVIEWED_IDMATERIAL + "= ?" + " AND " + TVIEWED_IDELEMENT + "= ?" + " AND " + TVIEWED_IDUSUARIO + "= ?";
Otro tema màs y seguimos aprendiendo Java avanzado.
Por que crean una instancia de la clase Movie para llamar el metodo setMovieViewed()? Esto no es necesario, pueden llamar el metodo simplemente asi:
setMovieViewed(this);
Lo mismo me andaba preguntando 🤔
Si fuera un solo usuario que ejecute el sistema funcionaria, pero si ingresa dos o mas como es un metodo estatico los otros accederian a la misma instancia lo cual es incorrecto y causaria problemas. Mejor instanciar un nuevo objeto y se soluciona
Una mejor forma sería hacer void a setMovieViewed
default void setMovieViewed(Movie movie)
y ejecutarla asi
@Override public void view() { setViewed(true); Date dateI = startToSee(new Date()); setMovieViewed(this); for (int i = 0; i < 100000; i++) { System.out.println(".........."); } //Termine de verla stopToSee(dateI, new Date()); System.out.println(); System.out.println("Viste: " + toString()); System.out.println("Por: " + getTimeViewed() + " milisegundos"); }
cuando se realiza una consulta a la base de datos porque no se cierra la conexión o la librería de conexión se encarga de cerrar la conexión
Hola Ras, Cuando se emplean los try-with-resources, estos se encargan de manejar los cierres de conexión, es por eso que Ann no cierra en ningún momento. Saludos!.
¿Para insertar también se puede usar PreparedStatement? Si es afirmativo, ¿para qué usar PreparedStatement si se puede hacer más fácil y más legible hacer la query concatenando los valores?
Hola, también puede usarse PreparedStatement para insertar.
Aquí te dejo un post en donde lo explican: https://stackoverflow.com/questions/11804906/insert-row-into-database-with-preparedstatement
Con respecto a tu segunda pregunta, en mi opinión, al concatenar valores tu código puede perder legibilidad. A mayor cantidad de columnas, más valores que concatenar.
Supongo que depende de cada desarrollador elegir cuándo usar cada uno.
Saludos.
Hola, respecto de si usar instrucciones concatenadas es más sencillo, puede ser que sí, pero cuando tengas que lidiar con datos que tienen una comilla simple como una abreviación en inglés, la concatenación te dará dolores de cabeza. Si alguien tiene una tabla de empleados, y un nuevo empleado se llama Joe O'neil, la concatenación te dará error en el sql resultante. Además, los PreparedStatement son mucho mejores contra ataques de inyección de SQL, así que debes tener en cuenta que la seguridad también debe ser parte de tu aplicación. Espero que te sirvan estos datos! Un abrazo cordial desde Chile.
Alguien me puede ayudar de como genero el reporte... me gustaría saberlo, muchas gracias...
Muy buena clase.
Porqué se uso statement en caso de insert y no un preparedStament?
Statement es para querys staticos y prepareStatement es para querys dinamicos
Normalmente se deben usar query preparadas con los insert, para asi evitar sql injection
Excelente lo de pasar (this) .
😃
buena clase!!!
Excelente material 😄
muy buen ejemplo, solo algo, si le vuelves a da 4 te crea un nuevo registro
Excelente Explicación
Lo puedes poner como visto de esta manera (mas corta y no confunde cual movie es)
new Movie().setMovieViewed(this);
mi versión del query complejo
String query = String.format("INSERT INTO %s (%s, %s, %s) VALUES (" + "(SELECT %s FROM %s WHERE %s = '%s'), %s," + "%s)", TVIEWED, TVIEWED_IDMATERIAL, TVIEWED_IDELEMENT, TVIEWED_IDUSER, TMATERIAL_ID, TMATERIAL, TMATERIAL_NAME, TMOVIE, movie.getId(), TUSER_IDUSUARIO);