package com.trifulcas.controller; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class EjercicioController { // Endpoint. Cualquier programa que acceda a este endpoint // Tendrá esta respuesta // url del servidor + '/ola' @GetMapping("/ola") public String ola() { return "Ola k ase???"; } @GetMapping("/normal") public String normal() { return "Hola ¿Qué tal?"; } @GetMapping("/personal") public String personal( @RequestParam(value = "nombre", defaultValue = "Anónimo") String nombre) { return String.format("Hola %s ¿Cómo estás?", nombre); } @GetMapping("/azar") public String azar() { return azarRandom(); } private String azarRandom() { List<String> mensajes = new ArrayList<>(Arrays.asList("Hola", "Que hay?", "Buenas", "Jelou", "Hey")); Random r=new Random(); return mensajes.get(r.nextInt(mensajes.size())); } }
Autor: Juan Pablo Fuentes
Como NO hacer una calculadora
Spring boot
Asó queda el main
package com.trifulcas.TestSpringBoot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan("com.trifulcas") public class TestSpringBootApplication { public static void main(String[] args) { SpringApplication.run(TestSpringBootApplication.class, args); } }
Así queda el controlador
package com.trifulcas.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { // Dentro del controlador pondré todas las entradas a mi app // Se mapean con Mapping y la ruta @GetMapping("/") public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { return String.format("Hello %s!", name); } }
Controlador con más endpoints
package com.trifulcas.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { // Dentro del controlador pondré todas las entradas a mi app // Se mapean con Mapping y la ruta // Defino un punto de entrada que es la raiz @GetMapping("/") public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { System.out.println("Han entrado en la raiz. Name vale"+name); return String.format("Hello %s!", name); } // mi punto de entrada es /pepe @GetMapping("/pepe") public String pepe() { System.out.println("Han entrado en pepe"); return "Me llamo pepe"; } // Punto de entrada /suma y recupero dos parámetros (a y b) con los que hago la suma @GetMapping("/suma") public String suma(@RequestParam(value = "a", defaultValue = "1") String a, @RequestParam(value = "b", defaultValue = "1") String b) { System.out.println("Han entrado en suma con valores "+a+","+b); return (Integer.parseInt(a)+Integer.parseInt(b))+""; } }
Ejemplos HQL
Session session = HibernateUtil.getSessionFactory().openSession(); // Ojo aquí, el from es caseinsensitive pero la entidad 'Autor' // SI LO ES tiene que ser como se llame la entidad // Esto es lo más sencillo, seleccionar todo de una entidad List<Autor> autores = session.createQuery("from Autor", Autor.class).list(); System.out.println(autores); // Podemos añadir condiciones con Where autores = session.createQuery("from Autor where idautor=6", Autor.class).list(); System.out.println(autores); // Podemos seleccionar algunas propiedades List<String> nombres = session.createQuery("select nombre from Autor", String.class).list(); System.out.println(nombres); // Podemos usar parámetros Query<Autor> query = session.createQuery("from Autor where idautor=:id", Autor.class); query.setParameter("id",6); autores=query.list(); System.out.println(autores); // Si nos fijamos después de cada query ponemos list() // Esto nos sirve para dos cosas: obtener una lista // Y, sobre todo, ejecutar la query. // Las queries son como los procedimientos preparados // No se lanzan hasta que se lo decimos
Ejercicio de trabajar con Hibernate
Por partes.
Crear un género:
Genero g=new Genero(); g.setNombre("SteamPunk"); DAO<Genero> gdao=new DAO<>(Genero.class); gdao.save(g);
Crear un libro:
DAO<Genero> gdao=new DAO<>(Genero.class); Genero g=gdao.get(8); Libro l=new Libro(); l.setTitulo("Luna cruel"); l.setPaginas(750); l.setGenero(g); DAO<Libro> ldao=new DAO<>(Libro.class); ldao.save(l);
Crear un autor
DAO<Libro> ldao=new DAO<>(Libro.class); Libro l=ldao.get(9); DAO<Autor> adao=new DAO<>(Autor.class); Autor a=new Autor(); a.setNombre("Juan Perez"); a.getLibros().add(l); adao.save(a);
Todo junto
// Todo junto DAO<Genero> gdao=new DAO<>(Genero.class); DAO<Libro> ldao=new DAO<>(Libro.class); DAO<Autor> adao=new DAO<>(Autor.class); // Creo el género Genero g=new Genero(); g.setNombre("Realismo sucio"); gdao.save(g); // Creo el libro Libro l=new Libro(); l.setTitulo("Cloacas de Barcelona"); l.setPaginas(750); // Le asigno el género que acao de crear l.setGenero(g); ldao.save(l); // Creo el autor Autor a=new Autor(); a.setNombre("Andreu Martín"); // Le añado el libro que acabo de crear a.getLibros().add(l); adao.save(a);
Autores por género.
Con un método:
package com.trifulcas.Biblioteca; import java.util.ArrayList; import java.util.List; import com.trifulcas.DAO.DAO; import com.trifulcas.models.Autor; import com.trifulcas.models.Genero; import com.trifulcas.models.Libro; public class GetAutores { public static void main(String[] args) { DAO<Genero> gdao=new DAO<>(Genero.class); Genero g=gdao.get(8); System.out.println(getAutores2(g)); System.out.println(g.getAutores()); } public static List<Autor> getAutores(Genero genero){ List<Autor> res=new ArrayList<>(); for(Libro libro:genero.getLibros()) { for(Autor autor:libro.getAutores()) { res.add(autor); } } return res; } public static List<Autor> getAutores2(Genero genero){ List<Autor> res=new ArrayList<>(); for(Libro libro:genero.getLibros()) { res.addAll(libro.getAutores()); } return res; } }
Dentro del POJO (no recomendable pero… ya se sabe 😉 )
package com.trifulcas.models; import java.util.ArrayList; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity public class Genero { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idgenero") private int idGenero; private String nombre; @OneToMany(mappedBy="genero") List<Libro> libros=new ArrayList(); public Genero() { super(); // TODO Auto-generated constructor stub } public int getIdGenero() { return idGenero; } public void setIdGenero(int idGenero) { this.idGenero = idGenero; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public List<Libro> getLibros() { return libros; } public void setLibros(List<Libro> libros) { this.libros = libros; } public List<Autor> getAutores() { List<Autor> res=new ArrayList<>(); for(Libro libro:this.getLibros()) { res.addAll(libro.getAutores()); } return res; } @Override public String toString() { return "Genero [idGenero=" + idGenero + ", nombre=" + nombre + "]"; } }
Seguimos con DAO y más
Añado la clase DAO en un paquete aparte
package com.trifulcas.DAO; import java.util.List; import org.hibernate.Session; import org.hibernate.Transaction; import com.trifulcas.hibernate.HibernateUtil; public class DAO<T> { private Class<T> entityClass; public Session session; public DAO(Class<T> clase) { this.entityClass = clase; session = HibernateUtil.getSessionFactory().openSession(); } public void save(T Objeto) { Transaction transaction = null; try { transaction = session.beginTransaction(); session.persist(Objeto); // commit transaction transaction.commit(); } catch (Exception e) { if (transaction != null) { transaction.rollback(); } e.printStackTrace(); } } public List<T> getAll() { return session.createQuery("from " + entityClass.getSimpleName(), entityClass).list(); } public T get(int id) { return session.get(entityClass, id); } public boolean delete(int id) { Transaction transaction = null; try { transaction = session.beginTransaction(); T objeto = session.get(entityClass, id); session.remove(objeto); transaction.commit(); return true; } catch (Exception ex) { System.out.println(ex.getMessage()); if (transaction != null) { transaction.rollback(); } return false; } } }
Creo la entidad Libro
package com.trifulcas.models; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; @Entity public class Libro { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idlibro") private int idLibro; private String titulo; private int paginas; @ManyToOne @JoinColumn(name="idgenero") private Genero genero; public Libro() { super(); // TODO Auto-generated constructor stub } public int getIdLibro() { return idLibro; } public void setIdLibro(int idLibro) { this.idLibro = idLibro; } public String getTitulo() { return titulo; } public void setTitulo(String titulo) { this.titulo = titulo; } public int getPaginas() { return paginas; } public void setPaginas(int paginas) { this.paginas = paginas; } public Genero getGenero() { return genero; } public void setGenero(Genero genero) { this.genero = genero; } @Override public String toString() { return "Libro [idLibro=" + idLibro + ", titulo=" + titulo + ", paginas=" + paginas + "]"; } }
Añado a Genero la anotación onetomany
package com.trifulcas.models; import java.util.ArrayList; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; @Entity public class Genero { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idgenero") private int idGenero; private String nombre; @OneToMany(mappedBy="genero") List<Libro> libros=new ArrayList(); public Genero() { super(); // TODO Auto-generated constructor stub } public int getIdGenero() { return idGenero; } public void setIdGenero(int idGenero) { this.idGenero = idGenero; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public List<Libro> getLibros() { return libros; } public void setLibros(List<Libro> libros) { this.libros = libros; } @Override public String toString() { return "Genero [idGenero=" + idGenero + ", nombre=" + nombre + "]"; } }
Lo anoto en hibernateutil
... configuration.addAnnotatedClass(Libro.class); ...
Y lo pruebo
package com.trifulcas.Biblioteca; import com.trifulcas.DAO.DAO; import com.trifulcas.models.Genero; import com.trifulcas.models.Libro; /** * Hello world! * */ public class App { public static void main( String[] args ) { try { DAO<Genero> gdao=new DAO<>(Genero.class); Genero g=gdao.get(1); System.out.println(g); System.out.println(g.getLibros()); DAO<Libro> ldao=new DAO<>(Libro.class); Libro l=ldao.get(2); System.out.println(l); System.out.println(l.getGenero()); /* * Genero sf=new Genero(); sf.setNombre("Ciencia ficción"); gdao.save(sf); */ //gdao.delete(6); } catch (Exception ex) { System.out.println(ex); } } }
Añado autor, pongo el manytomany y modifico libro para que también lo tenga
package com.trifulcas.models; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name = "autor") public class Autor { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int idautor; private String nombre; @ManyToMany(cascade= {CascadeType.MERGE}) @JoinTable(name = "libro_autor", joinColumns = { @JoinColumn(name = "idautor") }, // La de esta entidad inverseJoinColumns = { @JoinColumn(name = "idlibro") }) List<Libro> libros = new ArrayList(); // Constructor por defecto public Autor() { } // Constructor con parámetros public Autor(String nombre) { this.nombre = nombre; } // Getters y Setters public int getIdautor() { return idautor; } public void setIdautor(int idautor) { this.idautor = idautor; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public List<Libro> getLibros() { return libros; } public void setLibros(List<Libro> libros) { this.libros = libros; } // Método toString @Override public String toString() { return "Autor{" + "idautor=" + idautor + ", nombre='" + nombre + '\'' + '}'; } }
package com.trifulcas.models; import java.util.ArrayList; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; @Entity public class Libro { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idlibro") private int idLibro; private String titulo; private int paginas; @ManyToMany(mappedBy="libros") List<Autor> autores=new ArrayList(); @ManyToOne @JoinColumn(name="idgenero") private Genero genero; public Libro() { super(); // TODO Auto-generated constructor stub } public int getIdLibro() { return idLibro; } public void setIdLibro(int idLibro) { this.idLibro = idLibro; } public String getTitulo() { return titulo; } public void setTitulo(String titulo) { this.titulo = titulo; } public int getPaginas() { return paginas; } public void setPaginas(int paginas) { this.paginas = paginas; } public Genero getGenero() { return genero; } public void setGenero(Genero genero) { this.genero = genero; } public List<Autor> getAutores() { return autores; } public void setAutores(List<Autor> autores) { this.autores = autores; } @Override public String toString() { return "Libro [idLibro=" + idLibro + ", titulo=" + titulo + ", paginas=" + paginas + "]"; } }
Lo pruebo:
package com.trifulcas.Biblioteca; import com.trifulcas.DAO.DAO; import com.trifulcas.models.Autor; import com.trifulcas.models.Genero; import com.trifulcas.models.Libro; /** * Hello world! * */ public class App { public static void main(String[] args) { try { DAO<Genero> gdao = new DAO<>(Genero.class); Genero g = gdao.get(1); System.out.println(g); System.out.println(g.getLibros()); DAO<Libro> ldao = new DAO<>(Libro.class); Libro l = ldao.get(2); System.out.println(l); System.out.println(l.getGenero()); DAO<Autor> adao = new DAO<>(Autor.class); Autor a = adao.get(2); System.out.println(a); System.out.println(a.getLibros()); Libro fantasia=ldao.get(7); // Añado el libro al autor a.getLibros().add(fantasia); // Lo guardo adao.save(a); /* * Genero sf = new Genero(); * * sf.setNombre("Fantasía romántica"); * gdao.save(sf); * Libro libro=new Libro(); * libro.setTitulo("Amor en el fin del mundo"); * libro.setPaginas(200); * libro.setGenero(sf); * ldao.save(libro); */ } catch (Exception ex) { System.out.println(ex); } } }
Pasos proyecto
1.- Crear proyecto Maven (maven-archetype-quickstart)
2.- Añadir dependencias: Mysql e hibernate
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.6.15.Final</version> </dependency>
3.- Creo la clase HibernateUtil
package com.trifulcas.hibernate; import java.util.Properties; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.service.ServiceRegistry; public class HibernateUtil { private static SessionFactory sessionFactory; public static SessionFactory getSessionFactory() { if (sessionFactory == null) { try { Configuration configuration = new Configuration(); // Hibernate settings equivalent to hibernate.cfg.xml's properties Properties settings = new Properties(); settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver"); settings.put(Environment.URL, "jdbc:mysql://localhost:3306/sakila"); settings.put(Environment.USER, "root"); settings.put(Environment.PASS, ""); settings.put(Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect"); settings.put(Environment.SHOW_SQL, "true"); settings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread"); configuration.setProperties(settings); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()).build(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); } catch (Exception e) { e.printStackTrace(); } } return sessionFactory; } public static void shutdown() { // Close caches and connection pools getSessionFactory().close(); } }
4.- Pongo los datos correctos de conexión: BD, usuario y password (settings.put(Environment.URL, “jdbc:mysql://localhost:3306/biblioteca”);)
5.- Creo mi entidad
package com.trifulcas.models; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "genero") public class Genero { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idgenero") private int idGenero; private String nombre; public Genero() { super(); // TODO Auto-generated constructor stub } public int getIdGenero() { return idGenero; } public void setIdGenero(int idGenero) { this.idGenero = idGenero; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } @Override public String toString() { return "Genero [idGenero=" + idGenero + ", nombre=" + nombre + "]"; } }
6.- Lo anotamos en hibernateutil
... configuration.addAnnotatedClass(Genero.class); ...
7.- Lo pruebo:
Session session = HibernateUtil.getSessionFactory().openSession(); try { Genero g = session.get(Genero.class, 1); System.out.println(g); } catch (Exception ex) { System.out.println(ex); } session.close();
Ejercicio Hibernate Biblioteca
Vamos a hacer la siguiente BD y la vamos a implementar con Hibernate
Genero 1–N Libro N–N Autor
Genero: Nombre
Libro: Titulo, paginas
Autor: nombre
CREATE TABLE `biblioteca`.`genero` ( `idgenero` INT NOT NULL AUTO_INCREMENT, `nombre` VARCHAR(45) NULL, PRIMARY KEY (`idgenero`)); CREATE TABLE `biblioteca`.`libro` ( `idlibro` INT NOT NULL AUTO_INCREMENT, `idgenero` INT NULL, `titulo` VARCHAR(45) NULL, `paginas` INT NULL, PRIMARY KEY (`idlibro`)); CREATE TABLE `biblioteca`.`autor` ( `idautor` INT NOT NULL AUTO_INCREMENT, `nombre` VARCHAR(150) NULL, PRIMARY KEY (`idautor`)); CREATE TABLE `libro_autor` ( `idlibro_autor` int(11) NOT NULL AUTO_INCREMENT, `idlibro` int(11) DEFAULT NULL, `idautor` int(11) DEFAULT NULL, PRIMARY KEY (`idlibro_autor`), KEY `fk_libro_idx` (`idlibro`), KEY `fk_autor_idx` (`idautor`), CONSTRAINT `fk_autor` FOREIGN KEY (`idautor`) REFERENCES `autor` (`idautor`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_libro` FOREIGN KEY (`idlibro`) REFERENCES `libro` (`idlibro`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ALTER TABLE `biblioteca`.`libro` ADD INDEX `fk_genero_idx` (`idgenero` ASC) ; ; ALTER TABLE `biblioteca`.`libro` ADD CONSTRAINT `fk_genero` FOREIGN KEY (`idgenero`) REFERENCES `biblioteca`.`genero` (`idgenero`) ON DELETE NO ACTION ON UPDATE NO ACTION;
Datos de prueba
INSERT INTO `biblioteca`.`genero` (`nombre`) VALUES ('Ficción'), ('No Ficción'), ('Ciencia Ficción'), ('Fantasía'), ('Biografía'); INSERT INTO `biblioteca`.`libro` (`idgenero`, `titulo`, `paginas`) VALUES (1, 'El Gran Gatsby', 180), (2, 'Sapiens: De animales a dioses', 443), (3, 'Dune', 412), (4, 'Harry Potter y la piedra filosofal', 309), (5, 'Steve Jobs', 656); INSERT INTO `biblioteca`.`autor` (`nombre`) VALUES ('F. Scott Fitzgerald'), ('Yuval Noah Harari'), ('Frank Herbert'), ('J.K. Rowling'), ('Walter Isaacson'); INSERT INTO `libro_autor` (`idlibro`, `idautor`) VALUES (1, 1), -- El Gran Gatsby por F. Scott Fitzgerald (2, 2), -- Sapiens: De animales a dioses por Yuval Noah Harari (3, 3), -- Dune por Frank Herbert (4, 4), -- Harry Potter y la piedra filosofal por J.K. Rowling (5, 5); -- Steve Jobs por Walter Isaacson
Onetomany
package com.trifulcas.models; import java.util.Date; import java.util.List; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.persistence.Temporal; import jakarta.persistence.TemporalType; @Entity @Table(name = "city") public class City { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "city_id") private Short cityId; @Column(name = "city", nullable = false) private String city; // En la entidad de 'varios' ponemos ManyToOne @ManyToOne // Especificamos cual es la clave foránea de esta relación @JoinColumn(name = "country_id", nullable = false) // La propiedad siempre será la entidad relacionada private Country country; // Cuando recuperamos la entidad se cargan automáticamente las entidades relacionadas // Es decir, cuando yo cargo una ciudad se carga su país // Y puedo acceder a sus valores @OneToMany(mappedBy="city",cascade=CascadeType.ALL) private List<Address> addreses; @Column(name = "last_update", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") @Temporal(TemporalType.TIMESTAMP) private java.util.Date lastUpdate = new Date(); // Constructor, getters, and setters public City() { } public City(String city, Country country) { this.city = city; this.country = country; } public Short getCityId() { return cityId; } public void setCityId(Short cityId) { this.cityId = cityId; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Country getCountry() { return country; } public void setCountry(Country country) { this.country = country; } public java.util.Date getLastUpdate() { return lastUpdate; } public void setLastUpdate(java.util.Date lastUpdate) { this.lastUpdate = lastUpdate; } public List<Address> getAddreses() { return addreses; } public void setAddreses(List<Address> addreses) { this.addreses = addreses; } // Cuidado con poner country porque entramos en bucle @Override public String toString() { return "City [cityId=" + cityId + ", city=" + city + ", country="+country.getCountry()+"]"; } }
package com.trifulcas.models; import java.sql.Timestamp; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; @Entity @Table(name = "address") public class Address { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "address_id") private short addressId; @Column(name = "address", nullable = false, length = 50) private String address; @Column(name = "address2", length = 50) private String address2; @Column(name = "district", nullable = false, length = 20) private String district; @ManyToOne @JoinColumn(name="city_id") private City city; @Column(name = "postal_code", length = 10) private String postalCode; @Column(name = "phone", nullable = false, length = 20) private String phone; @Column(name = "last_update", nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private Timestamp lastUpdate; // Getters and Setters public short getAddressId() { return addressId; } public void setAddressId(short addressId) { this.addressId = addressId; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getAddress2() { return address2; } public void setAddress2(String address2) { this.address2 = address2; } public String getDistrict() { return district; } public void setDistrict(String district) { this.district = district; } public City getCity() { return city; } public void setCity(City city) { this.city = city; } public String getPostalCode() { return postalCode; } public void setPostalCode(String postalCode) { this.postalCode = postalCode; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public Timestamp getLastUpdate() { return lastUpdate; } public void setLastUpdate(Timestamp lastUpdate) { this.lastUpdate = lastUpdate; } @Override public String toString() { return "Address [addressId=" + addressId + ", address=" + address + ", address2=" + address2 + ", district=" + district + ", city=" + city + ", postalCode=" + postalCode + ", phone=" + phone + ", lastUpdate=" + lastUpdate + "]"; } }
No olvideis anotar en HibernateUtil:
... configuration.addAnnotatedClass(Address.class); ...
Ejercicio Colección de funkos
Mi hija quiere hacer una base de datos para guardar su colección de funkos. Los funkos están organizados en colecciones, que tienen un nombre de la colección y el nombre del diseñador. Un funko solo pertenece a una colección. De cada funko queremos guardar el Nombre, Precio, Número,Estilo, Fecha de lanzamiento y Tamaño.
La mayoría de los funkos son de productos audiovisuales (series, películas…). Nos interesa conocer el título de ese producto, la fecha de emisión, la nacionalidad y el número de temporadas.
coleccion
———-
idcoleccion int
nombre varchar(150)
disenyador varchar(150)
funko
—–
idfunko int
idcoleccion int
idaudiovisual int
nombre varchar(150)
precio decimal
numero smallint
estilo varchar(150)
lanzamiento date
tamanyo varchar
audiovisual
———–
idaudiovisual int
titulo varchar(150)
emision date
nacionalidad varchar(150)
temporadas smallint
CREATE TABLE `coleccion` ( `idcoleccion` int(10) unsigned NOT NULL AUTO_INCREMENT, `nombre` varchar(150) DEFAULT NULL, `disenyador` varchar(150) DEFAULT NULL, PRIMARY KEY (`idcoleccion`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; CREATE TABLE `audiovisual` ( `idaudiovisual` int(10) unsigned NOT NULL AUTO_INCREMENT, `titulo` varchar(150) DEFAULT NULL, `emision` date DEFAULT NULL, `nacionalidad` varchar(150) DEFAULT NULL, `temporadas` smallint(6) DEFAULT NULL, PRIMARY KEY (`idaudiovisual`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; CREATE TABLE `funko` ( `idfunko` int(10) unsigned NOT NULL AUTO_INCREMENT, `idcoleccion` int(11) unsigned DEFAULT NULL, `idaudiovisual` int(11) unsigned DEFAULT NULL, `nombre` varchar(150) DEFAULT NULL, `precio` decimal(8,2) DEFAULT NULL, `numero` smallint(6) DEFAULT NULL, `estilo` varchar(150) DEFAULT NULL, `lanzamiento` date DEFAULT NULL, `tamanyo` varchar(150) DEFAULT NULL, PRIMARY KEY (`idfunko`), KEY `fk_coleccion_idx` (`idcoleccion`), KEY `fk_audiovisual_idx` (`idaudiovisual`), CONSTRAINT `fk_audiovisual` FOREIGN KEY (`idaudiovisual`) REFERENCES `audiovisual` (`idaudiovisual`) ON UPDATE NO ACTION, CONSTRAINT `fk_coleccion` FOREIGN KEY (`idcoleccion`) REFERENCES `coleccion` (`idcoleccion`) ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
Datos de prueba:
INSERT INTO `coleccion` (`nombre`, `disenyador`) VALUES ('Star Wars: Original Trilogy', 'John Doe'), ('Marvel Avengers', 'Jane Smith'), ('Harry Potter', 'Robert Brown'), ('Game of Thrones', 'Emily White'), ('The Walking Dead', 'Michael Green'), ('Disney Classics', 'Sarah Black'), ('DC Comics Superheroes', 'Thomas Blue'), ('Stranger Things', 'Olivia Purple'), ('Rick and Morty', 'Daniel Red'), ('The Simpsons', 'Jessica Pink'), ('Dragon Ball Z', 'Matthew Yellow'), ('Naruto Shippuden', 'Sophia Orange'), ('One Piece', 'James Violet'), ('Pokemon', 'Emma Indigo'), ('Lord of the Rings', 'Christopher Teal'), ('The Office', 'Isabella Grey'), ('Friends', 'Benjamin Azure'), ('My Hero Academia', 'Mia Lime'), ('Overwatch', 'Elijah Olive'), ('Fortnite', 'Charlotte Cyan'); INSERT INTO `audiovisual` (`titulo`, `emision`, `nacionalidad`, `temporadas`) VALUES ('Breaking Bad', '2008-01-20', 'USA', 5), ('Stranger Things', '2016-07-15', 'USA', 4), ('Game of Thrones', '2011-04-17', 'USA', 8), ('Narcos', '2015-08-28', 'USA', 3), ('The Crown', '2016-11-04', 'UK', 4), ('La Casa de Papel', '2017-05-02', 'Spain', 5), ('Dark', '2017-12-01', 'Germany', 3), ('Money Heist', '2017-05-02', 'Spain', 5), ('The Mandalorian', '2019-11-12', 'USA', 2), ('The Witcher', '2019-12-20', 'USA', 2), ('Friends', '1994-09-22', 'USA', 10), ('The Office', '2005-03-24', 'USA', 9), ('Sherlock', '2010-07-25', 'UK', 4), ('Black Mirror', '2011-12-04', 'UK', 5), ('The Simpsons', '1989-12-17', 'USA', 32), ('Rick and Morty', '2013-12-02', 'USA', 5), ('Naruto Shippuden', '2007-02-15', 'Japan', 21), ('One Piece', '1999-10-20', 'Japan', 20), ('Dragon Ball Z', '1989-04-26', 'Japan', 9), ('Attack on Titan', '2013-04-07', 'Japan', 4); INSERT INTO `funko` (`idcoleccion`, `idaudiovisual`, `nombre`, `precio`, `numero`, `estilo`, `lanzamiento`, `tamanyo`) VALUES (1, 3, 'Darth Vader', 12.99, 1, 'Vinyl', '2018-05-04', 'Standard'), (1, 3, 'Luke Skywalker', 12.99, 2, 'Vinyl', '2018-05-04', 'Standard'), (2, 10, 'Iron Man', 14.99, 3, 'Vinyl', '2019-04-26', 'Standard'), (2, 10, 'Captain America', 14.99, 4, 'Vinyl', '2019-04-26', 'Standard'), (3, 7, 'Harry Potter', 11.99, 5, 'Vinyl', '2017-07-31', 'Standard'), (3, 7, 'Hermione Granger', 11.99, 6, 'Vinyl', '2017-07-31', 'Standard'), (4, 2, 'Jon Snow', 13.99, 7, 'Vinyl', '2019-04-14', 'Standard'), (4, 2, 'Daenerys Targaryen', 13.99, 8, 'Vinyl', '2019-04-14', 'Standard'), (5, 1, 'Rick Grimes', 10.99, 9, 'Vinyl', '2018-10-07', 'Standard'), (5, 1, 'Daryl Dixon', 10.99, 10, 'Vinyl', '2018-10-07', 'Standard'), (6, 19, 'Mickey Mouse', 9.99, 11, 'Vinyl', '2019-11-18', 'Standard'), (6, 19, 'Donald Duck', 9.99, 12, 'Vinyl', '2019-11-18', 'Standard'), (7, 11, 'Batman', 12.99, 13, 'Vinyl', '2019-03-01', 'Standard'), (7, 11, 'Superman', 12.99, 14, 'Vinyl', '2019-03-01', 'Standard'), (8, 2, 'Eleven', 14.99, 15, 'Vinyl', '2019-07-04', 'Standard'), (8, 2, 'Jim Hopper', 14.99, 16, 'Vinyl', '2019-07-04', 'Standard'), (9, 17, 'Rick', 13.49, 17, 'Vinyl', '2020-09-20', 'Standard'), (9, 17, 'Morty', 13.49, 18, 'Vinyl', '2020-09-20', 'Standard'), (10, 12, 'Homer Simpson', 11.49, 19, 'Vinyl', '2019-09-29', 'Standard'), (10, 12, 'Bart Simpson', 11.49, 20, 'Vinyl', '2019-09-29', 'Standard'), (11, 14, 'Goku', 12.49, 21, 'Vinyl', '2018-11-18', 'Standard'), (11, 14, 'Vegeta', 12.49, 22, 'Vinyl', '2018-11-18', 'Standard'), (12, 16, 'Naruto Uzumaki', 13.99, 23, 'Vinyl', '2019-02-15', 'Standard'), (12, 16, 'Sasuke Uchiha', 13.99, 24, 'Vinyl', '2019-02-15', 'Standard'), (13, 18, 'Monkey D. Luffy', 14.49, 25, 'Vinyl', '2020-05-20', 'Standard'), (13, 18, 'Roronoa Zoro', 14.49, 26, 'Vinyl', '2020-05-20', 'Standard'), (14, 15, 'Pikachu', 9.99, 27, 'Vinyl', '2019-07-06', 'Standard'), (14, 15, 'Charmander', 9.99, 28, 'Vinyl', '2019-07-06', 'Standard'), (15, 5, 'Frodo Baggins', 11.99, 29, 'Vinyl', '2018-12-19', 'Standard'), (15, 5, 'Gandalf', 11.99, 30, 'Vinyl', '2018-12-19', 'Standard'), (16, 8, 'Michael Scott', 10.99, 31, 'Vinyl', '2019-10-07', 'Standard'), (16, 8, 'Dwight Schrute', 10.99, 32, 'Vinyl', '2019-10-07', 'Standard'), (17, 9, 'Rachel Green', 11.99, 33, 'Vinyl', '2019-05-01', 'Standard'), (17, 9, 'Ross Geller', 11.99, 34, 'Vinyl', '2019-05-01', 'Standard'), (18, 4, 'Izuku Midoriya', 14.99, 35, 'Vinyl', '2020-03-15', 'Standard'), (18, 4, 'Katsuki Bakugo', 14.99, 36, 'Vinyl', '2020-03-15', 'Standard'), (19, 13, 'Tracer', 12.99, 37, 'Vinyl', '2019-10-10', 'Standard'), (19, 13, 'Reaper', 12.99, 38, 'Vinyl', '2019-10-10', 'Standard'), (20, 6, 'Jonesy', 11.49, 39, 'Vinyl', '2019-06-05', 'Standard'), (20, 6, 'Raven', 11.49, 40, 'Vinyl', '2019-06-05', 'Standard'), (1, 3, 'Boba Fett', 14.99, 41, 'Vinyl', '2019-12-05', 'Standard'), (1, 3, 'Princess Leia', 14.99, 42, 'Vinyl', '2019-12-05', 'Standard'), (2, 10, 'Thor', 15.99, 43, 'Vinyl', '2020-02-20', 'Standard'), (2, 10, 'Hulk', 15.99, 44, 'Vinyl', '2020-02-20', 'Standard'), (3, 7, 'Ron Weasley', 11.99, 45, 'Vinyl', '2018-08-31', 'Standard'), (3, 7, 'Albus Dumbledore', 11.99, 46, 'Vinyl', '2018-08-31', 'Standard'), (4, 2, 'Tyrion Lannister', 13.99, 47, 'Vinyl', '2018-03-25', 'Standard'), (4, 2, 'Arya Stark', 13.99, 48, 'Vinyl', '2018-03-25', 'Standard'), (5, 1, 'Michonne', 10.99, 49, 'Vinyl', '2017-04-06', 'Standard'), (5, 1, 'Negan', 10.99, 50, 'Vinyl', '2017-04-06', 'Standard');
Ejemplo modificar datos:
UPDATE `funko` SET `estilo` = 'Metallic' WHERE `idfunko` = 1; UPDATE `funko` SET `estilo` = 'Glow in the Dark' WHERE `idfunko` = 2; UPDATE `funko` SET `estilo` = 'Flocked' WHERE `idfunko` = 3; UPDATE `funko` SET `estilo` = 'Diamond' WHERE `idfunko` = 4; UPDATE `funko` SET `estilo` = 'Chrome' WHERE `idfunko` = 5; UPDATE `funko` SET `estilo` = 'Pearlescent' WHERE `idfunko` = 6; UPDATE `funko` SET `estilo` = 'Translucent' WHERE `idfunko` = 7; UPDATE `funko` SET `estilo` = 'Glitter' WHERE `idfunko` = 8; UPDATE `funko` SET `estilo` = 'Wooden' WHERE `idfunko` = 9; UPDATE `funko` SET `estilo` = '8-Bit' WHERE `idfunko` = 10; UPDATE `funko` SET `estilo` = 'Retro' WHERE `idfunko` = 11; UPDATE `funko` SET `estilo` = 'Vintage' WHERE `idfunko` = 12; UPDATE `funko` SET `estilo` = 'Chibi' WHERE `idfunko` = 13; UPDATE `funko` SET `estilo` = 'Pixel' WHERE `idfunko` = 14; UPDATE `funko` SET `estilo` = 'Steampunk' WHERE `idfunko` = 15; UPDATE `funko` SET `estilo` = 'Graffiti' WHERE `idfunko` = 16; UPDATE `funko` SET `estilo` = 'Art Series' WHERE `idfunko` = 17; UPDATE `funko` SET `estilo` = 'Metallic Gold' WHERE `idfunko` = 18; UPDATE `funko` SET `estilo` = 'Bronze' WHERE `idfunko` = 19; UPDATE `funko` SET `estilo` = 'Silver' WHERE `idfunko` = 20; UPDATE `funko` SET `tamanyo` = 'Large' WHERE `idfunko` = 1; UPDATE `funko` SET `tamanyo` = 'Small' WHERE `idfunko` = 2; UPDATE `funko` SET `tamanyo` = 'Mini' WHERE `idfunko` = 3; UPDATE `funko` SET `tamanyo` = 'Jumbo' WHERE `idfunko` = 4; UPDATE `funko` SET `tamanyo` = 'Super Sized' WHERE `idfunko` = 5; UPDATE `funko` SET `tamanyo` = 'Pocket' WHERE `idfunko` = 6; UPDATE `funko` SET `tamanyo` = 'Mega' WHERE `idfunko` = 7; UPDATE `funko` SET `tamanyo` = 'Giant' WHERE `idfunko` = 8; UPDATE `funko` SET `tamanyo` = 'Titan' WHERE `idfunko` = 9; UPDATE `funko` SET `tamanyo` = 'Colossal' WHERE `idfunko` = 10; UPDATE `funko` SET `tamanyo` = 'Compact' WHERE `idfunko` = 11; UPDATE `funko` SET `tamanyo` = 'Petite' WHERE `idfunko` = 12; UPDATE `funko` SET `tamanyo` = 'Grand' WHERE `idfunko` = 13; UPDATE `funko` SET `tamanyo` = 'Tiny' WHERE `idfunko` = 14; UPDATE `funko` SET `tamanyo` = 'Massive' WHERE `idfunko` = 15; UPDATE `funko` SET `tamanyo` = 'Huge' WHERE `idfunko` = 16; UPDATE `funko` SET `tamanyo` = 'Enormous' WHERE `idfunko` = 17; UPDATE `funko` SET `tamanyo` = 'Oversized' WHERE `idfunko` = 18; UPDATE `funko` SET `tamanyo` = 'Immense' WHERE `idfunko` = 19; UPDATE `funko` SET `tamanyo` = 'Gargantuan' WHERE `idfunko` = 20; UPDATE `funko` SET `estilo` = 'Diamond' WHERE `idfunko` between 20 and 25; UPDATE `funko` SET `estilo` = 'Glitter' WHERE `idfunko` between 25 and 30; UPDATE `funko` SET `estilo` = 'Steampunk' WHERE `idfunko` between 30 and 40; UPDATE `funko` SET `estilo` = 'Metallic' WHERE `idfunko` >40; UPDATE `funko` SET `tamanyo` = 'Small' WHERE `idfunko` between 20 and 25; UPDATE `funko` SET `tamanyo` = 'Compact' WHERE `idfunko` between 25 and 30; UPDATE `funko` SET `tamanyo` = 'Large' WHERE `idfunko` between 30 and 40; UPDATE `funko` SET `tamanyo` = 'Oversized' WHERE `idfunko`>40;
Consultas
-- Consultas con condiciones simples -- audiovisuales con más de 5 temporadas select * from audiovisual where temporadas>5; -- funkos que tengan una 'h' en el nombre select * from funko where nombre like '%h%'; -- colecciones de diseñadores cuyo nombre empiece por 'M' select * from coleccion where disenyador like 'm%'; -- Consultas con joins -- Todos los funkos de la colección 'friends' select funko.* from coleccion join funko on coleccion.idcoleccion=funko.idcoleccion where coleccion.nombre='friends'; -- Todos los funkos del audiovisual 'one piece' select funko.* from audiovisual join funko on audiovisual.idaudiovisual=funko.idaudiovisual where titulo='one piece'; -- Todos los funkos de la colección o el audiovisual 'friends' select f.* from funko f join coleccion c on f.idcoleccion=c.idcoleccion join audiovisual a on f.idaudiovisual=a.idaudiovisual where c.nombre='friends' or a.titulo='friends'; -- Consultas agrupadas -- Total de funkos por colección select coleccion.*, count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion; -- Total de funkos por audiovisual select audiovisual.*, count(idfunko) total from audiovisual join funko using(idaudiovisual) group by idaudiovisual; -- Total de funkos por estilos ordenados de mayor a menor select estilo,count(idfunko) total from funko group by estilo order by total desc, estilo desc; -- Media de precio de todos los funkos select avg(precio) from funko; -- Total de precios (suma) por tamaño select tamanyo,sum(precio) total from funko group by tamanyo; -- Colecciones con más de 10 funkos (no sé si hay) select coleccion.*, count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion having total>=4; -- Subconsultas y división -- Coleccion (o colecciones) con mayor número de funkos select coleccion.*, count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion having total=(maximo); select max(total) total from ( select count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion) foo; select count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion order by total desc limit 1 ; -- Junto la primera con alguna de las segundas y voila select coleccion.*, count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion having total=(select count(idfunko) total from coleccion left join funko using(idcoleccion) group by idcoleccion order by total desc limit 1); -- Lo mismo para audiovisual select audiovisual.*, count(idfunko) total from audiovisual left join funko using(idaudiovisual) group by idaudiovisual having total=(select count(idfunko) total from audiovisual left join funko using(idaudiovisual) group by idaudiovisual order by total desc limit 1); -- Funkos cuyo precio esté por encima de la media -- calculo la media select avg(precio) from funko; select * from funko where precio>(select avg(precio) from funko); -- Consultas con funciones -- Todos los funkos lanzados en febrero select * from funko where month(lanzamiento)=2; -- Total de funkos por año select year(lanzamiento) anyo,count(idfunko) total from funko group by year(lanzamiento); -- Funkos cuyo nombre tenga una longitud mayor de 12 letras select * from funko where length(nombre)>12; -- Funkos lanzados en 2020 o cuyo audiovisual se emitió en 2020 select * from funko join audiovisual on funko.idaudiovisual=audiovisual.idaudiovisual where year(lanzamiento)=2020 or year(emision)=2020;