Mapping BLOBs & CLOBs with JPA and Hibernate
Aug 15, 2023
Mapping BLOBs & CLOBs with JPA and Hibernate
Today I will show you how to map BLOBs and CLOBs with JPA and Hibernate. You will learn how to map these database columns to a String or a byte[] and how to use the java.sql classes Blob and Clob. And at the end of this video, I will show you an easy and portable way to load your BLOBs and CLOBs lazily. Especially the lazy-loading trick is a mapping that most developers are surprised about and that I have used with great success in various client projects. But before we start, if this is your first time here, and you want to learn how to create your entity mappings with ease, build incredible efficient persistence layers with Hibernate and all types of other Java persistence related stuff, start now by subscribing and clicking the bell, so you don’t miss anything. Databases use the data types binary large object aka BLOB and character large object aka CLOB to store large objects, like images and very long texts. JPA and Hibernate provide two kinds of mappings for these types. You can choose if you want to: Materialize the LOB and map it to a byte[] or a String. This mapping is defined by the JPA specification and prioritizes ease of use over performance. Or you can use JDBC’s LOB locators java.sql.Blob and java.sql.Clob. The LOB locators enable your JDBC driver to optimize for performance, e.g., by streaming the data. This mapping is Hibernate-specific. If you like this video, please give me your thumbs up and share it with your friends and co-workers. Like my channel? Subscribe! ➜ http://bit.ly/2cUsid8 Join the free Member Library:https://goo.gl/dtyIIC Read the accompanying post: https://thoughts-on-java.org/mapping- … Want to connect with me? Blog: http://www.thoughts-on-java.org/ Twitter: https://twitter.com/thjanssen123 Facebook: https://www.facebook.com/thoughtsonjava #JPA #Hibernate #blob #clob
Content
1.09 -> Hi, I'm Thorben Janssen from
thoughts-on-java.org.
4.67 -> Today I will show you how to map BLOBs
and CLOBs with JPA and Hibernate.
9.37 -> You will learn how to map these database
columns to a String or a byte[] and how
14.82 -> to use the java.sql classes Blob and
Clob.
18.86 -> And at the end of this video, I will
show you an easy and portable way to
22.55 -> load your BLOBs and CLOBs lazily.
25.01 -> Especially the lazy-loading trick is a
mapping that most developers are
29.08 -> surprised about and that I have used
with great success in various client
33.41 -> projects.
34.82 -> But before we start, if this is your
first time here, and you want to learn
38.42 -> how to create your entity mappings with
ease, build incredible efficient
42.219 -> persistence layers with Hibernate and
all types of other Java persistence
46.059 -> related stuff, start now by subscribing
and clicking the bell, so you don't miss
50.54 -> anything.
51.55 -> OK, let's dive into today's topic.
55.26 -> Databases use the data types binary
large object aka BLOB and character
60.949 -> large object aka CLOB to store large
objects, like images and very long
66.52 -> texts.
67.52 -> JPA and Hibernate provide two kinds of
mappings for these types.
72.039 -> You can choose if you want to:
Materialize the LOB and map it to a
77.06 -> byte[] or a String.
78.939 -> This mapping is defined by the JPA
specification and prioritizes ease of
82.99 -> use over performance.
85.43 -> Or you can use JDBC’s LOB locators
java.sql.Blob and java.sql.Clob.
90.84 -> The LOB locators enable your JDBC driver
to optimize for performance, e.g., by
96.799 -> streaming the data.
98.639 -> This mapping is Hibernate-specific.
101.319 -> The mapping of both approaches looks
almost identical.
104.539 -> You just need to annotate your entity
attribute with a @Lob annotation.
109.02 -> The only difference is the type of your
entity attribute.
112.479 -> But you will see a huge difference in
the way you use the values of these
116.28 -> entity attributes.
117.829 -> Let’s use both options to map the
following Book table.
122.549 -> The columns cover of type oid and
content of type text are the important
128.039 -> ones for this video.
129.179 -> We will map the cover column as BLOB and
the content column as a CLOB.
135.469 -> The materialized mapping to a String or
a byte[] is the most intuitive mapping
140.25 -> for most Java developers.
142.68 -> Entity attributes of these types are
easy to use, and it feels natural to use
146.97 -> them in your domain model.
149.09 -> But Hibernate also needs to fetch all
data stored in the LOB immediately and
153.56 -> map it to a Java object.
156.28 -> Depending on the size of your LOB, this
can cause severe performance problems.
160.31 -> If you, e.g., store large video files in
your database, it’s often better to
164.659 -> use JDBC’s LOB locators.
166.92 -> I show you how to use them in the next
section.
170.45 -> The JPA specification defines this
mapping.
173.42 -> You can not only use it with Hibernate
but also with EclipseLink and OpenJPA.
181.36 -> Creating materialized mappings is very
simple.
184.019 -> You just need an attribute of type
String or byte[] and annotate it with
188.019 -> JPA’s @Lob annotation.
190.709 -> Hibernate can also map nationalized
character data types, like NCHAR,
194.59 -> NVARCHAR, LONGNVARCHAR, and NCLOB.
198.209 -> To define such a mapping, you need to
annotate your entity attribute of type
201.78 -> String with Hibernate’s @Nationalized
annotation instead of @Lob.
206.719 -> As I said at the beginning of this
video, materialized mappings are
209.89 -> straightforward to use.
212.05 -> Hibernate fetches all data stored in the
LOB when it initializes the entity and
216.319 -> maps it to a String or byte[].
218.959 -> You can then use the entity attribute in
the same way as any other attribute.
222.939 -> Here are 2 examples that store a new
Book entity and fetch an existing Book
228.12 -> entity from the database.
233.209 -> With Hibernate, you can use the same
approach to map your LOB to a
237.079 -> java.sql.Clob or a java.sql.Blob.
240.239 -> These Java types are not as easy to use
as a String or byte[].
244.609 -> But they enable your JDBC driver to use
LOB-specific optimizations, which might
249.76 -> improve the performance of your
application.
252.2 -> If and what kind of optimizations are
used, depends on the JDBC driver and
257.1 -> your database.
258.8 -> The mapping is Hibernate-specific and
not defined by the JPA specification.
266.479 -> As you can see in the following code
snippet, the mapping to JDBC’s LOB
269.95 -> locators java.sql.Clob and java.sql.Blob
is almost identical to the previous
276.039 -> example.
277.11 -> The only 2 differences are: The cover
attribute is now of type Blob.
281.99 -> The content attribute is of type Clob.
284.68 -> And Hibernate also enables you to map
the nationalized character data types
288.93 -> NCHAR, NVARCHAR, LONGNVARCHAR, and NCLOB
to a java.sql.Clob.
295.67 -> The types java.sql.Clob and
java.sql.Blob provide more flexibility
300.12 -> to the JDBC driver, but they are not as
easy to use as a byte[] or a String.
305.75 -> You need to use Hibernate’s BlobProxy
and ClobProxy classes to create a Blob
310.59 -> or Clob.
311.87 -> As you can see in the code, that’s a
rather small inconvenience.
315.86 -> To create a Blob object, you can call
the generateProxy method of the
320.34 -> BlobProxy with a byte[] or an
InputStream.
323.87 -> And you can call the generateProxy
method of the ClobProxy with a String or
328.199 -> a Reader.
329.389 -> That makes both proxies very comfortable
to use.
333.139 -> Reading a Blob or a Clob is also not too
complicated but requires a little more
337.639 -> work than using a byte[] or a String.
340.59 -> The java.sql.Blob interface provides you
with multiple methods to get an
344.77 -> InputStream or a byte[] of the BLOB
value.
348.72 -> And the java.sql.Clob interface defines
various ways to get a Reader or a String
353.8 -> of the CLOB value.
358.879 -> When we are talking about LOBs, we also
need to talk about lazy loading.
362.86 -> In most cases, LOBs require too much
memory to fetch them eagerly every time
367.3 -> you fetch the entity.
369.05 -> It would be better only to fetch the LOB
if you need it in your business code.
373.46 -> As I explained in a previous video, JPA
defines lazy fetching for basic
377.27 -> attributes as a hint.
379.319 -> That means that your persistence
provider can decide if it follows that
382.69 -> hint or fetches the value eagerly.
386.21 -> As a result, the support and
implementation of this feature depend on
390.28 -> your JPA implementation.
391.93 -> Hibernate, for example, requires you to
activate byte code enhancement.
396.389 -> I explain that in more details in my
Hibernate Performance Tuning Online
399.91 -> Training.
401.19 -> In this video, I want to show and
recommend a different approach.
404.91 -> It doesn’t require any
provider-specific features and works
408.28 -> with all JPA implementations.
411.879 -> The easiest and best way to load LOBs
lazily is to store them in a separate
415.91 -> table.
416.91 -> You can then map the LOBs to a separate
entity.
420.36 -> That allows you to remove the LOBs from
the Book entity and to model a
424.78 -> unidirectional one-to-one association
with a shared primary key on the
428.47 -> BookLobs entity.
433.33 -> The mapping of the 2 entities is pretty
simple.
436.75 -> After removing the 2 LOBs, the Book
entity is a simple entity with a
440.56 -> generated primary key and a title
attribute.
443.97 -> As I will show you in the next section,
you don’t need to model the
447.06 -> association to the BookLob entity.
450.159 -> The BookLob entity models a
unidirectional one-to-one association to
454.919 -> the Book entity.
456.689 -> The @MapsId annotation tells Hibernate
to use the primary key value of the
460.789 -> associated Book.
462.189 -> I explained that in more details
in Hibernate Tips: How to Share the
466.069 -> Primary Key in a One-to-One Association.
469.38 -> And the materialized mappings of the
content and cover attributes are the
473.569 -> same as I used in the first example.
476.19 -> The shared primary key and the
unidirectional one-to-one associations
480.039 -> make using the 2 entities very easy.
482.919 -> To store a new book in your database,
you need to instantiate and persist a
487.08 -> Book and BookLobs entity.
489.81 -> The BookLobs entity uses the primary key
value of the associated Book entity.
494.159 -> So, you need to make sure to initialize
the association before you persist the
498.78 -> BookLobs entity.
501.25 -> And when you want to get the BookLobs
entity for a given Book entity, you just
505.78 -> need to call the find method on your
EntityManager with the id of the Book.
510.979 -> As you have seen, JPA provides an easy
way to map LOBs to entity attributes of
518.1 -> type byte[] and String.
520.6 -> This mapping is not only easy to define,
but it’s also very comfortable to use
524.82 -> and feels natural to most Java
developers.
528 -> The only downside of it is that it
prevents your JDBC driver from using
531.97 -> LOB-specific optimizations.
534.97 -> Hibernate takes the mapping of LOBs one
step further.
538.14 -> In addition to the JPA mappings, it also
allows you to map LOBs to JDBC’s Clob
543.63 -> and Lob locators.
545.37 -> These mappings are a little bit harder
to use.
547.96 -> But they enable your JDBC driver to
implement LOB specific implementations,
552.58 -> like the streaming of large objects.
554.97 -> That can provide better performance if
you’re using a lot of or very huge
558.91 -> LOBs.
559.91 -> OK, that’s it for today.
562.06 -> If you want to learn more about
Hibernate, you should join the free
564.6 -> Thoughts on Java Library.
566.4 -> It gives you free access to a lot of
member-only content like a cheat for
570.03 -> this video and an ebook about using
native queries with JPA and Hibernate.
574.841 -> I’ll add the link to it to the video
description below.
577.56 -> And if you like today’s video, please
give it a thumbs up and subscribe below.
Source: https://www.youtube.com/watch?v=uZXfZZ59cjU