Hibernate 常用更新数据方法(机制)

Hibernate随记——常用更新数据方法\机制

----文章内容属于基础范围。
在了解Hibernate常用数据更新方法之前,我们首先了解一下Hibernate的三种状态,以及状态之间的转换。

Hibernate 的三种状态

  • 在Hibernate中,对象的存在状态有三种,分别是:Transient(瞬时状态)、Persistent(持久化状态)、Detached(脱管/游离状态)。这三种状态的区别在于:

    1.Transient:处于瞬时状态时,对象只存在于JVM内存中,并没有和Hibernate中的Session关联,没有纳入到Hibernate的缓存管理中去,在数据库中也没有与对象对应的记录。如:新建一个对象时,该对象就处于瞬时状态。
    2.Persistent:处于持久化状态时,对象不仅在内存中占有空间,Hibernate缓存Session中也存在该对象,并且数据库表中有与该对象对应的记录,主键值确定。
    3.Detached:处于游离状态时,对象在内存中存在,在数据库中有与之对应的记录,但是不存在于Session缓存中
    示例如下:

        //  新建一个User类对象,此时user处于瞬时状态(Transient)
        User user=new User();
        user.setId(1);
        user.setName("Luvjuin");
        //  获取Session
        Configuration cfg=new Configuration().configure();
        SessionFactory sf=cfg.buildSessionFactory();
        Session session=sf.openSession();
        //开启事务
        session.beginTransaction();
        //保存user对象到数据库
        //事务提交后,对象将会处于持久化状态(Persistent)
        session.save(user);
        //事务提交
        session.getTransaction().commit();
        //关闭Session和SessionFactroy
        //此时user对象将处于游离状态(Detached)
        session.close();
        sf.close();

    4.三种状态之间的转换

    Hibernate 常用更新数据方法(机制)_第1张图片

    • transient:是由new 命令开辟的内存对象,意义仅是携带信息的载体,不和数据库中的数据有任何的关联。
    • persistent:持久的实例在数据库中有对应的记录,拥有一个持久化标识。在执行commit之后,才在数据据库中真正运行SQL进行变更
    • detached:与持久对象关联的Session被关闭后,对象变为托管的。对托管对象的引用依然有效,对象可以继续被修改。托管对象如果重新关联到某个新的Session上,会再次转变为持久化对象。托管期间的改动将会被持久化到数据库。

常用更新数据方法(机制)

在了解了Hibernate的三种状态之后,我们就可以对其常用更新数据方法进行测试。(Hibernate基础配置和类已经写好)

