Hibernate的基础入门--笔记(二)
1.持久化类的编写规范
遵从JavaBean的编写规范.
什么是JavaBean?
bean:在软件开发领域,Bean表示可重用组件.
JavaBean就是用Java语言开发的可重用组件.
JavaBean的编写规范是什么?
类都是public的
都有默认无参构造函数
成员变量都是私有的
都有公有的get/set方法
一般都实现Serializable接口
基本类型和包装类的选择问题?
包装类可以有null值.所以实际开发中都是用包装类.
2.主键生成策略(native之外的取值)
代理主键:不参与程序业务,只是用于区分表中数据的.
自然主键:参与程序业务.同时也能区分表中数据.
1 <?xml version="1.0"?> 2 3 <!DOCTYPE hibernate-mapping PUBLIC 4 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 5 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 6 <hibernate-mapping package="com.mypro.id"> 7 <class name="User" table="user"> 8 <id name="id" column="Id" type="int"> 9 <generator class="navite"></generator> 10 </id> 11 <property name="name" column="name" type="string"></property> 12 </class> 13 </hibernate-mapping>
通过配置可以看到,我们有个实体类User,该类有一个id和name的属性与数据库中user表的id和name字段分别对应。其中
<generator class="navite"></generator>
定义了主键的生成方式,下面我们将会介绍到我们常用的主键生成方式
1、assigned 适用于自然主键
主键由外部程序负责生成,在 save() 之前必须指定一个,Hibernate不负责维护主键生成。也就是可以每次指定主键。该方式不推荐
2、increment 适用于代理主键
这种方式在每次插入前,需要通过“select max(主键) from 表名 ”这种方式先查询最大ID,然后通过ID+1来作为新的主键值。这种方式也不推荐,因为这样会出现线程安全问题。
3、identity 适用于代理主键
identity由底层数据库生成标识符。identity是由数据库自己生成的,但这个主键必须设置为自增长,使用identity的前提条件是底层数据库支持自动增长字段类型,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle这类没有自增字段的则不支持。
4、sequence 适用于代理主键
采用数据库提供的sequence机制生成主键,需要数据库支持sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL这种不支持sequence的数据库则不行
5、hilo
hilo(高低位方式high low)是hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。可以跨数据库。
6、native 适用于代理主键
native由hibernate根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式,灵活性很强。如果能支持identity则使用identity,如果支持sequence则使用sequence。
7、uuid 适用于代理主键
UUID:Universally Unique Identifier,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字,标准的UUID格式为:
xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)
3.hibernate中的对象标识符
OID: Object Identifier 对象标识符
它就是hibernate用来区分两个对象是否是同一个对象的标识.

