基于mvc模式的应用框架之Hibernate(五)

本文介绍了ORM中对象的不同状态及其转换过程,并详细探讨了一级缓存的工作原理及懒加载特性,帮助理解Hibernate等框架如何高效操作数据库。

一、对象的状态

1.瞬时/临时状态(Transient Objects)

使用new操作符初始化的对象不是立刻就持久化的,他们的状态是瞬时的。
(1) 不处于Session的缓存中,也可以说,不被任何一个Session实例关联。
(2) 在数据库中没有对应的记录。

2.持久化状态(Persist Objects)

持久实例是任何具有数据库标识的实例。它有持久化管理器Session统一管理,持久实例是在事务中进行操作的———他们的状态在事务结束时同数据库进行同步。
(1) 位于一个Session实例的缓存中,也可以说,持久化对象总是被一个Session实例关联。
(2) 持久化对象和数据库中的相关记录对应。
(3) Session在清理缓存时,会根据持久化对象的属性变化,来同步更新数据库。

3.离线/游离对象(Detached Objects)

Session关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,他们不再受Hibernate管理。
(1) 不再位于Session的缓存中,也可以说,游离对象不被Session关联。
(2) 游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录(前提条件是没有其他程序删除了这条记录)。

4.对象状态转换图

这里写图片描述

5.核心代码
Session session = SessionUtils.getSession();
Transaction transaction = session.beginTransaction();       
User  user = (User) session.get(User.class, 1);
user.setName(“jack”);
user.setAge(30);
user.setBirthday(new Date());
transaction.commit();
6.完整案列
JavaBean代码
public class User 
{
    private int userId;
    private String userName;
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    @Override
    public String toString() {
        return "User [userId=" + userId + ", userName=" + userName + "]";
    }
}
状态代码
public class App1_status
 {
    private static SessionFactory sf;
    static {
        sf = new Configuration()
            .configure()
            .addClass(User.class)   // 测试时候使用
            .buildSessionFactory();
    }

    //1. 对象状态的转换
    @Test
    public void testSaveSet() throws Exception 
    {
        Session session = sf.openSession();
        session.beginTransaction();
        //创建对象【临时状态】
        //User user = new User();
        //user.setUserName("Jack22222");
        //保存【持久化状态】
        //session.save(user);   
        // 会反映到数据库  
        //user.setUserName("Jack333333");  
        // 查询
        User user = (User) session.get(User.class, 5);
        // hibernate会自动与数据库匹配(一级缓存),如果一样就更新数据库
        user.setUserName("Tomcat");

        session.getTransaction().commit();
        session.close();
        user.setUserName("Jack444444444");
        //打印【游离状态】
        System.out.println(user.getUserId());
        System.out.println(user.getUserName());
    }

    @Test
    public void bak() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        session.getTransaction().commit();
        session.close();
    }
}

二.一级缓存

1).Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效!
2).当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session的缓存中。
3).Session的缓存由hibernate维护, 用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。
特点:
只在(当前)session范围有效,作用时间短,效果不是特别明显!
在短时间内多次操作数据库,效果比较明显!

1.缓存相关几个方法的作用
session.flush();       让一级缓存与数据库同步
session.evict(arg0);   清空一级缓存中指定的对象
session.clear();       清空一级缓存中缓存的所有对象
2.批量操作使用使用
Session.flush();   // 先与数据库同步
Session.clear();   // 再清空一级缓存内容
3.不同的session是否会共享缓存数据?
不会
4.list与iterator查询的区别?

list()
一次把所有的记录都查询出来,
会放入缓存,但不会从缓存中获取数据
Iterator
N+1查询; N表示所有的记录总数
即会先发送一条语句查询所有记录的主键(1),
再根据每一个主键再去数据库查询(N)!
会放入缓存,也会从缓存中取数据!

5.代码实例
javaBean代码
public class User
 {
    private int userId;
    private String userName;
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    @Override
    public String toString() {
        return "User [userId=" + userId + ", userName=" + userName + "]";
    }
}
xml文件配置
<hibernate-mapping package="包名">
    <class name="User" table="t_user">
        <id name="userId" column="id">
            <generator class="native"></generator>
        </id>   
        <property name="userName"></property>
    </class>
</hibernate-mapping>
测试代码
public class App2_cache
 {
    private static SessionFactory sf;
    static {
        sf = new Configuration()
            .configure()
            .addClass(User.class)   // 测试时候使用
            .buildSessionFactory();
    }

    @Test
    public void testCache() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();
        User user = null;
        // 查询
        user = (User) session.get(User.class, 5);// 先检查缓存中是否有数据,如果有不查询数据库,直接从缓存中获取
        user = (User) session.get(User.class, 5);// 先检查缓存中是否有数据,如果有不查询数据库,直接从缓存中获取

        session.getTransaction().commit();
        session.close();
    }



    @Test
    public void flush() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();

        User user = null;
        user = (User) session.get(User.class, 5);
        user.setUserName("Jack");
        // 缓存数据与数据库同步
        session.flush();

        user.setUserName("Jack_new");

        session.getTransaction().commit();  // session.flush();
        session.close();
    }

    @Test
    public void clear() throws Exception {
        Session session = sf.openSession();
        session.beginTransaction();

        User user = null;
        // 查询
        user = (User) session.get(User.class, 5);
        // 清空缓存内容 
//      session.clear(); // 清空所有
        session.evict(user);// 清除指定

        user = (User) session.get(User.class, 5);


        session.getTransaction().commit();  // session.flush();
        session.close();
    }

    @Test
    public void sessionTest() throws Exception {
        Session session1 = sf.openSession();
        session1.beginTransaction();
        Session session2 = sf.openSession();
        session2.beginTransaction();

        // user放入session1的缓存区
        User user = (User) session1.get(User.class, 1);
        // user放入session2的缓存区
        session2.update(user);

        // 修改对象
        user.setUserName("New Name");  // 2条update
        session1.getTransaction().commit();  // session1.flush();
        session1.close();
        session2.getTransaction().commit();  // session2.flush();
        session2.close();
    }
}

三.懒加载

1. get、load方法的区别

get: 及时加载,只要调用get方法立刻向数据库查询
load:默认使用懒加载,当用到数据的时候才向数据库查询。

2.懒加载

概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
目的:提供程序执行效率!

3.lazy 值
true  使用懒加载
false 关闭懒加载
extra (在集合数据懒加载时候提升效率)

在真正使用数据的时候才向数据库发送查询的sql;
如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!

4.懒加载异常

Session关闭后,不能使用懒加载数据!如果session关闭后,使用懒加载数据报错:org.hibernate.LazyInitializationException: could not initialize proxy - no Session。
如何解决session关闭后不能使用懒加载数据的问题

方式1:先使用一下数据dept.getDeptName();
方式2:强迫代理对象初始化Hibernate.initialize(dept);
方式3:关闭懒加载设置lazy=false;
方式4:在使用数据之后,再关闭session!     
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The_Web3_社区

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值