二、第二天
1. hibernate-01 复习
2. hibernate 中的实体类的规则-详解
(1)实体类创建的注意事项:
1. 持久化类需要提供无参数构造方法; 因为Hibernate 的底层需要使用反射生成类的实例;
2. 成员变量私有,提供公有get/set 方法(属性)访问;需提供属性;
3. 持久化类中的属性,应尽量使用包装类型;
4. 持久化类需要提供oid. 与数据库中的主键列对应;
5. 不要用 final 修饰 class;
hibernate 使用 cglib 代理生成代理对象。 代理对象是继承被代理对象。
如果被 final 修饰,将无法继承,则将无法生成代理。
(2) 主键类型:(2种类型) 主键不能为空,且不能重复;
自然主键(少见):把具有业务含义的字段列作为主键;
代理主键(常见):把不具备业务含义的字段列作为主键;
3. hibernate 中的实体规则——主键生成策略详解
主键生成策略:就是 每条记录录入时,主键的生成规则(7个)。 eg: <generator class="native"></generator>
(1) 代理主键策略:
1. identity: 主键自增; 由数据库来维护主键值,录入时不需要指定主键。
2. increment(了解): 主键自增,由hibernate 来维护,每次插入前会先查询表中id最大值,然后+1 作为新主键;正式开发时不要使用,存在线程并发安全问题;
3. sequence:Oracle中的主键生成策略;
4. hilo(了解):采用高低位算法,主键自增,由hibernate来维护,开发时不使用;
5. native: hilo + sequence + identity ,自动三选一策略;
6. uuid:产生随机字符串作为主键,主键类型必须为string 类型;
(2)自然主键策略:
7. assigned: 自然主键生成策略,hibernate不会管理主键值,由开发人员手动指定、自己录入;
4. hibernate 中的对象状态
对象分为三种状态: 瞬时状态, 持久化状态, 游离(托管)状态
1. 瞬时状态: 没有id,不在session缓存中;
2. 持久化状态: 有id ,在session 缓存中; 持久化状态对象的任何变化都会自动同步到数据库中。
3. 游离(托管)状态: 有id ,在session缓存中;
三种状态的转换图
对象状态的转换: 增(save)、删(delete)、改(update)、查(get)
结论: 将我们希望同步到数据库的数据对应的对象 转换为 持久化状态,于是,对象的任何变化都会自动同步到数据库中。
可以使用 saveOrUpdate( )方法来完成
5. hibernate 进阶: 一级缓存( session 缓存) 和 快照
缓存 cache:提高效率,hibernate中的一级缓存 也是为了提高操作数据库的效率。
快照: 将数据库返回的内容,组装成两个对象: 一个放入缓存中,一个放入快照中;
提高效率的手段: 1. 提高查询效率——缓存; 2. 减少不必要的修改语句发送——快照;
6. hibernate 中的事务: 隔离级别设置 & 项目中的事务管理
事务的4大特性: ACID(原子性,一致性,隔离性,持久性)
事务并发问题: 1. 脏读(两次数据不一致); 2. 不可重复读; 3. 幻读(虚读)
事务的隔离级别: hibernate.connection.isolation 1 | 2 | 4 | 8
0001 —— 1 —— 读未提交(可能出现的问题: 1(脏读)、2(不可重复读)、3(幻读));
0010 —— 2 —— 读已提交(可能出现的问题:2、3);
0100 —— 4 —— 可重复读(可能出现的问题:3);
1000 —— 8 —— 串行化;
知识点1: 如何在hibernate中指定数据库的隔离级别
知识点2:在项目中如何管理事务
在业务开始之前,打开事务;
在业务执行之后,提交事务;
在执行过程中出现异常,回滚事务;
在dao层操作数据库需要用到session对象。 在service层控制事务也是使用session对象完成,因此我们要确保dao层和service层使用的是同一个session对象。
在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了。我们开发人员只需要调用sf.getCurrentSession()方法即可获得与当前线程绑定的session对象。
注意1:调用getCurrentSession方法必须配合主配置中的一段配置
指定session与当前线程绑定:<property name="hibernate.current_session_context_class"> thread </property>
而 HibernateUtils.openSession( ) 方法是每次获得新的session;
注意2: 通过getCurrentSession 方法获得的session对象, 当事务提交时,session会自动关闭。所以切记不要手动调用close关闭,否则抛出异常。
改造crm代码
7. hibernate 中的批量查询 三种方式: HQL查询, Criteria查询 , 原生SQL查询
1. HQL( Hibernate Query Language)查询: Hibernate 独家查询语言,属于面向对象的查询语言;
在多表查询且不复杂时使用
(1)HQL基本查询的一般步骤:
1. 书写HQL语句
//其他写法:String hql = " from cn.itheima.domain.Customer ";
String hql = " from Customer "; // 查询所有Customer对象
2. 根据HQL语句创建查询对象
Query query = session.createQuery( hql );
3. 根据查询对象获得查询结果
List<Customer> list = query.list( ); // 返回list结果
//其他写法:query.uniqueResult( ); //接收唯一的查询结果
System.out.println(list);
注意: 在HQL语句中,只能出现对象名和属性名,不可能出现任何数据库相关的信息的;
(2)HQL条件查询 String hql = " from Customer where cust_id = 1 ";
问号占位符: String hql = " from Customer where cust_id = ? "; query.setLong(0,1l); //设置参数
命名占位符: String hql = " from Customer where cust_id = :cust_id "; query.setParameter("cust_id",1l); //设置参数
(3)HQL分页查询 String hql = " from Customer "; query.setFirstResult( 0 ); query.setMaxResults( 1 );
2. Criteria 查询: Hibernate 自创的无语句面向对象查询; 单表条件查询
(1)基本查询:
Criteria criteria = session.createCriteria( Customer.class ); //创建 criteria 查询对象
List < Customer > list = criteria.list( ) ;
System.out.println( list );
(2) 条件查询:
Criteria criteria = session.createCriteria( Customer.class ); //创建 criteria 查询对象
criteria.add( Restrictions.eq("cust_id",1l ) ); // 添加查询参数——查询cust_id 为1 的Customer对象
Customer c = ( Customer ) criteria.uniqueResult( ); //执行查询获得结果
System.out.println(c);
SQL语句的条件查询: > , >= , < , <= , == , != , in , between and , like , is not null , is null , or , and
HQL语句中对应的: gt , ge , lt , le , eq , ne , in , between , like , isNotNull , isNull , or , and
(3) 分页查询
Criteria criteria = session.createCriteria( Customer.class ); //创建criteria 查询对象
criteria.setFirstResult( 0 ); criteria.setMaxResults(1 ); // 设置分页设置
List< Customer > List = criteria.list( ); //执行查询
System.out.println( list );
(4) 查询总记录数
Criteria criteria = session.createCriteria( Customer.class ); //创建criteria 查询对象
criteria.setProjection(Projections.rowCount( ) ); // 设置查询的聚合函数——总行数
Long count = (Long) criteria.uniqueResult( ); //执行查询
System.out.println( count );
3. 原生SQL查询(复杂的业务查询)
(1)基本查询:
String sql = " select * from cst_customer " ; //书写sql语句
SQLQuery query = session.createSQLQuery( sql ) ;// 创建sql 查询对象
query.addEntity( Customer.class ); //指定将结果集封装到哪个对象中
List< Customer > list = query.list( ); // 调用方法查询结果
System.out.println( list );
//List< Object[ ] > list = query.list( ); //调用方法查询结果
//for( Object[ ] objs : list ){
// System.out.println(Arrays.toString( objs ) );
// }
(2)条件查询
(3)分页查询
8. 练习——客户列表
运行流程:
1. 请求 发送给 ListCustomerServlet , 包括:
(1)调用service查询客户列表; CustomerService 中: List< Customer > getAll( ) 事务处理,调用dao
CustomerDao 中: List< Customer > getAll( ) , HQL 或 Criteria
(2)将列表数据放入request域;
(3)转发到list页面显示列表;