第一个 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整合开发王者归来》