Implementando Hibernate con Spring Boot y PostgreSQL

    Introducci贸n

    A medida que el uso de software se vuelve m谩s com煤n y se construyen m谩s y m谩s sistemas para manejar diversas tareas, los datos juegan un papel m谩s importante en la escena tecnol贸gica actual y futura. La informaci贸n es cada vez m谩s valiosa a medida que avanza la tecnolog铆a y abre m谩s oportunidades para su uso.

    Es por esta raz贸n, y muchas m谩s, que el almacenamiento seguro y la manipulaci贸n de datos se han convertido en un aspecto importante de cualquier sistema o aplicaci贸n que se construya.

    驴Qu茅 es el mapeo relacional de objetos?

    En muchos sistemas, los objetos de la vida real se modelan como objetos en sistemas para facilitar la representaci贸n y manipulaci贸n de sus atributos. Por ejemplo, un tel茅fono se puede modelar como un objeto con atributos como su nombre, sistema operativo, fabricante y mucho m谩s como sus atributos y esto se puede manipular y almacenar f谩cilmente en una base de datos.

    El mapeo relacional de objetos (ORM) es una t茅cnica de mapeo de dichos objetos y sus atributos en la base de datos a trav茅s de mapeadores relacionales de objetos. Esta t茅cnica tambi茅n nos ayuda a convertir datos entre sistemas incompatibles utilizando aplicaciones de programaci贸n orientadas a objetos.

    Un ORM es una biblioteca que nos ayuda a interactuar con m煤ltiples bases de datos o sistemas f谩cilmente utilizando nuestro idioma de elecci贸n. Nuestro c贸digo ahora est谩 asignado al lenguaje de consulta espec铆fico de las bases de datos.

    Normalmente, necesitamos usar un lenguaje espec铆fico de base de datos para interactuar con una base de datos. Por ejemplo, para interactuar con un MySQL base de datos, necesitamos utilizar el lenguaje de consulta estructurado (SQL), pero estos lenguajes pueden diferir de una plataforma a otra.

    Por ejemplo, si bien siguen siendo similares, la sintaxis en un Postgres La base de datos es diferente del lenguaje de consulta utilizado en un Microsoft SQL base de datos. Un ORM ayuda a salvar esa diferencia y conecta nuestro software a diferentes sistemas de bases de datos con facilidad.

    Otros beneficios de usar un ORM incluyen acelerar el proceso de desarrollo, ya que los desarrolladores no tienen que escribir el c贸digo de acceso a la base de datos y repetirlo cada vez que quieran acceder a una base de datos. Una vez que se dise帽a un modelo y se escribe el c贸digo de manipulaci贸n, no es necesario volver a hacerlo, lo que hace que el c贸digo sea f谩cil de actualizar, mantener y reutilizar.

    Sin embargo, existen algunos inconvenientes asociados con los ORM e incluyen:

    • Los ORM tienden a ser lentos en algunas situaciones en cuanto al rendimiento.
    • Para consultas complejas como uniones, los ORM a veces no pueden sustituir las consultas SQL sin procesar
    • Debido a las abstracciones introducidas por un ORM, el desarrollador puede perder la comprensi贸n de SQL y c贸mo se logra la administraci贸n de la base de datos entre bastidores.

    Hibernar

    Hibernar es un marco que permite a los desarrolladores conservar f谩cilmente los datos de la aplicaci贸n en bases de datos relacionales utilizando JDBC. Es una implementaci贸n de la API de persistencia de Java (JPA), lo que significa que se puede utilizar en cualquier sistema que admita JPA, como la edici贸n est谩ndar (Java SE) y la edici贸n empresarial (Java EE).

    Hibernate es una herramienta ligera y de c贸digo abierto que simplifica la creaci贸n, manipulaci贸n y acceso de datos desde una base de datos en aplicaciones basadas en Java. Funciona mapeando un objeto creado a partir de una clase Java y sus atributos a los datos almacenados en la base de datos.

    Algunas ventajas de usar Hibernate incluyen:

    • Es de c贸digo abierto y liviano, lo que significa que es de uso gratuito y tiene una comunidad de colaboradores que lo mejoran constantemente.
    • Hibernate utiliza un cach茅 internamente que mejora su rendimiento
    • Es independiente de la base de datos, lo que significa que se puede utilizar para acceder y manipular datos en varias bases de datos diferentes.
    • Proporciona la funcionalidad para simplificar las combinaciones cuando se obtienen datos de varias tablas.
    • Al crear tablas autom谩ticamente, el desarrollador puede concentrarse en hacer otra l贸gica
    • Es un marco estable que existe desde hace 18 a帽os.

    Alternativas

    Hibernate no es el 煤nico marco ORM que podemos usar en nuestras aplicaciones Java, otros incluyen:

    • JOOQ (Consulta orientada a objetos de Java) es una biblioteca ligera de software de mapeo de bases de datos
    • JDBI proporciona acceso a datos relacionales en Java de una manera conveniente
    • MyBatis es un marco mapeador SQL para integrar bases de datos relacionales
    • Ebean que se puede utilizar para aplicaciones basadas en Java y Kotlin
    • ORMLite que es un marco ligero para persistir objetos Java en bases de datos SQL

    Estas son solo algunas de las alternativas para Hibernate, definitivamente hay incluso m谩s bibliotecas y marcos que se adaptan a muchos escenarios y bases de datos diferentes.

    Implementando Hibernate con Spring Boot

    Configuraci贸n del proyecto

    Para este proyecto de demostraci贸n, usaremos una base de datos PostgreSQL y se pueden encontrar instrucciones de instalaci贸n. Aqu铆 para plataformas Mac OS, Linux y Windows.

    Una vez configurado, podemos crear nuestra base de datos de demostraci贸n, phonesdemo. PgAdmin proporciona una interfaz de usuario para interactuar con una base de datos PostgreSQL, pero tambi茅n se puede utilizar una terminal.

    Veamos ahora a Hibernate en acci贸n us谩ndolo en una API Spring Boot de muestra, que arrancaremos usando el Spring Initializr herramienta:

    Usaremos Java 8 y Maven para nuestra gesti贸n de dependencias con algunas dependencias:

    • Spring Web Starter para ayudarnos a crear una aplicaci贸n basada en web
    • Spring Data JPA para proporcionar la API de acceso a datos que utilizar谩 Hibernate
    • H2 Database para incorporar la funcionalidad de Hibernate a nuestro proyecto
    • PostgreSQL para permitirnos conectarnos a una base de datos PostgreSQL

    Una vez que hagamos clic en “Generar”, recibiremos un archivo zip que contiene el proyecto y podemos comenzar a implementar la aplicaci贸n web que requiere una base de datos. Una vez que descomprimimos este archivo zip en nuestra carpeta de trabajo, podemos probar que est谩 listo para trabajar ejecutando el comando:

    $ mvn spring-boot:run
    

    Implementaci贸n

    Modifiquemos nuestro application.properties para incluir los detalles de nuestra base de datos:

    # Database Properties
    spring.datasource.url=jdbc:postgresql://localhost:5432/phonesdemo
    spring.datasource.username=postgres
    spring.datasource.password=
    
    # Hibernate Properties
    # The SQL dialect makes Hibernate generate better SQL for the chosen database
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL92Dialect
    
    # Hibernate ddl auto (create, create-drop, validate, update)
    spring.jpa.hibernate.ddl-auto=update
    

    Hibernate proporciona una consola H2 que podemos usar para verificar el estado de la base de datos e incluso realizar la entrada de datos a trav茅s de una interfaz de usuario. Lo habilitamos agregando la siguiente l铆nea a nuestro application.properties:

    spring.h2.console.enabled=true
    

    Luego iniciamos nuestra aplicaci贸n y navegamos a http://localhost:8080/h2-console para probar si todo est谩 funcionando. Obtenemos una p谩gina donde podemos probar si la conexi贸n a nuestra base de datos funciona:

    Para el men煤 desplegable de configuraciones guardadas, elegiremos Generic PostgreSQL y tambi茅n actualizaremos la URL de JDBC para que coincida con el nombre de nuestra base de datos de prueba. Luego, completamos el nombre de usuario y la contrase帽a de nuestra base de datos y hacemos clic en “Probar conexi贸n” solo para asegurarnos de que nuestra aplicaci贸n Spring pueda conectarse a nuestra base de datos. Si todo est谩 bien configurado, recibimos un mensaje de 茅xito.

    Si hacemos clic en “Conectar”, obtenemos esta p谩gina:

    Aqu铆 podemos navegar por nuestra base de datos e incluso realizar consultas SQL.

    La API que crearemos se utilizar谩 para almacenar y manipular tel茅fonos y sus atributos, como el nombre y el sistema operativo. Con nuestra base de datos instalada y conectada, creemos una clase de entidad (Phone.java) que mapear谩 los atributos de nuestro objeto a la base de datos y nos permitir谩 realizar operaciones CRUD en la base de datos:

    // Imports truncated for brevity, refer to GitHub link below for the full code
    
    @Entity
    @Table(name = "phones")
    @EntityListeners(AuditingEntityListener.class)
    public class Phone {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private long id; // Each phone will be given an auto-generated unique identifier when stored
    
        @Column(name = "phone_name", nullable = false)
        private String phoneName; // Save the name of the phone
    
        @Column(name = "os", nullable = false)
        private String os; // Save the operating system running in the phone
        
        // Standard getters and setters
    }
    

    los @Entity La anotaci贸n le dice a Hibernate que esta clase representa una entidad que debe persistir.

    los @Table La anotaci贸n se utiliza para nombrar la tabla. Si se omite esta anotaci贸n, la tabla simplemente usar谩 el nombre de la clase / entidad.

    Similarmente el @Column Las anotaciones tambi茅n se pueden omitir, pero las columnas de la base de datos usar谩n los nombres de campo tal como est谩n, y algunas veces este no es el comportamiento preferido ya que los nombres de sus columnas pueden ser may煤sculas y min煤sculas y los nombres de campos son may煤sculas y min煤sculas, por ejemplo.

    Cuando guardamos este archivo y reiniciamos nuestro servidor y verificamos nuestra base de datos, habr谩 una nueva tabla llamada phones y las columnas de id, phone_namey os estar谩 presente.

    No habr谩 datos, pero esto es Hibernate en funcionamiento, si la tabla especificada en la clase de entidad no existe, Hibernate la crear谩 por nosotros.

    Implementemos ahora el controlador para ayudarnos a realizar operaciones en nuestra base de datos a trav茅s de una API:

    @RestController
    @RequestMapping("/api/v1")
    public class PhoneController {
        @Autowired
        private PhoneRepository phoneRepository;
    
        // GET method to fetch all phones
        @GetMapping("/phones")
        public List<Phone> getAllPhones() {
            return phoneRepository.findAll();
        }
    
        // GET method to fetch phone by Id
        @GetMapping("/phones/{id}")
        public ResponseEntity<Phone> getPhoneById(@PathVariable(value = "id") Long phoneId)
            throws Exception {
            Phone phone = phoneRepository.findById(phoneId)
                   .orElseThrow(() -> new Exception("Phone " + phoneId + " not found"));
            return ResponseEntity.ok().body(phone);
        }
      
        // POST method to create a phone
        @PostMapping("/phones")
        public Phone createPhone(@Valid @RequestBody Phone phone) {
            return phoneRepository.save(phone);
        }
      
        // PUT method to update a phone's details
        @PutMapping("/phones/{id}")
        public ResponseEntity<Phone> updatePhone(
            @PathVariable(value="id") Long phoneId, @Valid @RequestBody Phone phoneDetails
        ) throws Exception {
            Phone phone = phoneRepository.findById(phoneId)
                .orElseThrow(() -> new Exception("Phone " + phoneId + " not found"));
    
            phone.setPhoneName(phoneDetails.getPhoneName());
            phone.setOs(phoneDetails.getOs());
    
            final Phone updatedPhone = phoneRepository.save(phone);
            return ResponseEntity.ok(updatedPhone);
        }
      
        // DELETE method to delete a phone
        @DeleteMapping("/phone/{id}")
        public Map<String, Boolean> deletePhone(@PathVariable(value="id") Long phoneId) throws Exception {
            Phone phone = phoneRepository.findById(phoneId)
                .orElseThrow(() -> new Exception("Phone " + phoneId + " not found"));
    
            phoneRepository.delete(phone);
            Map<String, Boolean> response = new HashMap<>();
            response.put("deleted", Boolean.TRUE);
            return response;
        }
    }
    

    En nuestra clase de controlador, anotamos nuestra clase por @RestController para indicar que esta es la clase de controlador de solicitudes que manejar谩 la funcionalidad REST para nuestra API. Luego definimos m茅todos para manejar cada una de las cuatro operaciones RESTful: GET, POST, PUTy DELETE. Estos m茅todos nos proporcionar谩n una interfaz para interactuar con nuestra API y administrar datos.

    Nuestra API, a su vez, utilizar谩 Hibernate para reflejar nuestras operaciones en dichos datos en nuestra base de datos.

    Comencemos creando un solo tel茅fono a trav茅s de nuestra API:

    Obtenemos la respuesta de nuestra API, pero verifiquemos la base de datos usando la Consola H2 para confirmar:

    Como puede ver, en la captura de pantalla anterior, para obtener los datos en nuestra base de datos, usamos el comando SQL SELECT * FROM phones. Para lograr lo mismo en nuestro c贸digo a trav茅s del ORM, es tan simple como usar la l铆nea:

    phoneRepository.findAll();
    

    Esto es m谩s amigable y familiar para nosotros ya que se logra en el mismo idioma que estamos usando mientras implementamos el resto de nuestro proyecto.

    Conclusi贸n

    Hemos creado con 茅xito un objeto de tel茅fono y hemos guardado sus atributos en nuestra base de datos PostgreSQL usando Hibernate en nuestra API Spring Boot. Podemos agregar m谩s tel茅fonos, eliminar tel茅fonos y actualizar los datos del tel茅fono interactuando con la API e Hibernate reflejar谩 los cambios en nuestra base de datos.

    Hibernate nos ha facilitado interactuar con una base de datos desde nuestra aplicaci贸n Spring Boot y administrar nuestros datos. El tiempo de desarrollo tambi茅n se ha reducido significativamente ya que no tenemos que escribir los comandos SQL para administrar los datos nosotros mismos.

    El c贸digo fuente de este proyecto est谩 disponible aqu铆 en GitHub.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *