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.

How do I limit MySQL query result?

package org.kodejava.jdbc;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SqlLimitExample {
    private static final String URL = "jdbc:mysql://localhost/kodejava";
    private static final String USERNAME = "kodejava";
    private static final String PASSWORD = "s3cr*t";

    public static void main(String[] args) {
        try (Connection connection =
                     DriverManager.getConnection(URL, USERNAME, PASSWORD)) {

            // Create PreparedStatement to get all data from a database.
            String query = "select count(*) from product";
            PreparedStatement ps = connection.prepareStatement(query);
            ResultSet result = ps.executeQuery();

            int total = 0;
            while (result.next()) {
                total = result.getInt(1);
            }

            System.out.println("Total number of data in database: " +
                               total + "\n");

            // Create PreparedStatement to the first 5 records only.
            query = "select * from product limit 5";
            ps = connection.prepareStatement(query);
            result = ps.executeQuery();

            System.out.println("Result fetched with specified limit 5");
            System.out.println("====================================");
            while (result.next()) {
                System.out.println("id:" + result.getInt("id") +
                                   ", code:" + result.getString("code") +
                                   ", name:" + result.getString("name") +
                                   ", price:" + result.getString("price"));
            }

            // Create PreparedStatement to get data from the 4th
            // record (remember the first record is 0) and limited
            // to 3 records only.
            query = "select * from product limit 3, 3";
            ps = connection.prepareStatement(query);
            result = ps.executeQuery();

            System.out.println("\nResult fetched with specified limit 3, 3");
            System.out.println("====================================");
            while (result.next()) {
                System.out.println("id:" + result.getInt("id") +
                                   ", code:" + result.getString("code") +
                                   ", name:" + result.getString("name") +
                                   ", price:" + result.getString("price"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

An example result of our program is:

Total number of data in database: 9

Result fetched with specified limit 5
====================================
id:1, code:P0000001, name:UML Distilled 3rd Edition, price:25.00
id:3, code:P0000003, name:PHP Programming, price:20.00
id:4, code:P0000004, name:Longman Active Study Dictionary, price:40.00
id:5, code:P0000005, name:Ruby on Rails, price:24.00
id:6, code:P0000006, name:Championship Manager, price:0.00

Result fetched with specified limit 3, 3
====================================
id:5, code:P0000005, name:Ruby on Rails, price:24.00
id:6, code:P0000006, name:Championship Manager, price:0.00
id:7, code:P0000007, name:Transport Tycoon Deluxe, price:0.00

Maven Dependencies

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.1.0</version>
</dependency>

Maven Central

How do I limit Hibernate query result?

In the example below you’ll see how to limit the number of records returned by hibernate queries. Limiting the query result is usually use for creating pagination, where we can navigate from page to page of data in our application but only a few of them are read from the database.

In hibernate Query object we need to specify the first result and max results by calling the setFirstResult() and setMaxResults() methods to limit the query results.

package org.kodejava.hibernate.service;

import org.hibernate.Session;
import org.hibernate.query.Query;
import org.kodejava.hibernate.SessionFactoryHelper;
import org.kodejava.hibernate.model.Label;

import java.util.List;

public class LabelService {
    public List<Label> getLabels(int pageNumber, int pageSize) {
        Session session =
                SessionFactoryHelper.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        Query<Label> query = session.createQuery("from Label", Label.class);

        // Set the first record position and the max number of record to be
        // read. The setFirstResult() tell hibernate from which row the data
        // should be read. In the example if we have pages of 10 records,
        // passing the page number 2 will read 10 records from the 20th row
        // in the selected records.
        query.setFirstResult((pageNumber - 1) * pageSize);
        query.setMaxResults(pageSize);

        List<Label> labels = query.list();
        session.getTransaction().commit();
        return labels;
    }
}
package org.kodejava.hibernate;

import org.kodejava.hibernate.model.Label;
import org.kodejava.hibernate.service.LabelService;

import java.util.List;

public class LimitDemo {
    public static void main(String[] args) {
        LabelService service = new LabelService();

        List<Label> labels = service.getLabels(1, 10);
        for (Label label : labels) {
            System.out.println("Label = " + label);
        }
    }
}

Maven Dependencies

<dependencies>
    <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.0.33</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I retrieve a list of Hibernate’s persistent objects?

In this example we add the function to read a list of records in our LabelService class. This function will read all Label persistent object from database. You can see the other functions such as saveLabel, getLabel and deleteLabel in the related example section of this example.

package org.kodejava.hibernate.service;

import org.hibernate.Session;
import org.kodejava.hibernate.SessionFactoryHelper;
import org.kodejava.hibernate.model.Label;

import java.util.List;

public class LabelService {
    public List<Label> getLabels() {
        Session session =
                SessionFactoryHelper.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        // We read labels record from database using a simple Hibernate
        // query, Hibernate Query Language (HQL).
        List<Label> labels = session.createQuery("from Label", Label.class)
                .list();
        session.getTransaction().commit();

        return labels;
    }

    public void saveLabel(Label label) {
        // To save an object we first get a session by calling 
        // getCurrentSession() method from the SessionFactoryHelper class. 
        // Next we create a new transaction, save the Label object and 
        // commit it to database,
        Session session = SessionFactoryHelper.getSessionFactory()
                .getCurrentSession();

        session.beginTransaction();
        session.save(label);
        session.getTransaction().commit();
    }
}
package org.kodejava.hibernate;

import org.kodejava.hibernate.model.Label;
import org.kodejava.hibernate.service.LabelService;

import java.util.Date;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        LabelService service = new LabelService();

        // Creates a Label object we are going to store in the database.
        // We set the name, modified by and modified date information.
        Label newLabel = new Label();
        newLabel.setName("PolyGram");
        newLabel.setCreated(new Date());

        // Call the LabelManager saveLabel method.
        service.saveLabel(newLabel);

        List<Label> labels = service.getLabels();
        for (Label label : labels) {
            System.out.println("Label = " + label);
        }
    }
}

Maven Dependencies

<dependencies>
    <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.0.33</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I query records from a table?

package org.kodejava.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JdbcQueryExample {
    // Database connection information
    private static final String URL = "jdbc:mysql://localhost/kodejava";
    private static final String USERNAME = "kodejava";
    private static final String PASSWORD = "s3cr*t";

    public static void main(String[] args) {
        // Get a connection to database.
        try (Connection connection =
                     DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
            // Create a statement object.
            Statement statement = connection.createStatement();

            // Executes a query command to select isbn and the book title
            // from books table. The execute query returns a ResultSet
            // object which is the result of our query execution.
            String query = "SELECT isbn, title, published_year FROM book";
            ResultSet books = statement.executeQuery(query);

            // To get the value returned by the statement.executeQuery we
            // need to iterate the books object until the last items.
            while (books.next()) {
                // To get the value from the ResultSet object we can call
                // a method that correspond to the data type of the column
                // in database table. In the example below we call
                // books.getString("isbn") to get the book's ISBN 
                // information.
                System.out.println(books.getString("isbn") + ", " +
                        books.getString("title") + ", " +
                        books.getInt("published_year"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Maven Dependencies

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.1.0</version>
</dependency>

Maven Central