Hibernate学习笔记(2)

Hibernate学习笔记(2)

前言

坚持就是胜利,今天来写一下Hibernate中实体类的编写原则,主键生成策略,增删改查的一些操作还有Hibernate缓存,还有一些乱七八糟的东西

实体类编写原则

1.实体类里面的属性必须为私有的

2.私有属性要使用public公开的set和get方法

3.实体属性建议使用基本属性类型对应的包装类

包装类: 两个特殊的:int-Integer char-Character
其他的都是首字母大写,如:double-Double

至于为什么使用包装类,包装类是为了避免产生歧义,double=0 和 Double=null 的意义是不一样的,比如你的考试成绩,int =0为表示零分,你没去考试不也是零分吗?但这里我们用 Integer=null来表示。这样就不会产生歧义

主键生成策略

hibernate2-3

主键生成策略常用的有 native和uuid。

 <id name="cust_id" column="cust_id">
            <generator class="native"/>
            <generator class="uuid"/>    
        </id>

二者有什么区别呢?先来看图
hibernate2-1


hibernate2-2

native:为id自动生成策略,生成的是数字id,在实体类id的属性必须为int类型

uuid:生成的为16进制的uuid主键,添加到数据库中不需要设置id的值,在实体类中id的属性必须为字符串string类型

PS:我在测试uuid的时候遇到输入中文就报错的情况,原因是在数据库的表中设置的编码格式不正确,所以如果你其他没有错误,但是就是运行不了,那一定要检查一下你表中字段的编码格式,设置成utf8mb4基本就解决了

对实体类的操作

添加操作

调用session里面的sava方法来实现

        Customer customer=new Customer();
        customer.setCust_name("小溪");
        customer.setCust_source("网络");
        customer.setCust_level("vip");
        session.save(customer);

我们来看控制台输出的语句:
hibernate2-4
save方法实现了sql中insert语句

查询操作

调用session里面的get方法来实现

Customer customer = session.get(Customer.class,1);

ger这里需要两个参数,第一个:实体类.class 第二个:id的值

控制台输出
hibernate2-5
get方法实现了select查询语句

ps:这里我又遇到了一个坑,之前实体类定义id的时候使用了Long类型,这就导致在查询id的时候出现格式不匹配的错误,最后我把Long改成了int就解决了。

修改操作

先查询再修改

Customer customer = session.get(Customer.class,1);
        customer.setCust_name("大溪");
        session.update(customer);

我们来看控制台输出语句:

hibernate2-6

在这里,通过session.get方法来获取到了id的值,然后调用实体类中的set方法来对值进行修改,最后调用session的update的方法来实现对数据库表中内容的修改


执行过程:到Customer对象里面找到cust_id的值,根据id的值进行修改

删除操作

先查询再删除

        Customer customer = session.get(Customer.class,1);
        session.delete(customer);

这里执行方法和上面的修改操作方法类似
我们看控制台输出

hibernate2-7

Hibernate的持久化对象的三种状态

瞬时态

瞬时态由new命令创建,开辟内存空间的对象,没有持久化表示OID(可以理解为主键),未与Session对象关联,可以表现为以下形式

Customer customer=new Customer();
        customer.setCust_name("小溪");
        customer.setCust_source("网络");
        customer.setCust_level("vip");

持久态

持久态有了OID,加入到了Session的缓存中,并且关联的session没有关闭,在数据库中有对应的记录,持久态对象是在事务没有提交之前变成持久态的

Customer customer = session.get(Customer.class,1);

脱管态

同样存在OID,可以理解为离线了,当持久态与session的关联被关闭了就成为了脱管态,但是仍然与数据库的数据存在关联,只是失去了与当前Session的关联

Customer customer=new Customer();
         customer.setCust_id("2");

对saveorUpdate方法的理解

在session的众多方法中,存在一个saveorUpdate方法,从字面意思来看,这是两个方法,添加或者修改,那么什么时候是修改呢,什么时候是添加呢?这和上面三种状态有啥关系呢?

瞬时态下调用:

Customer customer=new Customer();
        customer.setCust_name("小溪");
        customer.setCust_source("网络");
        customer.setCust_level("vip");
        session.saveOrUpdate(customer);

控制台输出
hibernate2-8
很明显,这里调用了添加操作,我们可以总结,实体类对象的状态是瞬时态时,做添加

持久态下调用:

Customer customer = session.get(Customer.class,2);
        customer.setCust_name("大溪");
        session.saveOrUpdate(customer);

