Hibernate Binary Data and BLOB Mapping Example
- Details
- Written by Nam Ha Minh
- Last Updated on 15 July 2019   |   Print Email
This tutorial shows you how to map byte array (byte[]) or Binary Large Object (java.sql.Blob) of Java type to database type using Hibernate ORM framework. Byte array or Blob can be used to store large binary data such as files and images. According to Hibernate Types:
- A primitive byte[] is mapped to a JDBC VARBINARY.
- A java.sql.Blob is mapped to a JDBC BLOB.
Let’s understand how to do binary types mapping by exploring the below sample application. We cover both mapping of byte[] and java.sql.Blob with some slightly differences.
1. Database Setup
We are going to code an example program that works with a MySQL database. Therefore, execute the following script to create a database called person_db and a table called person:
CREATE DATABASE `person_db`; CREATE TABLE `person` ( `person_id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `photo` longblob, PRIMARY KEY (`person_id`) )
Here, the column photo is declared as of type longblob in MySQL which can hold approximately up to 232 bytes of data (about 4GB).
2. Model Class
Model Class with a primitive byte[] type:
Here’s the model class (Person.java) that uses JPA annotations for mapping:
package net.codejava.hibernate; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "PERSON") public class Person { private int id; private String name; private byte[] photo; public Person() { } public Person(String name) { this.name = name; } @Id @Column(name = "PERSON_ID") @GeneratedValue public int getId() { return id; } public byte[] getPhoto() { return photo; } public void setPhoto(byte[] photo) { this.photo = photo; } // other getters and setters }
Model Class with a java.sql.Blob type:
Here’s another version of the model class in case the java.sql.Blob type is used:
package net.codejava.hibernate; import java.sql.Blob; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "PERSON") public class Person { private int id; private String name; private Blob photo; public Person() { } public Person(String name) { this.name = name; } @Id @Column(name = "PERSON_ID") @GeneratedValue public int getId() { return id; } public Blob getPhoto() { return photo; } public void setPhoto(Blob photo) { this.photo = photo; } // other getters and setters }
XML Mapping
In both cases, we can use XML mapping as in the following file (Person.hbm.xml):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="net.codejava.hibernate"> <class name="Person" table="PERSON_PHOTO"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="name" column="NAME" /> <property name="photo" column="PHOTO" /> </class> </hibernate-mapping>
Hibernate can infer the actual type of the photo attribute by parsing the Person class. In case we want more verbose, add type attribute as following:
- For primitive byte[] array:
<property name="photo" column="PHOTO" type="binary" />
- For java.sql.Blob:
<property name="photo" column="PHOTO" type="blob" />
It’s better to let Hibernate decides the appropriate mapping type.
3. Hibernate Blob Mapping Test Programs
Here is code of a test program for the case in which a primitive byte[] array is used:
package net.codejava.hibernate; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; /** * Test Hibernate binary data mapping with primitive byte[] array. * @author www.codejava.net * */ public class PersonPhotoTest { private static ServiceRegistry serviceRegistry; private static Session session; public static void main(String[] args) throws IOException { initSession(); String photoFilePathToRead = "e:/Test/Photo/Puppy.jpg"; savePersonWithPhoto(photoFilePathToRead); int personId = 1; String photoFilePathToSave = "e:/Test/Photo/MyPuppy.jpg"; readPhotoOfPerson(personId, photoFilePathToSave); endSession(); } private static void savePersonWithPhoto(String photoFilePath) throws IOException { Person person = new Person("Tom"); byte[] photoBytes = readBytesFromFile(photoFilePath); person.setPhoto(photoBytes); session.save(person); } private static void readPhotoOfPerson(int personId, String photoFilePath) throws IOException { Person person = (Person) session.get(Person.class, personId); byte[] photoBytes = person.getPhoto(); saveBytesToFile(photoFilePath, photoBytes); } private static byte[] readBytesFromFile(String filePath) throws IOException { File inputFile = new File(filePath); FileInputStream inputStream = new FileInputStream(inputFile); byte[] fileBytes = new byte[(int) inputFile.length()]; inputStream.read(fileBytes); inputStream.close(); return fileBytes; } private static void saveBytesToFile(String filePath, byte[] fileBytes) throws IOException { FileOutputStream outputStream = new FileOutputStream(filePath); outputStream.write(fileBytes); outputStream.close(); } private static void initSession() { Configuration configuration = new Configuration().configure(); serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()).build(); SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession(); session.beginTransaction(); } private static void endSession() { session.getTransaction().commit(); session.close(); StandardServiceRegistryBuilder.destroy(serviceRegistry); } }
And the following program’s code is for the case in which a java.sql.Blob is used:
package net.codejava.hibernate; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.sql.Blob; import java.sql.SQLException; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; /** * Test Hibernate binary data mapping with java.sql.Blob type. * @author www.codejava.net * */ public class PersonPhotoTest { private static ServiceRegistry serviceRegistry; private static Session session; public static void main(String[] args) throws IOException, SQLException { initSession(); String photoFilePathToRead = "e:/Test/Photo/Rex10.jpg"; savePersonWithPhoto(photoFilePathToRead); endSession(); initSession(); int personId = 1; String photoFilePathToSave = "e:/Test/Photo/MyPuppy.jpg"; readPhotoOfPerson(personId, photoFilePathToSave); endSession(); } private static void savePersonWithPhoto(String photoFilePath) throws IOException, SQLException { Person person = new Person("Peter"); File file = new File(photoFilePath); FileInputStream inputStream = new FileInputStream(file); Blob blob = Hibernate.getLobCreator(session) .createBlob(inputStream, file.length()); person.setPhoto(blob); session.save(person); blob.free(); } private static void readPhotoOfPerson(int personId, String photoFilePath) throws IOException, SQLException { Person person = (Person) session.get(Person.class, personId); Blob blob = person.getPhoto(); byte[] blobBytes = blob.getBytes(1, (int) blob.length()); saveBytesToFile(photoFilePath, blobBytes); blob.free(); } private static void saveBytesToFile(String filePath, byte[] fileBytes) throws IOException { FileOutputStream outputStream = new FileOutputStream(filePath); outputStream.write(fileBytes); outputStream.close(); } private static void initSession() { Configuration configuration = new Configuration().configure(); serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()).build(); SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession(); session.beginTransaction(); } private static void endSession() { session.getTransaction().commit(); session.close(); StandardServiceRegistryBuilder.destroy(serviceRegistry); } }
Both of these test programs insert a person with a photo (specified by its file path) to the database, and then they read the person back, extract the photo data and save as an image file. For your convenience, download both projects in the attachments section below.
Other Hibernate Tutorials:
- Hibernate Hello World Tutorial for Beginners with Eclipse and MySQL
- Java Hibernate JPA Annotations Tutorial for Beginners
- Hibernate One-to-One Association on Primary Key Annotations Example
- Hibernate One-to-Many Association Annotations Example
- Hibernate Many-to-Many Association Annotations Example
- Hibernate Enum Type Mapping Example
- Hibernate Query Language (HQL) Example
- Java Hibernate Reverse Engineering Tutorial with Eclipse and MySQL
- Hibernate Basics - 3 ways to delete an entity from the datastore
Comments
Use longblob type which supports up to 4GB.
which is the best way ,if the size of file is large.2+ GB approx.
JAXB, Web Services, and Binary Data
In my case Im working in an webservice app where I have a field "logo" in a table client. Where I need to store the client's logo image. I used Netbenas MySQL and Hibernate. And I generate POJOS and hbm.xml with the Netbeans wizard.
But Jaxb gives me this error message:
Dec 31, 2015 11:06:10 AM com.sun.xml.bind.v2.runtime.reflect.opt.Injector inject
WARNING: duplicate class definition bug occured? Please report this : com/model/pojos/Organizacion$JaxbAccessorM_getLogo_setLogo_[B
java.lang.ClassFormatError: Illegal class name
where logo Hibernate has mapped it like this:
-In the class:
private byte[] logo;
setter and getter
-In the hbm file:
Please Blaise Help!