Partner – DBSchema – NPI (tag = SQL)
announcement - icon

DbSchema is a super-flexible database designer, which can take you from designing the DB with your team all the way to safely deploying the schema.

The way it does all of that is by using a design model, a database-independent image of the schema, which can be shared in a team using GIT and compared or deployed on to any database.

And, of course, it can be heavily visual, allowing you to interact with the database using diagrams, visually compose queries, explore the data, generate random data, import data or build HTML5 database reports.

>> Take a look at DBSchema

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Introduction

In this quick tutorial, we’ll explain how to manage the PostgreSQL TEXT type using the annotations defined by the JPA specification.

2. The TEXT Type in PostgreSQL

When working with PostgresSQL we may, periodically, need to store a string with an arbitrary length.

For this, PostgreSQL provides three character types:

  • CHAR(n)
  • VARCHAR(n)
  • TEXT

Unfortunately, the TEXT type is not part of the types that are managed by the SQL standard. This means that if we want to use JPA annotations in our persistence entities, we may have a problem.

This is because the JPA specification makes use of the SQL standard. Consequently, it doesn’t define a simple way to handle this type of object using, for example, a @Text annotation.

Luckily, we have a couple of possibilities for managing the TEXT data type for a PostgreSQL database:

  • We can use the @Lob annotation
  • Alternatively, we can also use the @Column annotation, combined with the columnDefinition attribute

Let’s now take a look at the two solutions beginning with the @Lob annotation.

3. @Lob

As the name suggests, a lob is a large object. In database terms, lob columns are used to store very long texts or binary files.

We can choose from two kinds of lobs:

  • CLOB – a character lob used to store texts
  • BLOB – a binary lob that can be used to store binary data

We can use the JPA @Lob annotation to map large fields to large database object types.

When we use the @Lob record on a String type attribute, the JPA specification says that the persistence provider should use a large character type object to store the value of the attribute. Consequently, PostgreSQL can translate a character lob into a TEXT type.

Let’s suppose we have a simple Exam entity object, with a description field, which could have an arbitrary length:

@Entity
public class Exam {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Lob
    private String description;
}

Using the @Lob annotation on the description field, we instruct Hibernate to manage this field using the PostgreSQL TEXT type.

Note that when we use Hibernate with PostgreSQL, the storage mechanics become unusual when handling a String attribute annotated with @Lob. We must understand how Hibernate persists @Lob String attribute values to avoid losing information.

For instance, PostgreSQL stores the contents of a column annotated with @Lob in a separate table, the column itself will only store a UID for each entry in that table. Therefore, this behaviour may lead to information loss. To solve this problem, we can either use @Column(columnDefinition=”TEXT”) along with the @Lob annotation or use only @Column(columnDefinition = “TEXT”).

4. @Column

Another option for managing the TEXT type is to use the @Column annotation, together with the columnDefinition property.

Let’s use the same Exam entity object again but this time we’ll add a TEXT field, which could be of an arbitrary length:

@Entity
public class Exam {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @Lob
    private String description;
    
    @Column(columnDefinition = "TEXT")
    private String text;

}

In this example, we use the annotation @Column(columnDefinition = “TEXT”). Using the columnDefinition attribute allows us to specify the SQL fragment which will be used when constructing the data column for this type.

5. Bringing It All Together

In this section, we’ll write a simple unit test to verify our solution is working:

@Test
public void givenExam_whenSaveExam_thenReturnExpectedExam() {
    Exam exam = new Exam();
    exam.setDescription("This is a description. Sometimes the description can be very very long! ");
    exam.setText("This is a text. Sometimes the text can be very very long!");

    exam = examRepository.save(exam);

    assertEquals(examRepository.find(exam.getId()), exam);
}

In this example, we begin by creating a new Exam object and persisting it to our database.  We then retrieve the Exam object from the database and compare the result with the original exam we created.

To demonstrate the point, if we quickly modify the description field on our Exam entity:

@Column(length = 20)
private String description;

When we run our test again we’ll see an error:

ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Value too long for column "TEXT VARCHAR(20)"

6. Conclusion

In this tutorial, we covered two approaches for using JPA annotations with the PostgreSQL TEXT type.

We began by explaining what the TEXT type is used for and then we saw how we can use the JPA annotations @Lob and @Column to save String objects using the TEXT type defined by PostgreSQL.

As always, the full source code of the article is available on GitHub.

Course – LSD (cat=Persistence)

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE
Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Persistence (eBook) (cat=Persistence)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.