• Hibernate之Session对象的相关方法以及持久化对象的状态


    一、持久化对象的状态     

           站在持久化的角度, Hibernate 把对象分为 4种状态: 持久化状态,临时状态,游离状态,删除状态.Session 的特定方法能使对象从一个状态转换到另一个状态.  

    •临时对象(Transient):

    –在使用代理主键的情况下, OID 通常为null

    不处于 Session的缓存中

    在数据库中没有对应的记录

    •持久化对象(也叫”托管”)(Persist):

    OID 不为null

    位于 Session缓存中

    –若在数据库中已经有和其对应的记录,持久化对象和数据库中的相关记录对应

    Session flush缓存时,会根据持久化对象的属性变化,来同步更新数据库

    在同一个 Session实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象

    •删除对象(Removed)
    –在数据库中没有和其OID对应的记录
    –不再处于Session缓存中
    –一般情况下,应用程序不该再使用被删除的对象
    •游离对象(也叫”脱管”)(Detached):
    OID不为null
    不再处于Session缓存中

    –一般情况需下,游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录

    二、Session进行对象持久化的相关方法

          1.save() 方法:   

    •Session 的save()方法使一个临时对象转变为持久化对象

    •Session 的save()方法完成以下操作:

    News对象加入到Session缓存中,使它进入持久化状态

    选用映射文件指定的标识符生成器, 为持久化对象分配唯一的OID.在使用代理主键的情况下, setId()方法为News对象设置OID使无效的.

    计划执行一条 insert 语句:在 flush缓存的时候
    注意:
    •Hibernate 通过持久化对象的OID来维持它和数据库相关记录的对应关系.当News对象处于持久化状态时,不允许程序随意修改它的 ID

    /**
    	 * 1.使一个临时对象变为持久化对象
    	 * 2.为对象分配id
    	 * 3.在flush()缓存时,会发送一条insert语句
    	 * 4.在save方法之前的id是无效的
    	 * 5.持久化对象的id是不能被修改的
    	 */
    	@Test
    	public void testSave(){
    		News news=new News();
    		news.setAuthor("杜甫");
    		news.setTitle("笑傲江湖");
    		news.setDate(new Date());
    		System.out.println(news);
    		session.save(news);
    		System.out.println(news);
    	}

    运行结果:可以发现save方法执行前后对象的变化

    News [id=null, title=笑傲江湖, author=杜甫, date=Tue Aug 11 20:46:40 CST 2015]
    Hibernate: 
        insert 
        into
            NEWS
            (TITLE, AUTHOR, DATE) 
        values
            (?, ?, ?)
    News [id=5, title=笑傲江湖, author=杜甫, date=Tue Aug 11 20:46:40 CST 2015]
    2、persist()方法

    persist() save()区别
    当对一个OID不为Null的对象执行save()方法时,会把该对象以一个新的oid保存到数据库中;  但执行 persist()方法时会抛出一个异常
    /**
    	 * 1.persist()方法同样会执行insert操作
    	 * 2.和save()区别:
    	 *   在调用persist()方法之前,若对象已经有id,则不会执行insert,并抛出异常
    	 */
    	@Test
    	public void testPersist(){
    		News news=new News();
    		news.setAuthor("王维");
    		news.setTitle("射雕英雄传");
    		news.setDate(new Date());
    		news.setId(200);
    		System.out.println(news);
    		session.persist(news);
    	}
    3、get() 方法与load() 方法:

    •都可以根据跟定的 OID 从数据库中加载一个持久化对象

    •区别:

    –当数据库中不存在与 OID 对应的记录时,load() 方法抛出 ObjectNotFoundException异常,而get()方法返回null

    –两者采用不同的延迟检索策略:load方法支持延迟加载策略。而get 不支持

    /**
    	 * 加载一条对象到内存中
    	 */
    	@Test
    	public void testGet(){
    		News news=(News) session.get(News.class, 3);
    		System.out.println(news);
    	}
    	
    	/**
    	 * get vs load 区别
    	 * 1.执行get()方法会立即加载该对象,若执行load(),如果不立即使用此对象,则不会立即执行查询操作,而返回一个代理对象
    	 *   get是立即加载,load是延迟加载
    	 * 2.若数据表中没有对应的记录,get返回null,load若不实用对象,没问题,若需要初始化,抛出异常。
    	 * 3.load方法可能会抛出懒加载异常:在需要初始化代理对象之前已经关闭了session
    	 * 
    	 */
    	@Test
    	public void testLoad(){
    		News news=(News) session.load(News.class, 3);
    		System.out.println(news);
    	}

    4、update() 方法:

    •Session 的 update()方法使一个游离对象转变为持久化对象,并且计划执行一条update语句.

    •若希望 Session仅当修改了News对象的属性时,才执行update()语句,可以把映射文件中<class>元素的select-before-update设为true.该属性的默认值为false

    update()方法关联一个游离对象时,如果在Session的缓存中已经存在相同 OID的持久化对象,会抛出异常

    •当 update()方法关联一个游离对象时,如果在数据库中不存在相应的记录,也会抛出异常. 

    /**
    	 * update:
    	 * 1.若更新一个持久化对象,不需要显式调用update()方法,因为在调用commit()方法时,会先执行session的flush
    	 * 2.更新一个游离对象,需要显式的调用update方法,更新之后,并把该游离对象转化为持久化对象
    	 * 3.需要注意的:
    	 *   a.无论要更新的游离对象和数据表的记录是否一致,都会发送update语句,
    	 *     如何能让update语句不盲目的发出SQL语句(尤其在对象未改变的情况下)呢?在.hbm.xml文件的class节点设置
    	 *     select-before-update=true(此属性默认为false,通常不需要设置)即可
    	 *   b.若数据表中没有对应记录,但还调用了update方法,则会抛出异常
    	 *   c.用update关联一个游离对象的时候,若session缓存中已经存在一个相同OID的对象,则会抛出异常,因为在session缓存中
    	 *     不能有2个OID相同的对象。
    	 */
    	@Test
    	public void testUpdate(){
    		News news=(News) session.get(News.class, 3);
    		
    		transcation.commit();
    		session.close();
    		
    		session=sessionFactory.openSession();
    		transcation=session.beginTransaction();
    		
    		news.setAuthor("金庸");
    		session.update(news);
    		
    	}

    5、saveOrUpdate() 方法

    •Session 的 saveOrUpdate()方法同时包含了save()与update()方法的功能,当对象为游离对象时,执行update,对象为临时对象时,执行insert

    •判定对象为临时对象的标准

    Java 对象的 OID null

    –映射文件中为<id>设置了unsaved-value  属性,并且Java对象的OID取值与这个unsaved-value属性值匹配

    /**
    	 * 1、当setId() 方法未注释时,对象存在id,发出update语句,当注释掉的时候,发出insert语句
    	 * 2、若对象的id不为null,并且数据表中没有与之对应的记录,则会抛出异常
    	 * 
    	 */
    	@Test
    	public void testSaveOrUpdate(){
    		News news=new News();
    		news.setAuthor("王勃");
    		news.setTitle("凉州词");
    		news.setDate(new Date());
    		news.setId(1);
    		session.saveOrUpdate(news);
    	}
    6、delete() 方法

    •Session 的 delete()方法既可以删除一个游离对象,也可以删除一个持久化对象

    •Session 的 delete()方法处理过程

    –计划执行一条 delete语句

    –把对象从 Session缓存中删除,该对象进入删除状态.

    •Hibernate 的 cfg.xml配置文件中有一个hibernate.use_identifier_rollback属性,其默认值为false,若把它设为true,将改变delete()方法的运行行为:delete() 方法会把持久化对象或游离对象的 OID设置为null,使它们变为临时对象

    /**
    	 * 1.执行删除操作,只要OID与数据表一条记录对应,就会执行delete操作,若没有对应记录,则会抛出异常
    	 * 
    	 */
    	@Test
    	public void testDelete(){
    		News news=new News();
    		news.setId(2);
    		session.delete(news);
    	}
    7、evict() 方法:从缓存中移除指定的持久化对象
    8、Hibernate调用存储过程:

    •Session 的 doWork(Work)方法用于执行Work对象指定的操作,即调用Work对象的execute()方法.Session 会把当前使用的数据库连接传递给 execute()方法.

    @Test
    	public void testDoWork(){
    		session.doWork(new Work() {
    			
    			@Override
    			public void execute(Connection connection) throws SQLException {
    				// 调用存储过程
    				String procedure="{call testProcedure()}";
    				CallableStatement cs=connection.prepareCall(procedure);
    				cs.executeUpdate();
    				
    			}
    		});
    	}
    9、Hibernate与触发器协同工作:

    •Hibernate与数据库中的触发器协同工作时,会造成两类问题

    –触发器使 Session的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中,它执行的操作对Session是透明的

    –Session 的 update()方法盲目地激发触发器:无论游离对象的属性是否发生变化,都会执行update语句,而update语句会激发数据库中相应的触发器

    •解决方案:

    –在执行完 Session的相关操作后,立即调用Session的flush()和refresh()方法,迫使Session的缓存与数据库同步(refresh()方法重新从数据库中加载对象)

    –在映射文件的的 <class>元素中设置select-before-update属性:当Session的update或saveOrUpdate()方法更新一个游离对象时,会先执行Select语句,获得当前游离对象在数据库中的最新数据,只有在不一致的情况下才会执行update语句















  • 相关阅读:
    基于NFS实现多WEB服务器负载均衡
    CentOS 6编译安装lamp,并分别安装event模块方式和FPM方式的PHP
    CentOS 7 下的LAMP实现以及基于https的虚拟主机
    ssh 免密码设置失败原因总结
    任督二脉之进程管理(3)
    任督二脉之进程管理(4)
    任督二脉之进程管理(1)
    任督二脉之进程管理(2)
    VIRTIO概述和基本原理
    图解 TCMalloc
  • 原文地址:https://www.cnblogs.com/elgin-seth/p/5293779.html
Copyright © 2020-2023  润新知