05_传智播客hibernate教程_实体对象的三种状态与saveOrUpdate方法

脱管引发出来的知识点
对象的状态:
// 准确的说是Hibernate对象的状态,和session和数据库有微妙关系
瞬时(transient):
持久(persistent):
脱管(detached):
三种状态分析
瞬时状态时对象跟session和数据库都木有关系;session中木有该对象,数据库中木有这条记录对应;生命周期很短;
持久状态时对象保存在session中,他如果有任何变化,数据库都会做出对应修改;
脱管状态时对象是session关闭之后的对象,数据库中有对应的记录,但session中木有了。脱管对象再发生变化,数据库不会再进行对应调整;此时的对象ID是有值的;
个人分析by kang.cunhua
国外的科技工作者研究工作做得很细致,同时导致了很多抽象名词的产生,加上汉语的博大精深,就会出现一些莫名其妙或高深莫测的翻译;看不懂或者懒得看官方解释的,且看以下数行个人分析;
瞬时,持久和脱管,都是针对的一个对象的三种不同阶段的状态,

  • 瞬时状态对应对象的产生和赋值;(对象:啊~,我生在甲骨文,长在Hibernate下。我将接受Hibernate和Java给予我的教育和责任!Hibernate:你要牢记Hibernate和Java赋予你的责任和义务,好好学习,天天向上,争取早日加入hibernate,为Hibernate和Java做贡献!// 注,本来应该是生在SUN的,但最近SUN被甲骨文收购了。)
  • 持久状态对应对象进入Hibernate的作用域(Hibernate:现在我罩着你;对象:我光荣的加入了持久层)
  • 脱管状态对应对象脱离Hibernate的作用域,已完成持久化的使命,退出持久层的舞台。(Hibernate:祝贺你光荣地从舞台退休了!我代表Hibernate和Java感谢你对持久层做出的贡献!);脱离了Hibernate的舞台,你的所作所为都和持久层木有任何关系了。从现在开始,你要为你自己的行为负全责!

废话罗嗦完了,且看精彩的地方!
Hibernate对对象划分了三种状态,瞬时、持久、和脱管。只有处于持久状态(session开启和木有关闭之前),对象的任何改动都会同步变更到数据库;那么问题来了,我接收到一个参数,是个对象,我怎么知道这个对象是瞬时的还是脱管的?
Hibernate的高明设计:

  • hibernate设计了两种方法saveOrUpdate方法和merge方法来自动处理状态不明的Object(对象)参数;hibernate自己去做处理。
  • 两者的区别在于,saveOrUpdate方法在于处理完后对象会变成持久的;merge方法处理完之后,对象会变成脱管的;不管对象之前是什么状态;

新问题来了:Hibernate的判断依据是虾米:
根据ID,瞬时对象的id是0,而脱管对象是有值的,且>0。如果id是string,则默认是null;这个id的默认值可以在Hibernate的映射文件如User.hbm.xml中来配置,<id name="id" unsaveed-value="-1">;不推荐自定义;很少用到;
Hibernate会在某个状态将持久状态的对象更新到数据库。现在可以理解为到提交(commit;)的时候。具体是哪个时间点儿,且看后续教程讲解;
对象状态转换图:
对象的三种Hibernate状态

来一段代码,说明一下:

    /**
     * Hibernate简洁调用模板
     * @param user
     */
    static void addUser1(User user) {
        Session s = null;
        Transaction tx = null;
        try {
            s = HibernateUtil.getSession();
            tx = s.beginTransaction();
            s.save(user);
            user.setName("new name"); // 此时的对象是持久对象,此处更新user会对数据库也做更新
            user.setBirthday( new Date() );
            /**
             * 此时又做了一条update,但在Hibernate并不会立即更新数据库。
             * 而会做一些优化,比如合并这两条更新为一条update语句,在某个时间点做此更新。
             * 所以在控制台可以看到只有一条update语句输出;
             * 现在可以理解为提交的时候。后续会详细讲解具体提交的时间点;
             */
            tx.commit();
        } finally {
            if (s != null) {
                s.close();
            }
        }
    }

源码列表:
这一讲仅更新了一个文件

Mian.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.itcast.hibernate.domain;

import cn.itcast.hibernate.HibernateUtil;
import java.util.Date;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author kang.cunhua
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        User user = new User();
        user.setBirthday(new Date());
        user.setName("谷歌");

        System.out.println("----- Hibernate标准调用模板演示 -----");
        addUser(user);
        //addUser1(user); // Hibernate简介调用模板演示
        System.out.println("id:" + user.getId());

        System.out.println("----- 根据ID得到对象:演示get方法; -----");

        User u = getUser(user.getId());
        System.out.println("name:" + u.getName());

        System.out.println("----- 根据ID得到对象:演示load方法; -----");

        u = getUserByLoad(user.getId());
        // System.out.println("name:" + u.getName()); // 此处调用会报错。和懒加载有关系;且看后续讲解
        System.out.println(u.getClass().getName());

        System.out.println("----- 此处演示对象的Hibernate三种状态[瞬时,持久,脱离]以及Hibernate的提交时的优化; -----");
        addUserTest(user);
        System.out.println("----- 根据ID得到对象:演示get方法; -----");

    }

    /**
     * Hibernate标准调用模板
     * @param user
     */
    static void addUser(User user) {
        Session s = null;
        Transaction tx = null;
        try {
            s = HibernateUtil.getSession();
            tx = s.beginTransaction();
            s.save(user);
            tx.commit();
        } catch (HibernateException e) {  //catch部分可以省略。效果一致;
            if (tx != null) {
                tx.rollback();
            }
            throw e; //注意,此处必须抛出异常,而不能捕获异常却不处理!
        } finally {
            if (s != null) {
                s.close();
            }
        }
    }

    /**
     * Hibernate简洁调用模板
     * @param user
     */
    static void addUser1(User user) {
        Session s = null;
        Transaction tx = null;
        try {
            s = HibernateUtil.getSession();
            tx = s.beginTransaction();
            s.save(user);
            tx.commit();
        } finally {
            if (s != null) {
                s.close();
            }
        }
    }

    static void addUserTest(User user) {
        Session s = null;
        Transaction tx = null;
        try {
            s = HibernateUtil.getSession();
            tx = s.beginTransaction();
            s.save(user);

            System.out.println("----- 此时调用user.setName,但提交时不会输出对应Update语句; -----");

            user.setName("new name"); // 此时的对象是持久对象,此处更新user会对数据库也做更新

            System.out.println("----- 此时调用user.setBirthday,但提交时不会输出对应Update语句; -----");

            user.setBirthday(new Date());
            /**
             * 此时又做了一条update,但在Hibernate并不会立即更新数据库。
             * 而会做一些优化,比如合并这两条更新为一条update语句,在某个时间点做此更新。
             * 所以在控制台可以看到只有一条update语句输出;
             * 现在可以理解为提交的时候。后续会详细讲解具体提交的时间点;
             */
            System.out.println("----- 此时调用tx.commit(),会输出所有优化后的SQL语句,包括一条更新了两个值的Update语句,而不是两条update语句; -----");
            tx.commit();
        } finally {
            if (s != null) {
                s.close();
            }
        }
    }

    /**
     * 根据ID得到对象:演示get方法;
     * @param id
     * @return
     */
    static User getUser(int id) {
        Session s = null;
        try {
            s = HibernateUtil.getSession();
            Class userClass = User.class;
            User user = (User) s.get(userClass, id);
            return user;
        } finally {
            if (s != null) {
                s.close();
            }
        }
    }

    /**
     * 根据ID得到对象:演示load方法;
     * @param id
     * @return
     */
    static User getUserByLoad(int id) {
        Session s = null;
        try {
            s = HibernateUtil.getSession();
            Class userClass = User.class;
            User user = (User) s.load(userClass, id);
            System.out.println("----- ##User getUserByLoad(int id)## start -----");
            System.out.println("name:" + user.getName());
            System.out.println("----- ##User getUserByLoad(int id)## end -----");
            return user;
        } finally {
            if (s != null) {
                s.close();
            }
        }
    }
}
//run:
//----- Hibernate标准调用模板演示 -----
//log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
//log4j:WARN Please initialize the log4j system properly.
//Hibernate: insert into User (name, birthday) values (?, ?)
//id:26
//----- 根据ID得到对象:演示get方法; -----
//Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_ from User user0_ where user0_.id=?
//name:谷歌
//----- 根据ID得到对象:演示load方法; -----
//----- ##User getUserByLoad(int id)## start -----
//Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_ from User user0_ where user0_.id=?
//name:谷歌
//----- ##User getUserByLoad(int id)## end -----
//cn.itcast.hibernate.domain.User$$EnhancerByCGLIB$$ddacf5c4
//----- 此处演示对象的Hibernate三种状态[瞬时,持久,脱离]以及Hibernate的提交时的优化; -----
//Hibernate: insert into User (name, birthday) values (?, ?)
//----- 此时调用user.setName,但提交时不会输出对应Update语句; -----
//----- 此时调用user.setBirthday,但提交时不会输出对应Update语句; -----
//----- 此时调用tx.commit(),会输出所有优化后的SQL语句,包括一条更新了两个值的Update语句,而不是两条update语句; -----
//Hibernate: update User set name=?, birthday=? where id=?
//----- 根据ID得到对象:演示get方法; -----
//成功生成(总时间:1 秒)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值