4.hibernate中的一级缓存
什么是缓存?
内存中的临时数据.
hibernate中的一级缓存?
它指的是Session的对象的缓存.就是由一些集合组成的.
当我们在执行查询时,先去缓存中看看有没有数据,如果有的话,就不再去数据库中查询了.如果没有,则直接去数据库中查询.
从而提高效率.
当Session对象close了之后,一级缓存就消失了.
1 /** 2 * 证明一级缓存确实存在. 3 * 需求: 4 * 查询id为2的客户 5 */ 6 @Test 7 public void test1(){ 8 Session s = HibernateUtil.openSession(); 9 Transaction tx = s.beginTransaction(); 10 //1.查询id为2的客户 11 Customer c1 = s.get(Customer.class, 2L);//先从缓存中找,没找到。去数据库中查询。存入一级缓存中 12 System.out.println(c1); 13 Customer c2 = s.get(Customer.class, 2L);//先从缓存中找,找到了,直接返回了。 14 System.out.println(c2); 15 16 System.out.println(c1 == c2); 17 tx.commit(); 18 s.close();//一级缓存 19 } 20
快照机制:

session的快照
* 使用id进行查询数据库,将查询得到的结果放置到session一级缓存中,同时复制一份数据,放置到session的快照中
* 当使用tx.commit()的时候,同时清理session的一级缓存(flush)
* 当清理session一级缓存的时候,会使用OID判断一级缓存中对象和快照中的对象进行比对
* 如果2个对象(一级缓存的对象和快照的对象)中的属性发生变化,则执行update语句,此时更新数据库,更新成一级缓存中的数据
* 如果2个对象中的属性不发生变化,此时不执行update语句
目的:确保和数据库中的数据一致
5.hibernate中的一下方法问题
hibernate中对象的状态
明确:学习对象的状态是为了更好的掌握hibernate中操作的方法.
状态的分类:
临时状态(瞬时状态):Transient
没有OID,和Session没有关系.
持久化状态:Persistent
有OID,和Session有关系.
脱管状态(游离状态):Detached
有OID,和Session没有关系.

常用的方法:
save和persist方法:
1 /** 2 * save方法: 3 * 保存一个实体。 4 * 状态的转变: 5 * 把临时态对象转成了持久态。 6 */ 7 @Test 8 public void test1(){ 9 Customer c = new Customer(); 10 c.setCustName("修正save11"); 11 c.setCustIndustry("医药"); 12 c.setCustSource("网络"); 13 c.setCustLevel("VIP客户"); 14 c.setCustAddress("昌平区"); 15 c.setCustPhone("010-98234832"); 16 17 Session s = HibernateUtil.openSession(); 18 //Transaction tx = s.beginTransaction(); 19 s.save(c); 20 //tx.commit(); 21 s.close();//一级缓存 22 } 23 24 /** 25 * persist方法: 26 * 保存一个实体 27 * 状态的转变: 28 * 把临时态对象转成了持久态 29 */ 30 @Test 31 public void test2(){ 32 Customer c = new Customer(); 33 c.setCustName("修正persist"); 34 c.setCustIndustry("医药制造"); 35 c.setCustSource("网络"); 36 c.setCustLevel("VIP客户"); 37 c.setCustAddress("昌平区"); 38 c.setCustPhone("010-98234832"); 39 40 Session s = HibernateUtil.openSession(); 41 //Transaction tx = s.beginTransaction(); 42 s.persist(c); 43 //tx.commit(); 44 s.close();//一级缓存
45 }
共同点:
都是把临时态对象转换成持久态.
区别:
提供者不一样:
save方法是hibernate提供的.
persist方法是JPA规范提供的. (JPA: Java Persistence Api --Java持久化规范)
在没有事务的情况下:
save会去数据库中保存,hibernate提供了一个内置的事务来执行.
persist什么都不会做.
delete方法:
1 /** 2 * delete方法 3 * 4 * 5 */ 6 @Test 7 public void test3(){ 8 9 Session s = HibernateUtil.openSession(); 10 Transaction tx = s.beginTransaction(); 11 //1.查询id为11的客户 12 Customer c = s.get(Customer.class, 11L); 13 //2.删除客户 14 s.delete(c); 15 tx.commit(); 16 s.close(); 17 }
问题:当我们删除一个实体时,该实体已经被别的程序给删除了,此时会报错。
<控制台报错>Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
update方法:
1 /** 2 * update方法 3 * 4 * */ 5 @Test 6 public void test4(){ 7 8 Session s = HibernateUtil.openSession(); 9 Transaction tx = s.beginTransaction(); 10 //1.查询id为10的客户 11 Customer c10 = s.get(Customer.class, 10L);//持久态 12 tx.commit(); 13 s.close();//一级缓存没了 14 15 //2.修改c10的客户名称 16 c10.setCustName("修正update");//脱管态 17 18 Session s1 = HibernateUtil.openSession(); 19 Transaction tx1 = s1.beginTransaction(); 20 //3.查询id为10的客户 21 Customer c = s1.get(Customer.class, 10L);//持久态 22 //4.更新c10客户 23 s1.update(c10);//持久态 24 tx1.commit(); 25 s1.close();//一级缓存没了 26 }
问题:当我们更新一个脱管态实体时,一级缓存中已经包含了一个相同OID的持久态对象,会报错。
<控制台报错> A different object with the same identifier value was already associated with the session : [com.itheima.domain.Customer#10]

merge方法:
作用: 合并两个实体.永远是用一级缓存外的修改一级缓存内的对象.
1 /** 2 * merge方法 3 */ 4 @Test 5 public void test5(){ 6 7 Session s = HibernateUtil.openSession(); 8 Transaction tx = s.beginTransaction(); 9 //1.查询id为10的客户 10 Customer c10 = s.get(Customer.class, 10L);//持久态 11 tx.commit(); 12 s.close();//一级缓存没了 13 14 //2.修改c10的客户名称 15 c10.setCustName("修正update");//脱管态 16 17 Session s1 = HibernateUtil.openSession(); 18 Transaction tx1 = s1.beginTransaction(); 19 //3.查询id为10的客户 20 Customer c = s1.get(Customer.class, 10L);//持久态 21 //4.更新c10客户 22 s1.merge(c10);//持久态 23 tx1.commit(); 24 s1.close();//一级缓存没了 25 }
saveOrUpdate方法:
作用:保存或更新一个实体.
到底执行保存还是更新:
取决于对象的状态:
如果是临时态对象就是保存 / 如果是脱管态对象就是更新
6.满足Session的使用原则
在hibernate中的使用数据源(连接池)
使用步骤:
1.导入连接池的jar包

2.在hibernate主配置文件中配置
配置连接池的提供商
1 <!-- 配置连接池的提供商 --> 2 <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
1 /** 2 * 证明是否使用了连接池 3 */ 4 @Test 5 public void test1(){ 6 Session s = HibernateUtil.openSession(); 7 //hibernate中使用原始JDBC对象 8 s.doWork(new Work() { 9 @Override 10 public void execute(Connection conn) throws SQLException { 11 System.out.println(conn.getClass().getName()); 12 } 13 }); 14 }
配置hibernate中一个线程只能有一个session的方式:
配置步骤:
1.在hibernate主配置文件中配置
1 <!-- 把Session绑定到当前线程上 --> 2 <property name="hibernate.current_session_context_class">thread</property>
2.获取Session时使用的方法
1 /** 2 * Session的使用原则: 3 * 一个线程只应该有一个Session对象 4 */ 5 @Test 6 public void test2(){ 7 Session s1 = HibernateUtil.getCurrentSession(); 8 Session s2 = HibernateUtil.getCurrentSession(); 9 System.out.println(s1 == s2); 10 }
细节:
当我们把Session绑定到当前线程之后,关闭Session就是Hibernate来做的,我们就不需要关了.
7.查询对象的使用(入门,讲解在(四))
Query <掌握>
1 /** 2 * hibernate中的查询对象 3 * Query: 4 * 作用:使用的是HQL语句查询 5 * 如何获取: 6 * session.createQuery(String hql); 7 * 常用方法: 8 * list():获取结果集 9 * setXXXX方法():给参数占位符赋值用的。XXXX表示的是数据类型。 比如:setString(int index,String param) setObject(int index,Object obj) 10 * 在给参数占位符赋值时,索引位置是从0开始的12 * 13 */ 14 public class HibernateDemo4 { 15 16 /** 17 * 查询所有 18 */ 19 @Test 20 public void test1(){ 21 Session s = HibernateUtil.getCurrentSession(); 22 Transaction tx = s.beginTransaction(); 23 //1.获取Query对象 24 Query query = s.createQuery("from Customer"); 25 //2.执行list方法获取结果集 26 List list = query.list(); 27 tx.commit(); 28 29 30 for(Object o : list){ 31 System.out.println(o); 32 } 33 } 34 35 /** 36 * 查询客户: 37 * 带有条件:客户级别是VIP客户 38 */ 39 @Test 40 public void test2(){ 41 Session s = HibernateUtil.getCurrentSession(); 42 Transaction tx = s.beginTransaction(); 43 //1.获取Query对象 44 Query query = s.createQuery("from Customer where custLevel = ? and custName like ? "); 45 //2.给参数占位符赋值 46 query.setString(0, "VIP客户"); 47 query.setString(1, "%大%"); 48 //3.执行list方法获取结果集 49 List list = query.list(); 50 tx.commit(); 51 52 53 for(Object o : list){ 54 System.out.println(o); 55 } 56 } 57 58 /** 59 * 具名查询: 60 * 给参数占位符提供一个具体的名称 61 * 参数名称的写法: 62 * :名称 63 * 给占位符赋值时: 64 * 注意:不需要写冒号,直接写名称 65 */ 66 @Test 67 public void test3(){ 68 Session s = HibernateUtil.getCurrentSession(); 69 Transaction tx = s.beginTransaction(); 70 //1.获取Query对象 71 Query query = s.createQuery("from Customer where custName like :custName and custLevel = :custLevel "); 72 //2.给参数占位符赋值 73 query.setString("custLevel", "VIP客户"); 74 query.setString("custName", "%大%"); 75 //3.执行list方法获取结果集 76 List list = query.list(); 77 tx.commit(); 78 79 80 for(Object o : list){ 81 System.out.println(o); 82 } 83 } 84 }
Criteria <逐步掌握>
1 /** 2 * hibernate中的查询对象 3 * Criteria对象: 4 * 作用:使用QBC查询。 query by criteria 5 * 它是一种更加面向对象的查询方式。 6 * 明确: 7 * 能用HQL查询的,QBC都能查。反之亦然。 8 * hibernate官方推荐的是hql查询 9 * 如何获取对象 10 * 使用的是session对象的createCriteria(Class clazz); 11 * 参数的含义:要查询的实体类字节码对象13 * 14 */ 15 public class HibernateDemo5 { 16 17 /** 18 * 查询所有 19 */ 20 @Test 21 public void test1(){ 22 Session s = HibernateUtil.getCurrentSession(); 23 Transaction tx = s.beginTransaction(); 24 //1.获取Criteria对象 25 Criteria criteria = s.createCriteria(Customer.class);//就相当于HQL语句from Customer 26 //2.调用list获取结果集 27 List list = criteria.list(); 28 tx.commit(); 29 30 for(Object obj : list){ 31 System.out.println(obj); 32 } 33 } 34 35 36 /** 37 * 查询客户: 38 * 带有条件:客户级别是VIP客户 39 * 客户名称包含大字 40 */ 41 @Test 42 public void test2(){ 43 Session s = HibernateUtil.getCurrentSession(); 44 Transaction tx = s.beginTransaction(); 45 //1.获取Criteria对象 46 Criteria criteria = s.createCriteria(Customer.class);//就相当于HQL语句from Customer 47 //2.设置查询条件 48 criteria.add(Restrictions.eq("custLevel","VIP客户"));//谁=什么值 谁指的就是属性 49 criteria.add(Restrictions.like("custName", "%大%")); 50 //3.调用list获取结果集 51 List list = criteria.list(); 52 tx.commit(); 53 54 for(Object obj : list){ 55 System.out.println(obj); 56 } 57 } 58 59 60 }
SQLQuery <了解>
1 /** 2 * hibernate中的查询对象 3 * SQLQuery 4 * 作用:使用原始SQL语句查询 5 * 如何获取 6 * session.createSQLQuery(String sql);
8 * 9 */ 10 public class HibernateDemo6 { 11 12 /** 13 * 查询所有 14 */ 15 @Test 16 public void test1(){ 17 Session s = HibernateUtil.getCurrentSession(); 18 Transaction tx = s.beginTransaction(); 19 //1.获取sqlquery对象 20 SQLQuery sqlquery = s.createSQLQuery(" select * from cst_customer "); 21 //2.给sqlquery添加要转换的实体类 22 sqlquery.addEntity(Customer.class); 23 //3.获取结果集 24 List list = sqlquery.list(); 25 tx.commit(); 26 for(Object o : list ){ 27 System.out.println(o); 28 } 29 } 30 }

浙公网安备 33010602011771号