1、知识点
1、 对应包:hibernate.0
2、 hibernate.cfg.xml:hbm2ddl.auto
3、 搭建日志环境并配置显示DQL语句
4、 搭建JUnit环境
a) 需要注意JUuit的Bug
5、 hibernate.cfg.xml:show_sql
6、 hibernate.cfg.xml:format_sql
7、 表名和类名不同,对表名进行配置
a) Annotation:@Table
b) xml:自己查询
8、 字段名和属性名相同
a) 默认为@Basic
b) xml中不用写column
9、 字段名和属性名不同
a) Annotation:@Column
b) xml自己查询
10、 不需要persistence的字段
a) Annotation:@Transient
b) xml:不写
11、 映射日期与时间类型,指定时间精度
a) Annotation:@Temporal
b) xnl:指定type
12、 映射枚举类型
a) @Enumerated
b) xml:麻烦(不推荐)
13、 字段映射的位置(field或者get方法)
a) Best Practice:保持filed和get set方法的一致
14、 @Lob
15、 课外:CLOB和BLOB类型的数据存取
16、 课外:Hibernate自定义数据类型
17、 Hibernate
2、hibernate.cfg.xml中的一些配置
<propertyname="show_sql">true</property> <propertyname="format_sql">true</property> <propertyname="hbm2ddl.auto">create</property> |
关于hbm2ddl.auto的说明如下:
hibernate.hbm2ddl.auto | Automatically validates or exports schema DDL to the database when the SessionFactory is created. Withcreate-drop, the database schema will be dropped when theSessionFactory is closed explicitly. e.g. validate | update | create | create-drop |
3、使用JUnit测试程序
我们知道,可以创建Hibernate文档建议的辅助类来获取会话工厂,这样一来方便,二来通过单例设计模式规定了只实例化一次会话工厂。除了创建这个辅助类,还可以使用@BeforeClass和@AfterClass来完成此要求。
package com.bjsxt.hibernate;
import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test;
public class StudentTest { private static SessionFactory sessionFactory; @BeforeClass public static void beforeClass() { sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); } @AfterClass public static void afterClass() { sessionFactory.close(); }
@Test public void testStudentSave() { Student s = new Student(); s.setId(1); s.setName("zhangsan"); s.setAge(8);
Session session = sessionFactory.getCurrentSession(); session.beginTransaction(); session.save(s); session.getTransaction().commit(); }
public static void main(String[] args) { beforeClass(); //检测BUG的方法,如果出现的话 }
@Test public void testStudentDelete() {
} } |
4、综合使用基础配置
4.1、使用Annotation形式来设置上面提到的基础配置
首先建立Hibernate 4建议的工厂取得方法,写一个辅助类HibernateUtil:
package org.hibernate.tutorial.util;
import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() { Configuration cfg = new Configuration(); cfg.configure(); ServiceRegistry sr = new ServiceRegistryBuilder().applySettings( cfg.getProperties()).buildServiceRegistry(); SessionFactory sessionFactory = cfg.buildSessionFactory(sr); try { // Create the SessionFactory from hibernate.cfg.xml // the following is deprecated: // return new Configuration().configure().buildSessionFactory(); return sessionFactory; } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } }
public static SessionFactory getSessionFactory() { returnsessionFactory; } } |
修改教师类teacher:
package com.wolex.hibernate.model;
//注意导入的包 import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient;
@Entity // 指定数据表名为"teachers": @Table(name = "teachers") public class Teacher { private int id; private Stringname; private Stringtitle; private StringspouseName; private Datebirthday; private Sexsex;
@Id @Column(length = 15) // 奇怪的是:如果一个映射类没有@Id,会报错;而且@Id属性的长度无法指定 public int getId() { returnid; }
@Column(name = "tname", length = 20) public String getName() { returnname; }
// 不持久化的属性 @Transient public String getSpouse() { returnspouseName; }
@Column(length = 10) public String getTitle() { returntitle; }
// 但只有一个值的时候,value可写可不写: @Temporal(value = TemporalType.TIME) // 枚举类TemporalType中的其他常量:DATE、TIMESTAMP @Temporal(TemporalType.TIME) public Date getBirthday() { returnbirthday; }
// EnumType.ORDINAL表示采用枚举的序数(1、2。。。) @Enumerated(EnumType.STRING) @Column(length = 10) public Sex getSex() { returnsex; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
public void setId(int id) { this.id = id; }
public void setName(String name) { this.name = name; }
public void setSpouse(String spouse) { this.spouseName = spouse; }
public void setTitle(String title) { this.title = title; }
public void setSex(Sex sex) { this.sex = sex; }
} |
注意,Hibernate中是可以配置没有主键的类映射表,但是在实际中表都存在主键(即使没有,也可以人为添加一个id列),对于@Id指定的属性没有指定长度,请参考ID生产策略。
编写测试类TeacherTest:
package com.wolex.hibernate.model;
import java.util.Date; import org.hibernate.Session; import org.hibernate.tutorial.util.HibernateUtil; import com.wolex.hibernate.model.Teacher;
public class TeacherTest { public static void main(String[] args) { Teacher tea = new Teacher(); tea.setId(1); tea.setName("Theresa"); tea.setTitle("中级"); tea.setBirthday(new Date()); tea.setSex(Sex.FEMALE); Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.save(tea); session.getTransaction().commit(); session.close(); HibernateUtil.getSessionFactory().close(); } } |
Hibernate: drop table teachers cascade constraints Hibernate: create table teachers ( id number(10,0) not null, birthday date, tname varchar2(20), sex varchar2(10), title varchar2(10), primary key (id) ) Hibernate: insert into teachers (birthday, tname, sex, title, id) values (?, ?, ?, ?, ?) |
因为我们上面hbm2ddl.auto配置的是“create”,所以每次hibernate都会把先drop掉原来的表再生成。下面我们查询一下该表:
SQL> DESCRIBE teachers
Name Null? Type
------------------------------------------------- ----------------------------
ID NOTNULL NUMBER(10)
BIRTHDAY DATE
TNAME VARCHAR2(20)
SEX VARCHAR2(10)
TITLE VARCHAR2(10)
SQL> SELECT * FROM teachers;
ID BIRTHDAY TNAME SEX TITLE
---------- --------------- --------------- ------------------------------
1 04-JUN-13 Theresa FEMALE 中级
在Oracle 9i以前时间的数据类型就只有DATE一种,所以如果dialect设置为Oracle(anyversion),则上面TemporalType无论是TIME、DATE、TIMESTAMP都只会在数据库中映射为DATE类型。但是9i引入了两个新的、相关联的数据类型:INTERVAL和TIMESTAMP。
SQL Dialect设置为Oracle(anyversion):
<property name="dialect">org.hibernate.dialect.OracleDialect</property> |
SQL Dialect设置为Oracle 10g:
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> |
那么如果SQL Dialect设置为10g后,Temporal.DATE和Temporal.time都会在数据库中映射为DATE数据类型,如果是Temporal.TIMESTAMP的话,则映射为TIMESTAMP数据类型。至于怎样映射为INTERVAL类型,未知?!。
4.2、使用XML完成配置
package com.wolex.hibernate.model; import java.util.Date;
public class Student { private int id; private Stringname; private long password; private Datebirthday; private DateregistrationDate;
public int getId() { returnid; }
public void setId(int id) { this.id = id; }
public String getName() { returnname; }
public void setName(String name) { this.name = name; }
public Date getRegistrationDate() { returnregistrationDate; }
public void setRegistrationDate(Date registrationDate) { this.registrationDate = registrationDate; }
public long getPassword() { returnpassword; }
public void setPassword(long password) { this.password = password; }
public Date getBirthday() { returnbirthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; } } |
Student类建立好了,下面配置其映射文件Student.hbm.xml:
<?xmlversion="1.0"?> <!DOCTYPEhibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mappingpackage="com.wolex.hibernate.model"> <classname="Student"table="students"> <idname="id"column="stu_id"length="20"></id> <!-- 记得length="",不要忘了加双引号 --> <propertyname="name"column="sname"length="20"></property> <!-- <property name="password" type="java.math.BigDecimal" length="11" precision="2" scale="3"></property> --> <!-- 上面纠结了很久都改变不了最终生成表的number类型的长度与精度 --> <propertyname="password"></property> <propertyname="birthday"type="java.util.Date"></property> <propertyname="registrationDate"type="time"></property> </class>
</hibernate-mapping> |
这里使用到了length只有在类中field的类型是String的时候才有效,如果是int、long等都无效,原因未知!??注意birthday和registrationDate分别设置为不同的类型。
在hibernate.cfg.xml中添加:
<mapping resource="com/wolex/hibernate/model/Student.hbm.xml"/> |
编写测试类,此次不使用hibernateUtil辅助类:
package com.wolex.hibernate.model; import java.util.Date; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import com.wolex.hibernate.model.Student;
public class StudentTest { public static void main(String[] args) { Student stu = new Student(); stu.setId(1); stu.setName("Cyndi"); stu.setPassword(219341); stu.setBirthday(new Date()); stu.setRegistrationDate(new Date());
Configuration cfg = new Configuration(); cfg.configure(); SessionFactory sf; try {// 主要为了观察错误原因 ServiceRegistry sr = new ServiceRegistryBuilder().applySettings( cfg.getProperties()).buildServiceRegistry(); sf = cfg.buildSessionFactory(sr); Session session = sf.openSession(); session.beginTransaction(); session.save(stu); session.getTransaction().commit(); session.close(); sf.close(); } catch (HibernateException e) { e.printStackTrace(); } } } |
查询students表,观察结果:
SQL> DESCRIBE students;
Name Null? Type
------------------------------------------------- ----------------------------
STU_ID NOT NULLNUMBER(10)
SNAME VARCHAR2(20CHAR)
PASSWORD NUMBER(19)
BIRTHDAY TIMESTAMP(6)
REGISTRATIONDATE DATE
SQL> SELECT * FROM students;
STU_ID SNAME PASSWORD BIRTHDAY REGISTRAT
---------- ---------- ---------- ---------------------------------------
1 SoYeon 219341 04-JUN-13 07.21.00.329000PM 04-JUN-13
可见birthday字段的类型是TIMESTAMP,如果java类中属性类型为java.util.Date,那么Student.hbm.xml文件中的type不设置,则默认设置为java.util.Date。