第一個 Hibernate 程序(入門詳解)
- 說明:運行前請在mysql上手動創建數據庫”hibernate”,程序已經完整,完美運行。
文件名 | 作用 |
---|---|
explain.xml | 項目配置說明 |
hibernate.cfg.xml | Hibernate配置文件 |
log4j.properties | log4j日誌工具配置文件 |
- explain.xml
<?xml version="1.0" encoding="UTF-8"?>
<項目信息>
<字段>
<術名>Java EE version</術名>
<版本>JavaEE 7 - Web 3.1</版本>
</字段>
<字段>
<術名>Java version</術名>
<版本>1.7</版本>
</字段>
<字段>
<術名>JSTL version</術名>
<版本>1.2.2</版本>
</字段>
<外部依賴包信息>
<字段>
<術名>mysql-connector-java-bin.jar</術名>
<版本>5.1.7</版本>
</字段>
<字段>
<術名>Hibernate version</術名>
<版本>4.1.4</版本>
</字段>
</外部依賴包信息>
</項目信息>
以上除了 Hibernate 的版本不是當前最新的5.2.10以外其它均爲當前最新版本。—time:2017年9月5日。
基礎目錄結構(圖):
com.person.hibernate.bean包
Cat.java
package com.person.hibernate.bean;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/***
* 配置Cat實體類,實體類(Entity)是指與數據庫有影射關係的Java類,
* 一般推薦使用POJO(持久化對象)。
* 如果Cat某字段不需要保存到數據庫中,可以用@javax.persistence.Transient配置
* 使用Hibernate持久化數據步驟:
* 1)創建持久化類的實例;
* 2)初始化Configuration對象;
* 3)獲取SessionFactory;
* 4)通過SessionFactory打開Session;
* 5)聲明事務Transaction;
* 6)通過Session把POJO對象持久化到數據庫;
* 7)提交事務關閉Session。
* @author ljj
* */
//@NamedQuery(name = "all cat", query = " select c from Cat c ")
//@NamedNativeQuery(name = "all cat", query = "select * from tb_cat")
@NamedQueries(value = {
@NamedQuery(name = "all cat", query = " select c from Cat c "),
@NamedQuery(name = "cat by name", query = " select c from Cat c where c.name = :name ", hints = { @QueryHint(name = "org.hibernate.callable", value = "true") }),
@NamedQuery(name = "cat by mother", query = " select c from Cat c ") })
//@NamedNativeQueries(value = {
// @NamedNativeQuery(name = "all cat", query = "select * from tb_cat"),
// @NamedNativeQuery(name = "all cat", query = "select * from tb_cat"),
// @NamedNativeQuery(name = "all cat", query = "select * from tb_cat") })
@Entity
//註解Entity表示該類能被Hibernate持久化
@Table(name = "tb_cat")
//指定該Entity對應的數據表名
public class Cat {
@Id
@Column(name = "id")
//指定該列爲主鍵
@GeneratedValue(strategy = GenerationType.AUTO)
//主鍵類型,auto爲數據庫自增長類型
private Integer id;
@Column(name = "name")
// 指定屬性對應的數據庫表的列爲“name”
private String name;
@Column(name = "description")
// 同上。@Column與name均可省略
private String description;
@ManyToOne
// 指定POJO之間的關係,本例爲多對一關係
@JoinColumn(name = "mother_id")
// 該屬性對應的列
private Cat mother;
@Temporal(TemporalType.TIMESTAMP)
// 日期類型(DATE, TIME還是TIMESTEMP)
@Column(name = "createDate")
private Date createDate;
@OneToMany(mappedBy = "cat")
//@JoinColumns(value = { @JoinColumn(name = "cat_id", referencedColumnName= "id") })
private List<Event> events = new ArrayList<Event>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Cat getMother() {
return mother;
}
public void setMother(Cat mother) {
this.mother = mother;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public List<Event> getEvents() {
return events;
}
public void setEvents(List<Event> events) {
this.events = events;
}
}
Cat.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
.hbm.xml映射文件小結:
1)映射是從對象到數據表,所以映射文件的元素是關於對象的,元素的屬性纔是關於數據表的。
2)<id>或<property>的name屬性是對象的相關屬性,Hibernate根據name屬性尋找相應的 getter / setter 方法。
3)<generator class=“native”/>表示根據目標數據庫的特性自動選擇此數據庫的默認的標識符生成方式。
4)<id>或<property>的type屬性的取值既不是Java的類型,也不是數據庫的類型。是Hibernate專有的映射類型。
5)<id>或<property>的type屬性可以省略,如果省略,Hibernate則通過反射機制獲取類型。但通常不建議省略type,因爲會影響運行效率。
6)<id>或<property>的column屬性可以省略,如果省略,則表明對象的屬性映射到數據庫中的同名字段。如果省略,要注意是否爲關鍵字。
-->
<hibernate-mapping package="com.person.hibernate.bean">
<class name="Cat" table="tb_cat">
<id name="id" column="id">
<generator class="native"></generator> <!-- 由Hibernate根據底層數據庫自行判斷採用identity、hilo、sequence其中一種作爲主鍵生成方式。 -->
</id>
<property name="name" type="string" column="name"></property>
<property name="description" type="text"></property>
<property name="createDate" type="timestamp"></property>
<many-to-one name="mother" column="mother_id"></many-to-one>
<bag name="events" inverse="true">
<key column="cat_id"></key>
<one-to-many class="Event" />
</bag>
<sql-query name="cat by name">
<![CDATA[
select c from Cat c where c.name = :name
]]>
<return alias="" class="com.person.hibernate.bean.Cat" />
</sql-query>
<sql-query name="cat by mother">
<![CDATA[
select c from Cat c where c.mother.name = :mother
]]>
<return alias="" class="com.person.hibernate.bean.Cat" />
</sql-query>
</class>
</hibernate-mapping>
Event.java
package com.person.hibernate.bean;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name = "tb_event")
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.AUTO) //提供主鍵生成策略的規範,auto、identity、sequence、table
private Integer id;
@ManyToOne(fetch = FetchType.LAZY) //@多對一(取來 = FetchType.懶取 ),該屬性可以定義數據獲取是否爲急需還是懶取
@JoinColumn(name = "cat_id") //連接**表中的cat_id列
private Cat cat;
private String description;
@Temporal(TemporalType.TIMESTAMP) //@時間的(時態類型.時間戳)
private Date createDate;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
Event.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.person.hibernate.bean">
<class name="Event" table="tb_event">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="description" type="text"></property>
<property name="createDate" type="timestamp"></property>
<many-to-one name="cat" lazy="false" column="cat_id"></many-to-one>
</class>
</hibernate-mapping>
com.person.hibernate.test
CatTest.java
package com.person.hibernate.test;
import java.awt.Font;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.swing.JOptionPane;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.mysql.jdbc.log.Log;
import com.person.hibernate.bean.Cat;
import com.person.hibernate.util.HibernateSessionFactory;
public class CatTest {
/**
* 小程序我慣用println()來輸出一段對話來判斷是
* 否異常以及異常出現的準確位置,比較直觀。
* */
public static void main(String[] args) {
Cat mother = new Cat();
mother.setName("Mary White");
mother.setDescription("The Mama cat. ");
mother.setCreateDate(new Date());
System.out.println("執行成功:mother");
Cat kitty = new Cat();
kitty.setName("Kitty");
kitty.setDescription("Hello Kitty. ");
kitty.setMother(mother);
kitty.setCreateDate(new Date());
System.out.println("執行成功:Kitty");
Cat mimmy = new Cat();
mimmy.setName("Mimmy");
mimmy.setDescription("Kitty's little twin sister. ");
mimmy.setMother(mother);
mimmy.setCreateDate(new Date());
System.out.println("執行成功:mimmy");
/**
//生成Configuration示例並進行初始化
Configuration cfg = new Configuration().configure();
// 從Configuration實例中獲取SessionFactory
SessionFactory sf = cfg.buildSessionFactory();
//打開一個Session,準備數據庫讀寫操作
Session session = sf.openSession();
*此方法已過時,官方不推薦,測試時可以使用一下進行了解
**/
// 開啓一個 Hibernate 對話
Session session = HibernateSessionFactory.getSessionFactory().openSession();
System.out.println("執行成功:session");
// 開啓一個事務
Transaction trans = null;
try{
trans = session.beginTransaction();
System.out.println("執行成功:trans");
//持久化一組對象
session.save(mimmy);
session.save(kitty);
session.save(mother);
// 將三隻貓的資料保存到數據庫
session.persist(mother);
session.persist(kitty);
session.persist(mimmy);
System.out.println("執行成功:數據保存到數據庫成功!!");
// 查詢數據中的所有的貓
@SuppressWarnings("all")
List<Cat> catList = session.createQuery(" from Cat ").list();
StringBuffer result = new StringBuffer();
result.append("數據庫裏的所有的貓:\r\n\r\n");
// 遍歷 輸出貓與貓媽媽
for (Cat cc : catList) {
result.append("貓: " + cc.getName() + ", ");
result.append("貓媽媽: "
+ (cc.getMother() == null ? "沒有記錄" : cc.getMother()
.getName()));
result.append("\r\n");
}
System.out.println("執行成功:所有貓在Swing面板中已遍歷!!");
trans.commit(); //事務提交
System.out.println("執行成功:事務已經交!");
//Console控制檯輸出的顯示結果
for (Iterator iterator = catList.iterator(); iterator.hasNext(); ) {
Cat ct = (Cat) iterator.next();
System.out.println(ct.getName()+"[創建日期:"+ct.getCreateDate()+"]");
}
// 用 Swing 顯示查詢結果
JOptionPane.getRootFrame().setFont(new Font("Arial", Font.BOLD, 14));
JOptionPane.showMessageDialog(null, result.toString());
} catch(Exception e) {
if (trans != null) {
//回滾事務
trans.rollback();
System.out.println("異常出現:產生了事務回滾!!");
}
e.printStackTrace();
} finally {
session.close(); //關閉Hibernate對話
System.out.println("執行成功:HibernateSession已經關閉");
}
}
}
com.person.hibernate.util
HibernateSessionFactory.java
package com.person.hibernate.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
/**
* MyEclipse 嚮導生成 HibernateSessionFactory 的類
* 爲 Hibernate 的工具類,用來獲取Session。
* Hibernate 裏的 Session 爲org.hibernate.Session,
* 代表一次完整的數據庫操作;
* Servlet 裏的 Session 可以包括多次的數據庫讀寫、多個事務(Transaction)。
* */
public class HibernateSessionFactory {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
//private static Configuration configuration = new Configuration();
//XML配置時使用
@SuppressWarnings("deprecation")
private static Configuration configuration = new AnnotationConfiguration();
//@配置時使用
private static ServiceRegistry serviceRegistry;
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Configuration getConfiguration() {
return configuration;
}
}
HibernateUtil.java
package com.person.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
@SuppressWarnings("deprecation")
public class HibernateUtil {
private static final SessionFactory sessionFactory;
//單例模式的SessionFactory
static { //static代碼塊,類加載時初始化Hibernate
try {
sessionFactory = new AnnotationConfiguration().configure("hibernate.cfg.xml").buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
package-info.java
/**
*
*/
/**
* @author ljj
*
*/
package com.person.hibernate.util;
hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<!-- name中可以不用前綴"hibernate." -->
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/hibernate?characterEncoding=UTF-8
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1109812950</property>
<!-- 指定使用MySQL5.*數據庫格式的SQL語句 -->
<!-- 這裏要注意一下,看你的MySQLmysql數據庫的版本來填寫的,建議主動到相關jar包中查看了解,包org.hibernate.dialect -->
<property name="hibernate.dialect">
org.hibernate.dialect.MySQL5Dialect
</property>
<!-- 指定在控制檯打印生成的SQL語句 -->
<property name="hibernate.show_sql">true</property>
<!-- 指定Hibernate啓動時候自動創建表結構 -->
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="javax.persistence.validation.mode">none</property>
<!-- 要加這一句 否則可能會異常,意義:爲每一個線程生成一個Session -->
<property name="current_session_context_class">thread</property>
<!-- 映射表 -->
<!-- ,例指定 Cat 類爲 Hibernate 實體類 -->
<mapping class="com.person.hibernate.bean.Cat"/>
<mapping class="com.person.hibernate.bean.Event"/>
</session-factory>
</hibernate-configuration>
log4j.properties
log4j.rootLogger=ERROR, stdout
log4j.category.org.hibernate.tool.hbm2ddl =DEBUG, file
log4j.category.org.hibernate.SQL =DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.File = log.txt
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=Hibernate: %m%n
顯示結果:
控制檯console輸出成功的信息:
執行成功:mother
執行成功:Kitty
執行成功:mimmy
九月 06, 2017 8:35:41 下午 org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
九月 06, 2017 8:35:41 下午 org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.4.Final}
九月 06, 2017 8:35:41 下午 org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
九月 06, 2017 8:35:41 下午 org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
九月 06, 2017 8:35:41 下午 org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: /hibernate.cfg.xml
九月 06, 2017 8:35:41 下午 org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: HHH000040: Configuration resource: /hibernate.cfg.xml
九月 06, 2017 8:35:41 下午 org.hibernate.cfg.Configuration doConfigure
INFO: HHH000041: Configured SessionFactory: null
九月 06, 2017 8:35:41 下午 org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000402: Using Hibernate built-in connection pool (not for production use!)
九月 06, 2017 8:35:41 下午 org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 20
九月 06, 2017 8:35:41 下午 org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000006: Autocommit mode: false
九月 06, 2017 8:35:41 下午 org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000401: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/hibernate?characterEncoding=UTF-8]
九月 06, 2017 8:35:41 下午 org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000046: Connection properties: {user=root, password=****}
九月 06, 2017 8:35:41 下午 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
九月 06, 2017 8:35:41 下午 org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
九月 06, 2017 8:35:41 下午 org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
九月 06, 2017 8:35:41 下午 org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
九月 06, 2017 8:35:42 下午 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000227: Running hbm2ddl schema export
Hibernate: alter table tb_cat drop foreign key FKCB83D6852E2143B7
Hibernate: alter table tb_event drop foreign key FKFA0DD98914901C4
Hibernate: drop table if exists tb_cat
Hibernate: drop table if exists tb_event
Hibernate: create table tb_cat (id integer not null auto_increment, createDate datetime, description varchar(255), name varchar(255), mother_id integer, primary key (id))
Hibernate: create table tb_event (id integer not null auto_increment, createDate datetime, description varchar(255), cat_id integer, primary key (id))
Hibernate: alter table tb_cat add index FKCB83D6852E2143B7 (mother_id), add constraint FKCB83D6852E2143B7 foreign key (mother_id) references tb_cat (id)
Hibernate: alter table tb_event add index FKFA0DD98914901C4 (cat_id), add constraint FKFA0DD98914901C4 foreign key (cat_id) references tb_cat (id)
九月 06, 2017 8:35:42 下午 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
執行成功:session
執行成功:trans
Hibernate: insert into tb_cat (createDate, description, mother_id, name) values (?, ?, ?, ?)
Hibernate: insert into tb_cat (createDate, description, mother_id, name) values (?, ?, ?, ?)
Hibernate: insert into tb_cat (createDate, description, mother_id, name) values (?, ?, ?, ?)
執行成功:數據保存到數據庫成功!!
Hibernate: update tb_cat set createDate=?, description=?, mother_id=?, name=? where id=?
Hibernate: update tb_cat set createDate=?, description=?, mother_id=?, name=? where id=?
Hibernate: select cat0_.id as id0_, cat0_.createDate as createDate0_, cat0_.description as descript3_0_, cat0_.mother_id as mother5_0_, cat0_.name as name0_ from tb_cat cat0_
執行成功:所有貓在Swing面板中已遍歷!!
執行成功:事務已經交!
Mimmy[創建日期:Wed Sep 06 20:35:41 CST 2017]
Kitty[創建日期:Wed Sep 06 20:35:41 CST 2017]
Mary White[創建日期:Wed Sep 06 20:35:41 CST 2017]
分析器代理: 正在等待端口 5140 上的連接 (協議版本: 13)
分析器代理: 已使用工具建立連接
分析器代理: 本地加速會話
分析器代理: 與代理的連接已關閉
執行成功:HibernateSession已經關閉
Profiler Agent: JNI OnLoad Initializing...
Profiler Agent: JNI OnLoad Initialized successfully
原版代碼案例引用《JavaWeb整合開發王者歸來》