1.Configuration
Configuration对象是进行配置信息的管理,用来产生SessionFactory,可以在configure方法中指定hibernate配置文件,默认配置文件名为hibernate.cfg.xml。
package com.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateUtil {
//SessionFactory中维护的最重要的东西就是数据库连接池
private static final SessionFactory sessionFactory;
static{
try{
sessionFactory =new AnnotationConfiguration().configure().buildSessionFactory();
}catch(Throwable ex){
System.err.println("初始化SessionFactory创建失败"+ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
package com.hibernate.id;
import javax.persistence.Embeddable;
/* 实现Serializable接口的原因之一是:使用get或load方法时,需构建TeacherPK对象的实体,并作为第二个参数传进去
* load(Object object, Serializable id);
* get(Class clazz, Serializable id);
*/
public class TeacherPK implements java.io.Serializable{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//重载hashcode和equals方法来实现主键相等的判断
@Override
public boolean equals(Object obj) {
if(obj instanceof TeacherPK ){
TeacherPK pk=(TeacherPK)obj;
if(pk.getId()==this.id && pk.getName()==this.name)
return true;
}
return false;
}
//比较,先比较hashcode,hashcode相同再用equals比较
@Override
public int hashCode() {
return this.name.hashCode();
}
}
package com.hibernate.id;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
/**
* @author zj
*
* Annotation配置联合主键的三种方式:
* 1.TeacherPK上加@Embeddable,Teacher中的TeacherPK属性上加@Id;
* 2.TeacherPK上无需加注解,Teacher中的TeacherPK属性上加@@EmbeddedId;
* 3.TeacherPK上无需加注解,Teacher中无需定义TeacherPK属性,可以直接定义联合主键中的属性,并在各个属性上都加@Id,
* 在Teacher上加@IdClass(value=TeacherPK.class)。
* 其中:第2、3中比较常用。
*/
@Entity
@IdClass(value=TeacherPK.class)
public class Teacher {
//private TeacherPK pk;
private int id;
private String name;
private Date birthday;
private int age;
private String position;
/*@EmbeddedId
public TeacherPK getPk() {
return pk;
}
public void setPk(TeacherPK pk) {
this.pk = pk;
}*/
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Column(nullable=true)
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//不允许字段参加hibernate SQL语句的更新
@Column(updatable=false)
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
}
2.SessionFactory
org.hibernate.SessionFactory是一个线程安全的Session工厂类,能为不同线程生成不同的Session。SessionFactory维护者Session相关的资源,包括数据库连接池、缓存数据等。
注意openSession()和getCurrentSession()方法的区别:
1)openSession()永远打开新的session;需要手动close。
2)getCurrentSession()在session提交前(commit),如果原来有session,则直接拿已经存在的session,若没有则打开新的session;在session提交后session就消失了;事务提交时自动close。getCurrentSession的用处:同一个事务内的数据操作(如添加用户和记录添加用户日志,要么都完成,要么都失败),用于界定事务边界。
上述两种方式不能混用,两种方式拿到的Session具体实现不同。
3.Session
1)可持久化对象的三种状态
可持久化对象(Persistent Object)就是可以保存进数据库的对象,根据它在程序中的位置不同,可持久化对象可以有一下三种状态:
- Transient(临时状态):对象在保存至数据库之前为临时状态,这时候数据库中没有该对象的信息,该对象的Id属性也为空。如果没有被持久化,程序退出时Transient状态的对象信息将会丢失。
- Persistent(持久化状态):对象在保存进数据库后或者从数据库中加载后、并且没有脱离Session时为持久化状态。这时候数据库中有该对象的信息,该对象的Id为数据库中对应记录的主键值。由于还在Session中,持久化状态的对象可以执行任何有关数据库的操作,例如获取集合属性的值等。
- Detached(分离状态):分离状态是对象曾经处于持久化状态、但是现在已经离开Session了。虽然分离状态的对象有Id值,有对应的数据库记录,但是已经无法执行有关数据库的操作。例如,读取延迟加载的集合属性,可能会抛出LazyInitializeException。
2)load方法和get方法的区别
见下述代码中的注释。
3)update方法
见下述代码中的注释。
package com.hibernate.test;
import java.util.Date;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.hibernate.id.Student;
import com.hibernate.id.StudentPK;
import com.hibernate.id.Teacher;
import com.hibernate.id.TeacherPK;
import com.hibernate.id.Title;
import com.hibernate.util.HibernateUtil;
/*
* 1.Configuration对象的方法buildSessionFactory()
* SessionFactory
* Session:openSession,getCurrentSession
* 2.Session
* 对象的三种状态:Transisent、Persistent、Detached
* load与get的区别;
* update
* saveOrUpdate
* clear
* flush
* SchemaExport
*/
public class HibernateIdTest {
private static SessionFactory sessionFactory;
@BeforeClass
public static void beforeClass(){
sessionFactory=HibernateUtil.getSessionFactory();
}
@Test
public void testTeacherSave(){
/*TeacherPK pk=new TeacherPK();
pk.setId(28);
pk.setName("zhoumingming");*/
Teacher s=new Teacher();
s.setId(1);
s.setName("baihe");
//s.setPk(pk);
s.setBirthday(new Date());
Session session=sessionFactory.openSession();
//Session session2=sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(s);
session.getTransaction().commit();
session.close();
}
/*
* 测试可持久化对象(Persistent Object)的三种状态:
* 1.Transient(临时状态):内存中有一个对象,没有id,缓存中也没有
* 2.Persistent(持久化状态):内存中有,内存和数据库中都有id
* 3.Detached(分离状态):内存中无id,数据库中有id
*/
public void testTeacher3State(){
/**************Transient****************/
Teacher s=new Teacher();
s.setId(2);
s.setName("mingming");
s.setBirthday(new Date());
s.setAge(25);
s.setPosition("professor");
Session session=sessionFactory.openSession();
session.beginTransaction();
session.save(s);
/**************Persistent****************/
session.getTransaction().commit();
session.close();
/**************Detached****************/
s.setId(3);
s.setName("jingjing");
s.setBirthday(new Date());
s.setAge(23);
s.setPosition("adjunct professor");
Session session2=sessionFactory.openSession();
session2.beginTransaction();
session2.save(s);
/**************Persistent****************/
session2.getTransaction().commit();
session2.close();
/**************Detached****************/
}
public void testTeacherDelete(){
Teacher s=new Teacher();
s.setId(3);
s.setName("jingjing");
Session session=sessionFactory.openSession();
session.beginTransaction();
session.delete(s);
session.getTransaction().commit();
session.close();
}
public void testTeacherLoad(){
TeacherPK pk=new TeacherPK();
pk.setId(2);
pk.setName("mingming");
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
//使用load获得是对象的代理,并没有真正的发出SQL语句,SQL语句是在访问对象属性的时候才发出(延迟到访问对象属性时才加载)
//所要获取的对象不存在时,不报错,因为它根本就不发SQL语句
Teacher t=(Teacher)session.load(Teacher.class, pk);
System.out.println(t.getClass());//输出结果为:class com.hibernate.id.Teacher_$$_javassist_0,为Teacher的一个子类
//此时获取对象的属性不存在时,报org.hibernate.ObjectNotFoundException
System.out.println("load一个Teacher对象:"+t.getId()+" "+t.getName()+" "+t.getBirthday());
session.getTransaction().commit();
/* 在commit之后即session关闭之后访问t会报错:org.hibernate.LazyInitializationException
* System.out.println("load一个Teacher对象:"+t.getId()+" "+t.getName()+" "+t.getBirthday());
*/
}
public void testTeacherGet(){
TeacherPK pk=new TeacherPK();
pk.setId(3);
pk.setName("jingjing");
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
//使用get获取对象是直接发出SQL语句,然后从数据库中拿到数据,装入对象(直接从数据库加载,不会延迟)
//所要获取的对象不存在时,报java.lang.NullPointerException错
Teacher t=(Teacher)session.get(Teacher.class, pk);
System.out.println(t.getClass());//输出结果为:class com.hibernate.id.Teacher
session.getTransaction().commit();
System.out.println("get一个Teacher对象:"+t.getId()+" "+t.getName()+" "+t.getBirthday());
}
public void testTeacherUpdate1(){
//更新transient状态的对象,需要事先设定好transient对象的id,否则会报错
TeacherPK pk=new TeacherPK();
pk.setId(3);
pk.setName("jingjing");
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Teacher t=(Teacher)session.get(Teacher.class, pk);
session.getTransaction().commit();
//detached状态的对象,变persistent状态,同时数据库做更新
t.setBirthday(new Date());
t.setAge(25);
t.setPosition("lecturer");
Session session2=sessionFactory.getCurrentSession();
session2.beginTransaction();
session2.update(t);
session2.getTransaction().commit();
}
public void testTeacherUpdate2(){
//更新transient状态的对象,需要事先设定好transient对象的id,否则会报错
TeacherPK pk=new TeacherPK();
pk.setId(3);
pk.setName("jingjing");
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Teacher t=(Teacher)session.get(Teacher.class, pk);
//persistent状态的对象只要设定不同的字段就会发生更新,都不用写update就会更新,但若字段内容没变则不会更新
t.setAge(42);
session.getTransaction().commit();
}
@Test
public void testTeacherClear(){
TeacherPK pk=new TeacherPK();
pk.setId(2);
pk.setName("mingming");
//缓存中有对象时,则直接从缓存中获取对象,不再从数据库中拿数据
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Teacher t=(Teacher)session.load(Teacher.class, pk);
System.out.println(t.getClass()+t.getName());
//作用:强制清除Session缓存。无这条代码时,仅发一次SQL语句;有这条代码时,则发两次SQL语句
session.clear();
Teacher t2=(Teacher)session.load(Teacher.class, pk);
System.out.println(t2.getClass()+t2.getName());
session.getTransaction().commit();
}
public void testTeacherFlush(){
TeacherPK pk=new TeacherPK();
pk.setId(2);
pk.setName("mingming");
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
Teacher t=(Teacher)session.load(Teacher.class, pk);
t.setAge(22);
//作用:强制将缓存内容和数据库内容做同步
session.flush();
t.setAge(23);
//默认在commit时才将缓存内容和数据库内容同步
session.getTransaction().commit();
}
@Test
public void testSchemaExport(){
//在程序中生成建表语句,而不是xml文件中
(new SchemaExport(new AnnotationConfiguration().configure())).create(true, true);
}
@AfterClass
public static void afterClass(){
sessionFactory.close();
}
}