前言
坚持就是胜利,今天来写一下Hibernate中实体类的编写原则,主键生成策略,增删改查的一些操作还有Hibernate缓存,还有一些乱七八糟的东西
实体类编写原则
1.实体类里面的属性必须为私有的
2.私有属性要使用public公开的set和get方法
3.实体属性建议使用基本属性类型对应的包装类
包装类: 两个特殊的:int-Integer char-Character
其他的都是首字母大写,如:double-Double
至于为什么使用包装类,包装类是为了避免产生歧义,double=0 和 Double=null 的意义是不一样的,比如你的考试成绩,int =0为表示零分,你没去考试不也是零分吗?但这里我们用 Integer=null来表示。这样就不会产生歧义
主键生成策略
主键生成策略常用的有 native和uuid。
<id name="cust_id" column="cust_id">
<generator class="native"/>
<generator class="uuid"/>
</id>
二者有什么区别呢?先来看图
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);
我们来看控制台输出的语句:
save方法实现了sql中insert语句
查询操作
调用session里面的get方法来实现
Customer customer = session.get(Customer.class,1);
ger这里需要两个参数,第一个:实体类.class 第二个:id的值
控制台输出
get方法实现了select查询语句
ps:这里我又遇到了一个坑,之前实体类定义id的时候使用了Long类型,这就导致在查询id的时候出现格式不匹配的错误,最后我把Long改成了int就解决了。
修改操作
先查询再修改
Customer customer = session.get(Customer.class,1);
customer.setCust_name("大溪");
session.update(customer);
我们来看控制台输出语句:
在这里,通过session.get方法来获取到了id的值,然后调用实体类中的set方法来对值进行修改,最后调用session的update的方法来实现对数据库表中内容的修改
执行过程:到Customer对象里面找到cust_id的值,根据id的值进行修改
删除操作
先查询再删除
Customer customer = session.get(Customer.class,1);
session.delete(customer);
这里执行方法和上面的修改操作方法类似
我们看控制台输出
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);
控制台输出
很明显,这里调用了添加操作,我们可以总结,实体类对象的状态是瞬时态时,做添加
持久态下调用:
Customer customer = session.get(Customer.class,2);
customer.setCust_name("大溪");
session.saveOrUpdate(customer);
这里调用了修改操作。so,实体类对象的状态是持久态时,做修改
脱管态下调用:
ustomer customer=new Customer();
customer.setCust_id(3);
customer.setCust_name("小小溪");
customer.setCust_source("网络");
customer.setCust_level("vip");
session.saveOrUpdate(customer);
我们可以看到,这里调用了修改方法,所以实体类对象是托管态时,做修改
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语句,现在我们来看控制台输出
可以看到,第一步执行完以后,发送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();
我们可以看到,这里实现了更新数据库的操作。
执行过程
首先执行session的get操作,返回customer的持久态对象,放到了一级缓存中,同时在一级缓存中有个快照区,快照区保存的内容与一级缓存中的内容一致,调用set方法来修改值,也就是customer持久态对象在一级缓存中的值,修改一级缓存但不会修改快照区的内容,最后提交事务的时候,commit来比较,一级缓存中的值和快照中的值是否相同,如果相同不进行修改,如果不同,就修改咯,然后把一级缓存中的值放到数据库中。
Hibernate事务
什么是事务?
简单理解为就是同一组操作,要么一起成功,要么一起失败,只要其中一项操作出现了错误,就不能成功,这就和代码运行一样,其中一行代码出现了错误,其他后面就编译不通过,无法运行。
事务的四个特性(ACID)
在昨天的笔记中,我有提到一个回滚方法,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。
总结
第二次的学习完成,最大的感受就是有了框架来操作数据库是真的容易!继续努力!!!