hibernate2-9
这里调用了修改操作。so,实体类对象的状态是持久态时,做修改

脱管态下调用:

ustomer customer=new Customer();
        customer.setCust_id(3);
        customer.setCust_name("小小溪");
        customer.setCust_source("网络");
        customer.setCust_level("vip");
        session.saveOrUpdate(customer);

hibernate2-10


我们可以看到,这里调用了修改方法,所以实体类对象是托管态时,做修改

Hibernate的缓存

什么是缓存呢?
缓存就是把数据放到内存中,不用流的方式,直接在内存中读取数据,把数据放到了内存中,提高了读取效率。


Hibernate缓存
Hibernate有一级二级缓存,二级缓存目前已经被redis来代替了,这里不再讨论,Hibernate的缓存减少了访问数据库的次数

一级缓存

一级缓存默认是打开的,它的使用范围实际上是session的使用范围,从session的创建到session关闭,一级缓存中存储的是持久态数据

一级缓存的验证

        Customer customer1 = session.get(Customer.class,3);
        System.out.println(customer1);
        Customer customer2 = session.get(Customer.class,3);
        System.out.println(customer2);

在这里我们创建两个对象,根据id来查询,看是否会返回sql语句,现在我们来看控制台输出
hibernate2-11
可以看到,第一步执行完以后,发送sql语句查询,第二步则没有执行sql语句,直接访问了一级缓存的内容

一级缓存的执行过程

首先查询一级缓存,发现一级缓存没有数据,才会去查询数据库的内容,随后返回一个持久化对象(customer1)

其次把customer1放到一级缓存中

customer2开始运行,和cus1一样,先查询一级缓存,发现一级缓存有数据,则查询一级缓存中的数据,不再执行sql语句了

一级缓存的作用

Customer customer1 = session.get(Customer.class,3);
        System.out.println(customer1);
        customer1.setCust_name("大小溪");
        //提交事务
        tx.commit();
        //释放资源
        session.close();

hibernate2-12
我们可以看到,这里实现了更新数据库的操作。

执行过程

首先执行session的get操作,返回customer的持久态对象,放到了一级缓存中,同时在一级缓存中有个快照区,快照区保存的内容与一级缓存中的内容一致,调用set方法来修改值,也就是customer持久态对象在一级缓存中的值,修改一级缓存但不会修改快照区的内容,最后提交事务的时候,commit来比较,一级缓存中的值和快照中的值是否相同,如果相同不进行修改,如果不同,就修改咯,然后把一级缓存中的值放到数据库中。

Hibernate事务

什么是事务?
简单理解为就是同一组操作,要么一起成功,要么一起失败,只要其中一项操作出现了错误,就不能成功,这就和代码运行一样,其中一行代码出现了错误,其他后面就编译不通过,无法运行。

事务的四个特性(ACID)
hibernate2-13
在昨天的笔记中,我有提到一个回滚方法,rollback,这个操作就是当事务出现异常时,对事务进行回滚撤销。

Hibernate事务代码的规范写法

try{
    开启事务
    提交事务
}catch{
    回滚事务
}finally{
    关闭
}

代码事例

    public static void demo01() {
        Configuration cfg = new Configuration().configure();
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try {
            sessionFactory = cfg.buildSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            Customer customer = new Customer();
            customer.setCust_name("小溪");
            customer.setCust_source("网络");
            session.save(customer);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        } finally {
            session.close();
            sessionFactory.close();
        }

Hibernate其他API

Query

使用Query不需要编学sql语句,需要写hql语句,sql的语句是操作数据库的表和字段,hql语句是操作实体类和属性,查询所有的hql语句为 from+实体类名称,代码演示如下:

//创建Query对象,方法里面写hql语句
        Query query=session.createQuery("from Customer ");
        //调用query里的方法来得到结果,然后用for循环输出
        List<Customer> list=query.list();
        for (Customer customer:list)
        {
            System.out.println(customer);
        }

Criteria

使用这个对象查询操作,不需要写语句,直接调用方法实现

Criteria criteria=session.createCriteria(Customer.class);
        List<Customer> list=criteria.list();
        for (Customer customer:list)
        {
            System.out.println(customer);
        }

SQLQuery

调用底层的sql实现,需要写sql语句,不建议使用,太麻烦了orz。
hibernate2-14

总结

第二次的学习完成,最大的感受就是有了框架来操作数据库是真的容易!继续努力!!!