1.更新一个Detached(脱管状态)对象,把它重新变成Persistent(持久化状态),然后在数据库里做更新。


示例:

public void testUpDate1(){
Configuration cfg=new Configuration();
SessionFactory sf=cfg.configure().buildSessionFactory();

Session session=sf.openSession();
session.beginTransaction();
Teacher teacher=(Teacher)session.get(Teacher.class, 1);
session.getTransaction().commit();

teacher.setName("mr.zhang");
Session session2=sf.openSession();
session2.beginTransaction();
session2.update(teacher);
session2.getTransaction().commit();

}




2.更新Transient(游离状态)对象会报错


3.更新自己设定id的Transient(游离状态)对象才可以


示例:


public void testUpDate2(){

//这样更新Transient(游离状态)对象会报错
/*Teacher teacher=new Teacher();
teacher.setName("mr.liu");

Configuration cfg=new AnnotationConfiguration();
SessionFactory sf=cfg.configure().buildSessionFactory();

teacher.setName("mr.zhang");
Session session2=sf.openSession();
session2.beginTransaction();
session2.update(teacher);
session2.getTransaction().commit();*/

//给他设置id,只要数据库中有,就会更新Transient(游离状态)
Teacher teacher=new Teacher();
teacher.setId(8);
teacher.setName("mr.liu");

Configuration cfg=new AnnotationConfiguration();
SessionFactory sf=cfg.configure().buildSessionFactory();

teacher.setName("mr.zhang");
Session session2=sf.openSession();
session2.beginTransaction();
session2.update(teacher);
session2.getTransaction().commit();

}



由于每次更新都要更新所有字段,在你不更新其他多余字段的情况下比较浪费资源,所以要考虑下面的“5.更新部分更改的字段”






4.Persistent状态的对象只要设定不同字段就会发生更新。


public void testUpDate3(){

Configuration cfg=new AnnotationConfiguration();
SessionFactory sf=cfg.configure().buildSessionFactory();

Session session=sf.openSession();
session.beginTransaction();
Teacher teacher=(Teacher)session.get(Teacher.class, 1);
teacher.setTitle("高等");
session.getTransaction().commit();

}

在get出teacher对象时它发出了一条update语句,原因是我们改了它的name了。因为修改数据了,所以在提交(commit();)时,session会检查缓存和数据库的同步情况,当不同步时,就更新数据库至两者同步。不幸的是还是更新了所有字段。






5.更新部分更改的字段


a)xml设定property标签的update属性,annotation设定@Column的updatable属性,不过这种方式很少用,因为不灵活。


annotation做法示例:


@Column(updatable=false)
public String getName() {
return name;
}

在不需要更新的字段或字段的get方法上加Column(updatable=false)注解即可。


xml做法示例:


<property update="false" .../>




b)使用xml中的dynamic-update,JPA1.0 Annotation没有对应的属性(等待hibernate扩展)



xml示例:


例如 <class name="Student" table="student" dynamic-update="true">


对student对象的数据实行动态更新(没改过就不更新了)。



示例:


public void testUpDate4(){

Configuration cfg=new AnnotationConfiguration();
SessionFactory sf=cfg.configure().buildSessionFactory();

Session session=sf.openSession();
session.beginTransaction();
StudentPK sp=new StudentPK();//联合主键
sp.setId(2);
sp.setName("s2");
Student student=(Student)session.get(Student.class, sp);
student.setAge(100);//只更新年龄
session.getTransaction().commit();

}

这里看到hibernate发出的sql语句只更新了一个属性:


update


        student 


    set


        age=? 


    where   //联合主键


        id=? 


        and name=?




题外话:


对于dynamic-update,同一个session可以,跨session不行,不过可以用merge()代替原来的update。merge()将这个对象合并到数据库中,原来没改的就没必要合并了(比较不是从缓存中比较的,而是从数据库load出数据去比较,效率并没有提高多少)(不重要)




c)使用HQL(EJBQL)(建议)


public void testUpDate5(){

Configuration cfg=new AnnotationConfiguration();
SessionFactory sf=cfg.configure().buildSessionFactory();

Session session=sf.openSession();
session.beginTransaction();
//HQL面向对象的查询语言,此时就只会更新name自己
Query q=session.createQuery("update Teacher t set t.name = 't22' where t.id = 2");
q.executeUpdate();
session.getTransaction().commit();

}

观察hibernate发出的sql语句确实如此,很方便。记住,HQL是面向对象的SQL语句。



总结:你要觉得全更新字段效率可以不考虑,就可以不去理会它(说不定数据库中也会进行优化,没改的它就不改了)。