Como Salvar e Fazer Load de Imagens usando Hibernate e MySQL

18 Oct 2011
4 mins read

Este tutorial tem como objetivo mostrar como salvar e fazer load (select) de imagens no banco de dados usando Hibernate e MySQL.

Requerimentos

Para este projeto de exemplo, vamos precisar:

PrintScreen do Projeto

Ao final, nosso projeto deve ficar com a seguinte estrutura:

Modelo do Banco de Dados

Antes de começarmos a ver o código, precisamos rodar o seguinte script no MySQL para criar a tabela Book (livro):

[code lang="sql" firstline="1" toolbar="true" collapse="false" wraplines="false"]
DROP SCHEMA IF EXISTS `blog` ;
CREATE SCHEMA IF NOT EXISTS `blog` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `blog` ;

-- -----------------------------------------------------
-- Table `blog`.`BOOK`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `blog`.`BOOK` ;

CREATE TABLE IF NOT EXISTS `blog`.`BOOK` (
`BOOK_ID` INT NOT NULL AUTO_INCREMENT ,
`BOOK_NAME` VARCHAR(45) NOT NULL ,
`BOOK_IMAGE` MEDIUMBLOB NOT NULL ,
PRIMARY KEY (`BOOK_ID`) )
ENGINE = InnoDB;
[/code]

Essa tabela Book será usada nesse tutorial.

Book POJO

Vamos usar essa class para representar a tabela Book (livro). Um livro tem um ID, um nome (name) e uma imagem (image), que é representada por um array de bytes.

Como o objetivo é persistir uma imagem no banco de dados, temos que usar o tipo BLOB. O MySQL tem algumas variações de BLOBs. Você pode ver as diferenças entre os tipos aqui. Nesse exemplo vamos usar o Medium Blob, que pode armazenar  L + 3 bytes, onde L < 2^24.

Não esqueça de adicionar o column definition na annotation Column.

[code lang="java" firstline="1" toolbar="true" collapse="false" wraplines="false" highlight="22,23"]
package com.loiane.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;

@Entity
@Table(name="BOOK")
public class Book {

@Id
@GeneratedValue
@Column(name="BOOK_ID")
private long id;

@Column(name="BOOK_NAME", nullable=false)
private String name;

@Lob
@Column(name="BOOK_IMAGE", nullable=false, columnDefinition="mediumblob")
private byte[] image;

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public byte[] getImage() {
return image;
}

public void setImage(byte[] image) {
this.image = image;
}
}
[/code]

Hibernate Config

Este arquivo de configuração contém informações necessárias para conectar ao banco de dados.

[code lang="xml" firstline="1" toolbar="true" collapse="false" wraplines="false"]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/blog</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.pool_size">1</property>
<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>
[/code]

Hibernate Util

A classe HibernateUtil ajuda a criar um SessionFactory a partir das informações do arquivo de configuração.

[code lang="java" firstline="1" toolbar="true" collapse="false" wraplines="false"]
package com.loiane.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

import com.loiane.model.Book;

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
try {
sessionFactory = new AnnotationConfiguration()
.configure()
.addPackage("com.loiane.model") //the fully qualified package name
.addAnnotatedClass(Book.class)
.buildSessionFactory();

} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
[/code]

DAO

Nessa classe, vamos criar dois métodos: um para salvar uma instância da classe Book no banco de dados e outro para buscar uma instância dessa classe.

[code lang="java" firstline="1" toolbar="true" collapse="false" wraplines="false"]
package com.loiane.dao;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.loiane.hibernate.HibernateUtil;
import com.loiane.model.Book;

public class BookDAOImpl {

/**
* Inserts a row in the BOOK table.
* Do not need to pass the id, it will be generated.
* @param book
* @return an instance of the object Book
*/
public Book saveBook(Book book)
{
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
session.save(book);
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
return book;
}

/**
* Delete a book from database
* @param bookId id of the book to be retrieved
*/
public Book getBook(Long bookId)
{
Session session = HibernateUtil.getSessionFactory().openSession();
try {
Book book = (Book) session.get(Book.class, bookId);
return book;
} catch (HibernateException e) {
e.printStackTrace();
} finally {
session.close();
}
return null;
}
}
[/code]

Teste

Para testar, vamos primeiro criar uma instância da classe Book (livro) e setar o atributo da imagem. Para fazer isso, precisamos buscar a imagem em algum lugar, e nesse caso vamos pegar de um diretório do HD.

Apenas para garantir na hora de buscar no banco de dados que a imagem que gravamos é a mesma que estamos buscamos, vamos salvá-la em um diretório.

[code lang="java" firstline="1" toolbar="true" collapse="false" wraplines="false"]
package com.loiane.test;

import static org.junit.Assert.assertNotNull;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.loiane.dao.BookDAOImpl;
import com.loiane.model.Book;

public class TestBookDAO {

private static BookDAOImpl bookDAO;

@BeforeClass
public static void runBeforeClass() {
bookDAO = new BookDAOImpl();
}

@AfterClass
public static void runAfterClass() {
bookDAO = null;
}

/**
* Test method for {@link com.loiane.dao.BookDAOImpl#saveBook()}.
*/
@Test
public void testSaveBook() {

//File file = new File("images\\extjsfirstlook.jpg"); //windows
File file = new File("images/extjsfirstlook.jpg");
byte[] bFile = new byte[(int) file.length()];

try {
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

Book book = new Book();
book.setName("Ext JS 4 First Look");
book.setImage(bFile);

bookDAO.saveBook(book);

assertNotNull(book.getId());
}

/**
* Test method for {@link com.loiane.dao.BookDAOImpl#getBook()}.
*/
@Test
public void testGetBook() {

Book book = bookDAO.getBook((long) 1);

assertNotNull(book);

try{
//FileOutputStream fos = new FileOutputStream("images\\output.jpg"); //windows
FileOutputStream fos = new FileOutputStream("images/output.jpg");
fos.write(book.getImage());
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
[/code]

Outra maneira de manualmente verificar se a imagem foi realmente salva é ir no MySQL e olhar na tabela:

e se clicarmos com o botão direito...

podemos ver a imagem que salvamos:

Download do Código Fonte

Você pode fazer download do código fonte completo (ou fazer um fork/clone do projeto - git) (todos os repositórios possuem o mesmo código fonte):

Githubhttps://github.com/loiane/hibernate-image-example

BitBuckethttps://bitbucket.org/loiane/hibernate-image-example/downloads

Bons códigos!