Java Tutorial 第四堂(3)Hibernate 與 JPA
|
Java Tutorial 第四堂(2)使用 spring 相依注入 << 前情 現在來想想一個需求,如果設計變更,要為每個影片的導演增加更多資訊,因而 public class Dvd {
private String title;
private Integer year;
private Integer duration;
private Director director;
...
}
public class Director {
private String name;
...
}
那麼你的 Java 的世界中對這類物件關聯對應(Object-Relational Mapping, ORM)當然不缺解決方案,最有名的方案之一就是 Hibernate,2001年末 Hibernate 第一個版本發表,2003 年 6 月 8 日 Hibernate 2 發表,並於年末獲得 Jolt 2004 大獎,由於 Hibernate 廣為流行,設計方式後續影響了 EJB3 中 JPA(Java Persistence API) 規格之製定。 使用 Hibernate 這類的 ORM 方案,基本上需要宣告物件與關聯式資料庫的對應關係,後續操作就是從物件的觀點來進行操作,Hibernate 會自動為你產生對應的 SQL 語句。 hibernate.cfg.xml對應關係宣告的第一步,就是宣告資料庫組態資訊,這是在 hibernate.cfg.xml 中設定: <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"https://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.hsqldb.jdbc.JDBCDriver</property>
<property name="hibernate.connection.url">jdbc:hsqldb:file:src/main/resources/db/dvd_library</property>
<property name="hibernate.connection.username">codedata</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping class="tw.codedata.Dvd" />
<mapping class="tw.codedata.Director" />
</session-factory>
</hibernate-configuration>
Entity 宣告在 hibernate.cfg.xml 中可看到 package tw.codedata;
import javax.persistence.*;
@Entity
@Table(name="dvds")
public class Dvd {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private Integer year;
private Integer duration;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="director_id")
private Director director;
...
}
作為 Entity 的類別,必須使用 一個導演可能主導多個影片,因此 類似地, package tw.codedata;
import javax.persistence.*;
@Entity
@Table(name="directors")
public class Director {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
...
}
那麼那些沒有標註的欄位呢?沒有標註就會採預設值,例如 注意到 SessionFactory你可以使用 package tw.codedata;
import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
private static final StandardServiceRegistry serviceRegistry;
static {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void closeAllResources() {
sessionFactory.close();
StandardServiceRegistryBuilder.destroy(serviceRegistry);
}
}
老實說,這個過程是蠻醜陋的,因而,在你將來有時間深入 Hibernate 之前,故且當這是個魔法好了 … 儲存與查詢有了 Session session = sessionFactory.openSession(); session.beginTransaction(); // 開啟交易 session.save(dvd); // 儲存 Dvd 實體 session.getTransaction().commit(); // 確認變更 session.close(); // 關閉此次操作過程 查詢的話,有幾種方式,像是搭配 HQL(Hibernate Query Language): Session session = sessionFactory.openSession();
session.beginTransaction();
List dvds = session.createQuery("from Dvd").list();
session.getTransaction().commit();
session.close();
注意! 練習 13:使用 Hibernate 在 Lab 檔案的 exercises/exercise13 中有個 Hibernate 目錄,這是改寫自 Java Tutorial 第三堂(2)使用 spring-jdbc 存取資料庫 的範例,其中 build.gradle 已經幫你寫好了: apply plugin: 'java'
apply plugin:'application'
mainClassName = 'tw.codedata.Main'
repositories {
mavenCentral()
}
dependencies {
compile 'org.hsqldb:hsqldb:2.3.1'
compile group: 'com.google.guava', name: 'guava', version: '15.0'
compile 'org.hibernate:hibernate-core:4.3.0.Final'
}
hibernate.cfg.xml、 package tw.codedata;
import com.google.common.base.Optional;
import java.util.List;
import org.hibernate.*;
public class DirectorDaoHibernateImpl implements DirectorDao {
private SessionFactory sessionFactory;
public DirectorDaoHibernateImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void saveDirector(Director director) {
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(director);
session.getTransaction().commit();
session.close();
}
@Override
public Optional maybeFromName(String name) {
Session session = sessionFactory.openSession();
session.beginTransaction();
List directors =
session
.createQuery("from Director as d where d.name = :name")
.setString("name", name).list();
session.getTransaction().commit();
session.close();
return directors.isEmpty() ? Optional.absent() : Optional.of(directors.get(0));
}
}
這個 DAO 負責 package tw.codedata;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class DvdDaoHibernateImpl implements DvdDao {
private SessionFactory sessionFactory;
public DvdDaoHibernateImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void saveDvd(Dvd dvd) {
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(dvd);
session.getTransaction().commit();
session.close();
}
@Override
public List allDvds() {
Session session = sessionFactory.openSession();
session.beginTransaction();
List dvds = session.createQuery("from Dvd").list();
session.getTransaction().commit();
session.close();
return dvds;
}
}
觀察一下 package tw.codedata;
import org.hibernate.*;
public class Main {
public static void main(String[] args) {
SessionFactory factory = HibernateUtil.getSessionFactory();
DirectorDao directorDao = new DirectorDaoHibernateImpl(factory);
DvdDao dvdDao = new DvdDaoHibernateImpl(factory);
Director director = new Director("XD");
directorDao.saveDirector(director);
dvdDao.saveDvd(new Dvd("XD", 112, 1, director));
for(Dvd dvd : dvdDao.allDvds()) {
System.out.println(dvd);
}
HibernateUtil.closeAllResources();
}
}
接著執行 |

Java 學習之路