update(更新)

  • Persistent状态下对象没变化则不会发出SQL语句(即使手动调用update方法也不会发出update语句),有变化则自动发出update语句更新所有字段。不需要手动调用update()方法

    1.对象没有发生变化时:
    控制台输出的SQL语句只有get()方法发出的select语句,说明对象属性没变,即使调用update()方法,事务提交后也不会发出update语句。

        Session session = sessionFactory.openSession();
        session.beginTransaction();
        //获取user ,处于持久化(Persistent)状态
        User user=session.get(User.class, 1);
        //更新
        session.update(user);
        //提交事务
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();

    控制台输出:

    Hibernate 常用更新数据方法(机制)_第2张图片

    2.对象发生变化时
    控制台输出的SQL语句不仅有get()方法发出的select语句,还有一条update语句,说明在持久化状态下的对象的属性一旦变化,事务提交后,同时会自动(代码中没有手动调用update()方法)更新数据库中的记录。所有字段都将更新。

        Session session = sessionFactory.openSession();
        session.beginTransaction();
        //获取user ,处于持久化(Persistent)状态
        User user=session.get(User.class, 1);
        //此时修改user的属性
        user.setPassword("123456");
        //提交事务
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();

    控制台输出了update语句:

    Hibernate 常用更新数据方法(机制)_第3张图片

    根据以上知:Persistent状态下对象没变化则不会发出SQL语句,有变化则自动发出update语句更新所有字段。这种机制在某个表的字段非常多的情况下,程序执行效率将会大大降低,因为一旦改动某个字段,将会update所有字段值,虽然其他字段值没变。

  • Persistent状态下,修改了对象的属性,但只想要update修改过的字段值,做法如下
    如上要求,只需要修改xxx.hbm.xml配置文件即可。
    在对应的对象映射配置文件中的class标签上增加一个属性 dynamic-update=“true”。表示开启动态更新。这样,处于持久化状态下的对象变化时,update语句更新的只是变化的字段,不会更新所有字段。

     <class name="bean.User" table="TB_USER" schema="YP" dynamic-update="true">

    依旧是上面的代码,将user.setPassword(“123456”)改为user.setPassword(“123”)(因为上面程序执行过一次,password值为123456,如果不改,值没变),运行程序,控制台输出:update 只更新了password,并没有更新name。

    Hibernate 常用更新数据方法(机制)_第4张图片

  • Detached状态下不管JVM内存中对象的属性值和数据库表中的值是否一致,调用update方法后一定会发出一条update语句,这和Persistent状态下是不一致的

    运行以下代码,从数据库中get()到的user属性没有变过,关闭前一个Session后,对象处于游离状态。开启另外一个Session,手动调用update(),控制台输出update语句。

        Session session = sessionFactory.openSession();
        session.beginTransaction();
        //获取user ,此时处于持久化(Persistent)状态
        User user=session.get(User.class, 1);
        //提交事务
        session.getTransaction().commit();
        session.close();
        //session关闭之后处于游离(Detached)状态
        //开启另外一个Session
        Session session2=sessionFactory.getCurrentSession();
        session2.beginTransaction();
        session2.update(user);//处于持久化状态
        session2.getTransaction().commit();
        session2.close();//游离状态
        sessionFactory.close();

    Hibernate 常用更新数据方法(机制)_第5张图片

    例子说明:Detached状态下不管JVM内存中对象的属性值和数据库表中的值是否一致,调用update方法后一定会发出一条update语句,而Persistent状态下只有对象变化了才会发出update语句。

  • Detached状态下使用merge()方法更新数据

    把上面代码中的session2.update(user)更改为session2.merge(user)。运行程序,会发现控制台输出了两条select语句,并没有像上述一样:游离状态下不管对象有没有变,都会发出update语句。

        Session session = sessionFactory.openSession();
        session.beginTransaction();
        //获取user ,此时处于持久化(Persistent)状态
        User user=session.get(User.class, 1);
        //提交事务
        session.getTransaction().commit();
        session.close();
        //session关闭之后处于游离(Detached)状态
        //开启另外一个Session
        Session session2=sessionFactory.getCurrentSession();
        session2.beginTransaction();
        session2.merge(user);//处于持久化状态
        session2.getTransaction().commit();
        session2.close();//游离状态
        sessionFactory.close();

    Hibernate 常用更新数据方法(机制)_第6张图片

    这是因为游离状态下merge()方法总会发出一条select语句(所以控制台打印了两条select),然后将select到的数据与内存中的对象进行对比,如果不一致,则发出update语句,且只会更新不一样的字段,不会更新所有字段,之后进入持久化状态。如果内存中的对象与select到的数据一致,则不会发出update()。

  • Transient状态下更新数据要指定主键,否则不能更新

    Transient状态下,对象只存在于内存中。此时如果调用update()方法去更新数据库,则该对象对应数据库中主键的属性值必须要有,不能为空。如果为空,则会报错。

        Session session = sessionFactory.openSession();
        session.beginTransaction();
        //新建一个对象 瞬时状态
        User user = new User();
        user.setName("jkl");
        user.setPassword("123456");
        // 主键值确定
        user.setId(1);
        //update
        session.update(user);
        // 提交事务  持久化状态
        session.getTransaction().commit();
        session.close();
        //游离状态
        sessionFactory.close();

    在User 类中,id为数据库中的主键。如果将以上代码中 的user.setId(1) 去掉,则运行程序的时候报错:The given object has a null identifier:bean.User。(user对象的id属性为空,但该值在数据库表中应该为主键)

saveOrUpdate()方法

在调用这个方法前,我们要将xxx.hbm.xml配置文件中的主键生成策略改为native

调用这个方法时,如果对象的对应主键值确定的话,那么事务提交之后,会发出update()语句更新所有字段;如果对象的对应主键值不确定时,会发出select语句,保存一条新记录

        Session session = sessionFactory.openSession();
        session.beginTransaction();
        //新建一个对象 瞬时状态
        User user = new User();
        user.setName("uiooj");
        user.setPassword("123456");
        // 主键值确定
        user.setId(1);
        //update
        session.saveOrUpdate(user);
        // 提交事务  持久化状态
        session.getTransaction().commit();
        session.close();
        //游离状态
        sessionFactory.close();

Hibernate 常用更新数据方法(机制)_第7张图片

如果将user.setId(1)注释掉,那么主键值不确定,运行程序后会发出insert 语句,插入一条新纪录。

Hibernate 常用更新数据方法(机制)_第8张图片

由以上看出:saveOrUpdate()方法调用时,如果
对象对应的主键值确定:update;
对象对应的主键值不确定:insert;

flush()方法和clear()方法

flush()方法指的是强制缓冲数据与数据库数据保持一致;
clear()方法指的是清空缓存。

详解参考如下:

王康的技术博客—flush()和clear()方法详解

你可能感兴趣的:(Hibernate,随记)