Impact on using Spring Data native query @Query to Persistence Context?

Using Spring Data’s @Query annotation with native SQL queries can have several impacts on Hibernate or JPA persistence context:

Bypassing JPQL Translation: When you use a native SQL query with @Query, you bypass JPQL (Java Persistence Query Language) translation. This means that the query is written in the native SQL dialect of the underlying database, rather than in JPQL, which is database agnostic. While this can provide more flexibility in complex queries or when leveraging database-specific features, it also ties your application more tightly to the underlying database, potentially reducing portability.

Direct Interaction with Database: Native queries bypass the entity manager’s persistence context, as they don’t involve managed entities directly. This means that Hibernate or JPA typically not manage the entities returned by a native query. As a result, changes to these entities won’t be automatically synchronized with the database unless you manually manage them using entity manager operations.

Performance Considerations: Native queries might offer performance benefits in certain cases, especially when dealing with complex queries or when JPQL is not sufficient to express the logic efficiently. However, they also come with potential drawbacks such as decreased portability and increased maintenance complexity.

Mapping to Entities: While native queries return results in the form of arrays or lists of objects, you can still map these results to entities manually if needed. However, this requires additional code for mapping the columns returned by the native query to the fields of your entity classes.

Security Risks: Using native queries opens up potential security risks such as SQL injection if the queries involve user input. You need to be careful to properly sanitize and validate any user-provided parameters before incorporating them into native queries to prevent such vulnerabilities.

Testing and Maintenance: Native queries can make your code harder to test and maintain, especially when compared to JPQL queries. Since JPQL queries are language agnostic and are validated by JPA providers during application startup, they offer better compile-time safety and easier refactoring.

In summary, while native queries can be powerful and useful in certain scenarios, they should be used judiciously, considering the trade-offs in terms of performance, portability, security, and maintenance complexity. It’s often preferable to use JPQL queries where possible and resort to native queries only when necessary for performance optimization or when dealing with database-specific features.

Do we need to explicitly call save() method in Hibernate or JPA to save entities?

No, you typically don’t need to explicitly call the save() method in Hibernate or JPA to save entities. In JPA, when you modify a managed entity (an entity that was retrieved or persisted by the entity manager), the changes are automatically synchronized with the database when the transaction commits. Hibernate, being an implementation of JPA, follows this behavior.

Here’s how it generally works:

  1. Persisting new entities: When you create a new entity object and persist it using EntityManager.persist() (or Session.save() in Hibernate), the entity becomes managed by the persistence context. Any changes made to this entity within the scope of the transaction will be automatically synchronized with the database upon transaction commit.
    entityManager.persist(entity);
    
  2. Updating existing entities: When you retrieve an entity from the database (either by EntityManager.find() or through a query), any changes made to this managed entity will also be synchronized with the database upon transaction commit. You don’t need to call any explicit save method.
    Entity entity = entityManager.find(Entity.class, id);
    entity.setSomeProperty(newValue);
    // Changes to 'entity' are automatically synchronized with the database upon transaction commit
    
  3. Automatic dirty checking: Hibernate/JPA employs the concept of dirty checking. It tracks the changes made to managed entities within a transaction. When the transaction commits, it automatically detects the changes and synchronizes them with the database.
    // Entity retrieved and modified within a transaction
    Entity entity = entityManager.find(Entity.class, id);
    entity.setSomeProperty(newValue);
    // Changes to 'entity' are automatically tracked and synchronized with the database upon transaction commit
    

Explicitly calling save() might be necessary in specific cases where you’re dealing with detached entities (entities that are not managed by the persistence context) or if you’re operating outside a transaction boundary, but in general usage within a transaction, it’s not required.

How do I delete entity object in JPA?

The following code example show you how to delete or remove entity object from database using JPA. The first class that we are going to create is ArtistDaoImpl which implements ArtistDao. This DAO class handles the delete process either by the entity ID or by the entity object itself. We define the delete process in deleteById(Long id) and delete(Artist artist) methods.

In those methods we call the EntityManager.remove() method. This method of EntityManager will take care of removing the entity object from our database. Let’s see the DAO code below:

