实体类编写规则
1 实体类里面属性私有的
2 私有属性使用公开的set和get方法操作
3 要求实体类有属性作为唯一值(一般使用id值)
4 实体类属性建议不使用基本数据类型,使用基本数据类型对应的包装类
(1)八个基本数据类型对应的包装类
- int – Integer
- char—Character、
- 其他的都是首字母大写 比如 double – Double
(2)比如 表示学生的分数,假如 int score;
- 比如学生得了0分 ,int score = 0;
- 如果表示学生没有参加考试,int score = 0;不能准确表示学生是否参加考试
解决:使用包装类可以了, Integer score = 0,表示学生得了0分,
表示学生没有参加考试,Integer score = null;
对实体类crud操作
添加操作
1 调用session里面的save方法实现
根据id查询
1 调用session里面的get方法实现
修改操作
1 首先查询,然后修改值
(1)根据id查询,返回对象
删除操作
1 调用session里面delete方法实现
实体类对象状态(概念)
1 实体类状态有三种
(1)瞬时态:对象里面没有id值,对象与session没有关联
(2)持久态:对象里面有id值,对象与session关联
(3)托管态:对象有id值,对象与session没有关联
2 演示操作实体类对象的方法
(1)saveOrUpdate方法:实现添加、实现修改
测试代码:
一.创建瞬时态对象[没有id,与session没有关联],使用saveOrupdate保存,做插入操作
Customer c=new Customer(); c.setCname("传智"); session.saveOrUpdate(c);
底层sql语句
Hibernate: insert into t_customer (cname, tel) values (?, ?)
数据库插入了一条数据(使用的是主键自动增长策略):
二.创建托管态对象[有id,与session没有关联],使用saveOrupdate保存,做更新操作
首先需要明白它做的是更新的操作,那么问题就产生了,如果数据库中存在这个id值,那么会更新,
如果设置的id值,数据库中没有呢?那么就无法完成更细,会报错
(1)数据库中没有该id值(数据库中没有id为9的记录,那么进行更新的时候肯定会报错)
Customer c=new Customer(); c.setCid(9); c.setCname("传智9"); session.saveOrUpdate(c);
(2)数据库中有该id值(把id为1的记录的cname字段由“传智播客1”改为“百度”)
Customer c=new Customer(); c.setCid(1); c.setCname("百度"); session.saveOrUpdate(c);
底层sql
Hibernate:
update
t_customer
set
cname=?,
tel=?
where
cid=?
Hibernate:
update
t_linkman
set
clid=null
where
clid=?
数据库是更新了没错
但是它又多了一条更新语句,就是把关联表中的外键字段置为null,首先这里只需要明白产生的原因是hibernate双向维护机制,解决办法就是在customer配置文件的set标签中使用
inverse="true" 表示让它放弃外键的维护能力,这样就不会出现下面的更新语句了,详解请参考框架截图总结(一)
当然上面演示的情况因为在关联表中本来就没有记录,所以没有影响,但是如果是存在记录,那么根据打印的sql语句就能知道一定会出现下面的情况
修改之前数据库中的记录(存在外键的约束,即百度这个客户它对应的联系人是李彦宏):
现在把百度的名称,改变为百度1
Customer c=new Customer(); c.setCid(1); c.setCname("百度1"); session.saveOrUpdate(c);
sql语句:
Hibernate: update t_customer set cname=?, tel=? where cid=? Hibernate: update t_linkman set clid=null where clid=?
所以看表中的变化
更新没有问题,但是联系人表中的外键字段是null
三.创建持久态对象[有id,与session有关联],使用saveOrupdate保存,做更新操作
修改之前
现在把百度1改回百度
Customer c=session.get(Customer.class,1);//持久态对象
c.setCid(1);//这条语句写不写对结果没有任何的影响,因为id的值没有变化,但是如果把id值改变就会保错
c.setCname("百度");
session.saveOrUpdate(c);
sql语句:
Hibernate: select customer0_.cid as cid1_0_0_, customer0_.cname as cname2_0_0_, customer0_.tel as tel3_0_0_ from t_customer customer0_ where customer0_.cid=? Hibernate: update t_customer set cname=?, tel=? where cid=?
只做一次更新,观察数据库中的变化
可以发现在修改持久态对象的时候,并没有把关联表的外键字段置为null的语句打印,说明托管态和持久态之间使用saveOrupdate是有区别的虽然同样是更新操作,托管态在
更新数据之后会把关联表的外键字段再做一次更新(做了2次更新),置为null,而持久态的对象在更新之后只是更新了自己表的数据(1次更新)
全部测试代码:
1 package org.testdemo; 2 3 import org.hibernate.Session; 4 import org.hibernate.SessionFactory; 5 import org.hibernate.Transaction; 6 import org.hibernate.cfg.Configuration; 7 import org.junit.Test; 8 import org.model.User; 9 import org.util.SessionFactoryUtil; 10 11 public class TestDemo { 12 // 1通过工具类得到sessionfactory 对象 13 // SessionFactory sessionfactory = SessionFactoryUtil.getSessionFactory(); 14 // 2通过sessionfactory得到session对象 15 // Session session = sessionfactory.openSession(); 16 // 3通过session创建事务 17 // Transaction tran = session.beginTransaction(); 18 19 // 4进行数据库的操作 20 21 // 5提交事务 22 // tran.commit(); 23 // 6关闭链接 24 // session.close(); 25 // sessionfactory.close(); 26 27 @Test 28 public void add() { 29 //insert into t_user(name,password) values(?,?) 30 SessionFactory sessionfactory = SessionFactoryUtil.getSessionFactory(); 31 Session session = sessionfactory.openSession(); 32 Transaction tran = session.beginTransaction(); 33 //添加一条数据 34 User user = new User(); 35 user.setName("jay"); 36 user.setPassword("root"); 37 session.save(user); 38 tran.commit(); 39 session.close(); 40 sessionfactory.close(); 41 42 } 43 44 @Test 45 public void select() { 46 //select * from t_user where id=? 47 SessionFactory sessionfactory = SessionFactoryUtil.getSessionFactory(); 48 Session session = sessionfactory.openSession(); 49 Transaction tran = session.beginTransaction(); 50 //查询一条记录 根据id值 51 User user = session.get(User.class, 1); 52 System.out.println(user); 53 tran.commit(); 54 session.close(); 55 sessionfactory.close(); 56 } 57 58 @Test 59 public void update() { 60 //update t_user set name=?,password=? where id=? 61 SessionFactory sessionfactory = SessionFactoryUtil.getSessionFactory(); 62 Session session = sessionfactory.openSession(); 63 Transaction tran = session.beginTransaction(); 64 //执行修改操作 先找到对象 在进行修改 最后使用update方法执行最后的变更 65 User user=session.get(User.class,1); 66 user.setName("Joke"); 67 session.update(user); 68 69 tran.commit(); 70 session.close(); 71 sessionfactory.close(); 72 } 73 74 @Test 75 public void delete() { 76 //delete from t_user where id=? 77 SessionFactory sessionfactory = SessionFactoryUtil.getSessionFactory(); 78 Session session = sessionfactory.openSession(); 79 Transaction tran = session.beginTransaction(); 80 //执行删除操作 先找到对象 在进行删除 81 User user=session.get(User.class,1); 82 session.delete(user); 83 // User user=new User(); 84 // user.setUid(2); 85 // session.delete(user); 86 87 tran.commit(); 88 session.close(); 89 sessionfactory.close(); 90 } 91 92 @Test 93 public void saveorupdate() { 94 //delete from t_user where id=? 95 SessionFactory sessionfactory = SessionFactoryUtil.getSessionFactory(); 96 Session session = sessionfactory.openSession(); 97 Transaction tran = session.beginTransaction(); 98 99 //创建游离态 100 // User user=new User(); 101 // user.setName("aa"); 102 // user.setPassword("bb"); 103 // session.saveOrUpdate(user);//执行插入操作 104 105 //创建托管态 106 // User user=new User(); 107 // user.setUid(3); 108 // user.setName("cc2"); 109 // user.setPassword("dd3"); 110 // session.saveOrUpdate(user);//执行更新操作 111 112 //创建持久态 113 User user=session.get(User.class,3); 114 user.setName("feafw"); 115 session.saveOrUpdate(user);//执行更新操作 116 117 118 tran.commit(); 119 session.close(); 120 sessionfactory.close(); 121 } 122 123 124 }
Hibernate的一级缓存
什么是缓存
1 数据存到数据库里面,数据库本身是文件系统,使用流方式操作文件效率不是很高。
(1)把数据存到内存里面,不需要使用流方式,可以直接读取内存中数据
(2)把数据放到内存中,提供读取效率
Hibernate缓存
1 hibernate框架中提供很多优化方式,hibernate的缓存就是一个优化方式
2 hibernate缓存特点:
第一类 hibernate的一级缓存
(1)hibernate的一级缓存默认打开的
(2)hibernate的一级缓存使用范围,是session范围,从session创建到session关闭范围
(3)hibernate的一级缓存中,存储数据必须 持久态数据
第二类 hibernate的二级缓存
(1)目前已经不使用了,替代技术 redis
(2)二级缓存默认不是打开的,需要配置
(3)二级缓存使用范围,是sessionFactory范围
验证一级缓存存在
1 验证方式
(1)首先根据uid=1查询,返回对象
(2)其次再根据uid=1查询,返回对象
第一步执行get方法之后,发送sql语句查询数据库
第二个执行get方法之后,没有发送sql语句,查询一级缓存内容
Hibernate一级缓存执行过程
注意一级缓存中保存的数据并不是一个对象,而是每个对象的属性的值
Hibernate一级缓存特性
1 持久态自动更新数据库
1 @Test 2 public void testauto(){ 3 SessionFactory sessionfactory=SessionFactoryUtil.getSessionFactory(); 4 Session session=sessionfactory.openSession(); 5 Transaction tran=session.beginTransaction(); 6 //得到持久态对象 7 User user=session.get(User.class,3); 8 //修改持久态对象 9 user.setName("jay"); 10 //这里不需要保存 因为是持久态 所以会自动进行更新数据库 11 tran.commit(); 12 session.close(); 13 sessionfactory.close(); 14 }
代码执行到第7行的时候,控制台打印出查询语句,之后事务进行提交的时候,自动更新了数据库
需要注意的是:
如果修改前和修改时的数据一样,那么缓存机制并不会做更新操作 比如上面的代码在重新执行一次
执行后控制台打印的结果
因为数据没有发生变化,所以并没有执行更新
原因:观察下面这张图:
当执行get方法的时候,如果一级缓存中没有所需要的数据,就进行数据库的查询操作,把得到的数据保存在以及缓存的同时,还复制一份保存在快照区中,进行set方法更新的时候 只是修改一级缓存中的数据,并不修改快照区中的内容,当进行事务提交的时候,对比快照区和一级缓存中的数据是否一样,不一样则更新数据库以及把修改之后的内容存在以及缓存和快照区中, 一样则不做任何的更新操作
Hibernate事务代码规范写法
1 @Test 2 public void testTx() { 3 SessionFactory sessionFactory = null; 4 Session session = null; 5 Transaction tx = null; 6 try { 7 sessionFactory = HibernateUtils.getSessionFactory(); 8 session = sessionFactory.openSession(); 9 //开启事务 10 tx = session.beginTransaction(); 11 12 //添加 13 User user = new User(); 14 user.setUsername("小马"); 15 user.setPassword("250"); 16 user.setAddress("美国"); 17 18 session.save(user); 19 20 int i = 10/0; 21 //提交事务 22 tx.commit(); 23 }catch(Exception e) { 24 e.printStackTrace(); 25 //回滚事务 26 tx.rollback(); 27 }finally { 28 //关闭操作 29 session.close(); 30 sessionFactory.close(); 31 } 32 }
Hibernate绑定session
hibernate中的session对象可以看做是一个与数据库的链接,它的特点是单线程对象(只能自己用,别人不能用,每个用户都有一个自己的session对象)
为了保证它绝对是一个单线程对象,可以把session与本地线程进行绑定
1 session类似于jdbc的connection,之前web阶段学过 ThreadLocal,绑定session底层的原理就是 ThreadLocal
2框架 帮实现与本地线程绑定session
3 获取与本地线程session
(1)在hibernate核心配置文件中配置
(2)使用sessionfactory.getCurrentSession()方法得到与本地线程绑定的session
(一般在工具类中提供一个方法,返回这个session)
代码实践:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <!-- 配置数据库 信息 必须的 --> 8 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 9 <property name="hibernate.connection.username">root</property> 10 <property name="hibernate.connection.password">jay571018</property> 11 <property name="hibernate.connection.url">jdbc:mysql:///Hibernate2_demo1</property> 12 13 14 15 <!-- 2. 配置hibernate信息 可选的 --> 16 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 17 <property name="hibernate.show_sql">true</property> 18 <property name="hibernate.format_sql">true</property> 19 <property name="hibernate.hbm2ddl.auto">update</property> 20 21 <!-- 配置本地线程 绑定session --> 22 <property name="hibernate.current_session_context_class">thread</property> 23 24 <!-- 3 配置对象关系映射文件的位置 --> 25 <mapping resource="org/model/User.hbm.xml"/> 26 </session-factory> 27 </hibernate-configuration>
1 package org.util; 2 3 import org.hibernate.Session; 4 import org.hibernate.SessionFactory; 5 import org.hibernate.cfg.Configuration; 6 7 public class SessionFactoryUtil { 8 private static Configuration configuratrion=null; 9 private static SessionFactory sessionfactory=null; 10 static{//静态代码块 只会在类加载的时候执行一次 创建一次sessionfactory对象 提高性能 11 configuratrion=new Configuration(); 12 configuratrion.configure();//加载配置文件 13 sessionfactory=configuratrion.buildSessionFactory(); 14 } 15 //创建一个方法返回sessionfactory对象 16 public static SessionFactory getSessionFactory(){ 17 return sessionfactory; 18 }
//提供返回 与本地线程绑定的session的方法 19 public static Session get(){ 20 return sessionfactory.getCurrentSession(); 21 } 22 23 public static void close(){ 24 sessionfactory.close(); 25 } 26 public static void main(String args[]){ 27 28 } 29 }
这样在使用session的时候可以通过这个方法直接得到session对象,并且是与本地线程绑定的,保证是单线程对象
但是注意 :不需要我们手动关闭session了
1 public void t(){ 2 Session session=SessionFactoryUtil.get(); 3 Transaction tran=session.beginTransaction(); 4 User u=new User(); 5 u.setName("a"); 6 u.setPassword("a"); 7 session.save(u); 8 tran.commit(); 9 session.close();//这里不需要关闭session 10 }
执行之后 控制台打印:
插入了一条记录,但是出现错误
原因:操作结束的时候,这个线程就结束了,那么session是与本地线程绑定的,自然就结束了,所以不需要在关闭了
如果在dao操作中,使用hibernate提供的模板类HibernateTemplate进行数据操作(不用得到session对象),那么就不需要
在hibernate.cfg.xml中配置<property name="hibernate.current_session_context_class">thread</property>
因为该模板底层实现就是对 与本地线程绑定的session 进行了封装 使用该模板操作数据 就是使用与本地线程绑定的session操作数据
HibernateAPI
Query对象
1 使用query对象,不需要写sql语句,但是写hql语句
(1)hql:hibernate query language,hibernate提供查询语言,这个hql语句和普通sql语句很相似
(2)hql和sql语句区别:
- 使用sql操作表和表字段
- 使用hql操作的是实体类和属性
2 查询所有hql语句:
(1)from 实体类名称
3 Query对象使用
(1)创建Query对象
(2)调用query对象里面的方法得到结果
Criteria对象
1 使用这个对象查询操作,但是使用这个对象时候,不需要写语句
2 实现过程
(1)创建criteria对象
(2)调用对象里面的方法得到结果
SQLQuery对象
里边是写的是sql语句
返回的list集合 每部分是数组的形式
使用方法,使list中每部分是对象形式
sqlQuery.addEntity(实体类);
这样返回的list集合中,每部分就是一个对象了