package org.kodejava.jpa.dao;

import org.kodejava.jpa.entity.Artist;

import java.util.List;

public interface ArtistDao {
    Artist findById(Long id);

    void save(Artist artist);

    void update(Artist artist);

    List<Artist> getArtists();

    void deleteById(Long id);

    void delete(Artist artist);
}
package org.kodejava.jpa.dao.impl;

import org.kodejava.jpa.dao.ArtistDao;
import org.kodejava.jpa.entity.Artist;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.Query;
import java.util.List;

public class ArtistDaoImpl implements ArtistDao {
    private final EntityManager manager;

    public ArtistDaoImpl(EntityManager manager) {
        this.manager = manager;
    }

    /**
     * Find Artist based on the entity id.
     *
     * @param artistId the artist id.
     * @return Artist.
     * @throws EntityNotFoundException when no artist is found.
     */
    public Artist findById(Long artistId) {
        Artist artist = manager.find(Artist.class, artistId);
        if (artist == null) {
            throw new EntityNotFoundException("Can't find Artist for ID "
                    + artistId);
        }
        return artist;
    }

    @Override
    public void save(Artist artist) {
        manager.getTransaction().begin();
        manager.persist(artist);
        manager.getTransaction().commit();
    }

    /**
     * Update Artist information.
     *
     * @param artist an Artist to be updated.
     */
    @Override
    public void update(Artist artist) {
        manager.getTransaction().begin();
        manager.merge(artist);
        manager.getTransaction().commit();
    }

    @Override
    @SuppressWarnings(value = "unchecked")
    public List<Artist> getArtists() {
        Query query = manager.createQuery("select a from Artist a", Artist.class);
        return query.getResultList();
    }

    /**
     * Delete artist by their id.
     *
     * @param id the artist id.
     */
    @Override
    public void deleteById(Long id) {
        Artist artist = manager.find(Artist.class, id);
        if (artist != null) {
            manager.getTransaction().begin();
            manager.remove(artist);
            manager.getTransaction().commit();
        }
    }

    /**
     * Delete artist entity.
     *
     * @param artist the object to be deleted.
     */
    @Override
    public void delete(Artist artist) {
        manager.getTransaction().begin();
        manager.remove(artist);
        manager.getTransaction().commit();
    }
}

After defining the delete methods in the ArtistDao class we create a simple program to demonstrate both of them. In this program we start by create the EntityManagerFactory object from the defined persistence unit in the persistence.xml file. Then we create the EntityManager object, and we pass it to our ArtistDaoImpl object. And then we call the delete methods to remove entity from the database.

To show you the result of the delete process we print out the artist data before and after the delete method is called.

package org.kodejava.jpa;

import org.kodejava.jpa.dao.ArtistDao;
import org.kodejava.jpa.dao.impl.ArtistDaoImpl;
import org.kodejava.jpa.entity.Artist;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.List;

public class EntityRemoveDemo {
    public static final String PERSISTENCE_UNIT_NAME = "music";

    public static void main(String[] args) {
        EntityManagerFactory factory =
                Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager manager = factory.createEntityManager();

        ArtistDao dao = new ArtistDaoImpl(manager);
        System.out.println("Before Delete:");
        printArtists(dao.getArtists());

        // Remove artist with ID = 1.
        dao.deleteById(1L);

        // Remove artist with ID = 2.
        Artist artist = dao.findById(2L);
        dao.delete(artist);

        System.out.println("After Delete:");
        printArtists(dao.getArtists());
    }

    private static void printArtists(List<Artist> artists) {
        for (Artist artist : artists) {
            System.out.println("Artist = " + artist);
        }
    }
}

Here is the result of our code snippet. It shows the number of records before and after the delete process.

Before Delete:
Artist = Artist{id=1, name='Bon Jovi'}
Artist = Artist{id=2, name='Mr. Big'}
Artist = Artist{id=3, name='Metallica'}
After Delete:
Artist = Artist{id=3, name='Metallica'}

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.9.Final</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.1.0</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I get the primary key of any JPA entity?

If you want to get the primary key of any JPA entity object you can use PersistenceUnitUtil.getIdentifier() method. This method take a single parameter which is the entity object whose identifier to be read. The PersistenceUnitUtil instance can be accessed from the EntityManagerFactory object.

If the entity object contains an identifier the getIdentifier() method will return the identifier as a java.lang.Object. If the entity object does not have an identifier ye it will return null.

package org.kodejava.jpa;

import org.kodejava.jpa.entity.Artist;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class GetEntityIdDemo {
    public static final String PERSISTENCE_UNIT_NAME = "music";

    public static void main(String[] args) {
        EntityManagerFactory factory =
                Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager manager = factory.createEntityManager();

        // Get object identifier of an exists entity.
        Artist artist = manager.find(Artist.class, 1L);
        if (artist != null) {
            Object identifier =
                    factory.getPersistenceUnitUtil().getIdentifier(artist);

            System.out.println("Identifier = " + identifier);
        }

        // Get object identifier of a newly inserted entity.
        Artist newArtist = new Artist();
        newArtist.setName("Bon Jovi");

        manager.getTransaction().begin();
        manager.persist(newArtist);
        manager.getTransaction().commit();

        Object identifier =
                factory.getPersistenceUnitUtil().getIdentifier(newArtist);
        System.out.println("Identifier = " + identifier);
    }
}

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.9.Final</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.1.0</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I update entity object using JPA?

In this example you will learn how to update an entity object in JPA. We use the EntityManager.merge() method to update an entity. This method takes the entity to be saved as the parameter and return the merged entity back as the result.

You can see a simple example to the code snippet below. Here is the main program for running the ArtistDao class to update the artist data in the database.

package org.kodejava.jpa;

import org.kodejava.jpa.dao.ArtistDao;
import org.kodejava.jpa.dao.impl.ArtistDaoImpl;
import org.kodejava.jpa.entity.Artist;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityUpdateDemo {
    public static final String PERSISTENCE_UNIT_NAME = "music";

    public static void main(String[] args) {
        EntityManagerFactory factory =
                Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager em = factory.createEntityManager();

        ArtistDao dao = new ArtistDaoImpl(em);
        Artist artist = dao.findById(1L);
        System.out.println("Artist = " + artist);

        artist.setName("Bon Jovi");
        dao.update(artist);

        artist = dao.findById(artist.getId());
        System.out.println("Artist = " + artist);
    }
}

The ArtistDao interface and its implementation ArtistDaoImpl class definition.

package org.kodejava.jpa.dao;

import org.kodejava.jpa.entity.Artist;

import java.util.List;

public interface ArtistDao {
    Artist findById(Long id);

    void save(Artist artist);

    void update(Artist artist);

    List<Artist> getArtists();
}
package org.kodejava.jpa.dao.impl;

import org.kodejava.jpa.dao.ArtistDao;
import org.kodejava.jpa.entity.Artist;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.Query;
import java.util.List;

public class ArtistDaoImpl implements ArtistDao {
    private final EntityManager manager;

    public ArtistDaoImpl(EntityManager manager) {
        this.manager = manager;
    }

    /**
     * Find Artist based on the entity id.
     *
     * @param artistId the artist id.
     * @return Artist.
     * @throws EntityNotFoundException when no artist is found.
     */
    public Artist findById(Long artistId) {
        Artist artist = manager.find(Artist.class, artistId);
        if (artist == null) {
            throw new EntityNotFoundException("Can't find Artist for ID "
                    + artistId);
        }
        return artist;
    }

    @Override
    public void save(Artist artist) {
        manager.getTransaction().begin();
        manager.persist(artist);
        manager.getTransaction().commit();
    }

    /**
     * Update Artist information.
     *
     * @param artist an Artist to be updated.
     */
    @Override
    public void update(Artist artist) {
        manager.getTransaction().begin();
        manager.merge(artist);
        manager.getTransaction().commit();
    }

    @Override
    @SuppressWarnings(value = "unchecked")
    public List<Artist> getArtists() {
        Query query = manager.createQuery("select a from Artist a", Artist.class);
        return query.getResultList();
    }
}

The persitence.xml file can be found on the following link: persistence.xml.

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.9.Final</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.1.0</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central