路线:
- Hibernate的概述,原理,简单的API使用
- 一级缓存和其他API
- 1vN和NvN的配置
- Hibernate的查询方式和抓取策略
- CRM案例
引入:CRM系统【百度百科】
客户关系管理系统(CRM)是以客户数据的管理为核心,利用信息科学技术,实现市场营销、销售、服务等活动自动化,并建立一个客户信息的收集、管理、分析、利用的系统,帮助企业实现以客户为中心的管理模式。客户关系管理既是一种管理理念,又是一种软件技术。
客户关系管理系统主要有高可控性的数据库、更高的安全性、数据实时更新等特点,提供日程管理、订单管理、发票管理、知识库管理等功能。
客户关系一对一理论。满足每个客户的特殊需求,同每个客户建立联系,通过同客户的联系来了解客户的不同需求,并在此基础上进行"一对一"个性化服务。
从新客户接入到老客户维护和营销的每一个环节。与销售、营销、推广、策划、人事等多部门业务对接。优化各业务环节,减少各环节客户流失,和公司成本。----------市场营销、数据分析、掌控能力等
CRM系统是一种综合性的概念,这样的系统一般就是面向客户的数据信息,可以分为若干模块。如客户信息管理、联系人管理、统计分析、综合查询等。
简单解释,销售方业务员工(用户)使用这种系统,先去找到客户方的某些代表的联系人(联系人管理),通过他们开发成客户,并记录这个过程中的信息(客户拜访管理),然后把客户的资料录入系统(客户信息管理),然后可以随时通过系统查询上述这些所有的信息(综合查询),进而进行一些相应的分析处理(统计分析)。 另外,这个系统本身还有一些基本的管理和使用,比如账户、日志等(系统管理)。
本案例仅涉及CRM中客户信息管理的CRUD操作及配置
Hibernate是什么?怎么用?
框架是一种软件的半成品,未完全加工。
经典的JAVA EE(服务端)分为Web、业务、持久三层结构。不同的技术和框架对应着不同的层次,这是在长期经验下的产物,或者说建议。使用传统的 Servlet + Jsp + JavaBean + JDBC 可以完成开发,但是框架的好处是加快快发效率,性能更加优越。
常用架构对应的分层示意图:![图一 EE的三层结构](assets/图一 EE的三层结构2.bmp)
总结:持久层中的ORM框架,对JDBC进行了轻量级封装,自动化。ORM也就是对象关系映射,将Java中的对象和数据库的表通过xml做映射,达到操作对象就是直接操作表的目的。
优点:1)对JDBC的轻量级封装,简化数据访问层的重复性代码,减少内存消耗,提高效率
2)框架,优秀的ORM实现,简化DAO(Data Access Object)层的实现
3)性能强,扩展性强——多种RDB,多种ER关系映射;可拓展,多种API,开源。【注】:性能高是相对的,一般来说越底层的访问速率是越快的,而上层的提供了许多方便的拓展使用方法,进行了一些优化,达到提升性能的结果。
版本:3.x(5.x类似,兼容),4.x
使用:
- [下载](<https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/)文件,解压;
- 解压文件目录中包含doc(文档),lib(库),project(预设项目);其中lib中含有必须和非必须的各种库文件(jar包)
- 创建Java项目或者WEB项目时均可引用,使用的方式就是导JAR包;
- 数据库操作的JAR包:数据库驱动如 MySQL,JDBC/C3P0等
- lib中的required中的包
- 日志记录包log4j——便于开发
方式
-
创建数据表
-
创建实体类
-
使用hbm.xml(命名随意,但约定后缀),配置映射关系
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- 建立类与表的映射 --> <class name="com.itheima.hibernate.demo1.Customer" table="cst_customer"> <!-- 建立类中的属性与表中的主键对应 --> <id name="cust_id" column="cust_id" > <generator class="native"/> </id> <!-- 建立类中的普通的属性和表的字段的对应 --> <property name="cust_name" column="cust_name" length="32" /> <property name="cust_source" column="cust_source" length="32"/> <property name="cust_industry" column="cust_industry"/> <property name="cust_level" column="cust_level"/> <property name="cust_phone" column="cust_phone"/> <property name="cust_mobile" column="cust_mobile"/> </class> </hibernate-mapping>
-
Hibernate的全局配置cfg.xml,配置的说明在解压文件下l\project\etc\hibernate.properties中有示例
- 配置数据库:驱动,服务器,端口号,数据库
- Hibernate方言
- 数据库连接池
- 导入映射文件
配置文件
-
映射配置文件 ------xxx.hbm.xml
-
<hibernate-mapping>下配置所有
-
<class>/<id>/<property>标签
-
字段:name,column等,length在hibernate自动建表时使用
-
【class标签的配置】
-
标签用来建立类与表的映射关系
-
属性:
-
name :类的全路径
-
table :表名(类名与表名一致,table可以省略)
-
catalog :数据库名
-
【id标签的配置】
-
标签用来建立类中的属性与表中的主键的对应关系
-
属性:
-
name :类中的属性名
-
column :表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
-
length :长度
-
type :类型
-
【property标签的配置】
-
标签用来建立类中的普通属性与表的字段的对应关系
-
属性:
-
name :类中的属性名
-
column:表中的字段名
-
length :长度
-
type :类型
-
not-null :设置非空
-
unique :设置唯一
-
-
-
-
hibernate核心配置 hibernate.cfg.xml
- <hibernate-configuration>下配置所有,注:配置同样可以使用properties文件配置,但是这样加载不了映射文件
- <session-factory>配置会话工厂,相当于配置不同的连接容器,用来解析后创建不同的连接池,包含多个连接,也就是session
- 数据库的配置(驱动,DB,账户,密码等) 【必须】
- 方言配置——控制不同的数据库会话 【必须】
- 映射文件<mapping> , 也可以使用手动加载
- 【可选】SQL语句的打印(console)与格式化,自动创建表——用作测试和验证
- 显示SQL :hibernate.show_sql
格式化SQL :hibernate.format_sql
自动建表 :hibernate.hbm2ddl.auto- none:不使用hibernate的自动建表
- create:如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试)
- create-drop :如果数据库中已经有表,删除原有表,执行操作,删除这个表。如果没有表,新建一个,使用完了删除该表。(测试)
- update:如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)
- validate :如果没有表,不会创建表。只会使用数据库中原有的表。(校验映射和表结构)。
- 显示SQL :hibernate.show_sql
核心API (几个对象)
-
Configuration: 加载核心配置文件,映射配置文件(手动加载);用来配置Hibernate,启动Hibernate;启动时映射到不同的xml文件,然后创建SessionFactory对象。
-
SessionFactory:初始化hibernate,数据源的代理(相当于连接池),session的工厂,使用Configuration创建;维护hibernate的数据库连接池和二级缓存(已基本弃用);线程安全的,一个项目只需一个;也可以手动配置另外的如C3P0连接池(需导入相应的jar包)
- 于是,可以在一个项目中,使用一个工具类,抽取出相应的Session工厂;
- 同一个项目使用一个工厂即可,用来返回不同的session
-
Session:Session代表的是Hibernate与数据库的链接对象,类似于connection。不是线程安全的,所有一般会获取多个,单独使用。与数据库交互的桥梁。具有一批方法,来进行CRUD操作:
-
保存:Serializable save(Object obj); 返回序列化的键——序号
-
查询:T get(Class c,Serializable id); T load(Class c,Serializable id);
get和load的区别:get是立即执行发送SQL,返回查询到的对象或者null;load懒加载,使用对象的时候才执行查询的SQL(除了ID可以直接获取外);
get返回是真实对象,load返回的是代理对象(javassist),对象不存在的时候报错
-
修改:void update(Object obj);直接修改(相同ID的新对象替代),先查询再修改
-
删除:void delete(Object obj);根据删除(相同ID序号的新对象),先查询再删除,支持Hibernate的级联删除
-
【不常用】保存或更新:void saveOrUpdate(Object obj)
-
【不常用】查询所有: Query createSQLQuery(String sql) 同样支持HQL createQuery()
-
-
Transaction:事务对象,commit、rollback
基础笔记(案例一、基于Hibernate的DAO操作)
-
持久化与持久化类
Hibernate是持久层的ORM映射框架,专注于数据的持久化工作——也就是内存数据永久性地写入到数据库中。Java中与数据库表中完成对应的映射类文件,称为持久化类——或者说带有映射文件的Java类对象。
- 持久化类的规则
- 必须有一个无参的构造函数:Hibernate使用反射来生成实例对象,类的class字节码需要;
- 私有属性必须有get/set方法,Hibernate设置对象的值
- 类中必须一个和表主键对应的属性——唯一性
- 类中属性尽量使用包装类型,如Integer,Long——基本数据类型的默认值是0,存在歧义,例如int型的年龄,入DB的是0,是0还是忘了插入?
- 类不用final进行修饰——与延迟加载有关,延迟加载是Hibernate的一种优化,返回的是代理对象,其底层用到了继承,这样一来会使延迟加载失效,而返回真实对象
- 持久化类的规则
-
Hibernate主键生成策略
- 自然主键:表本身中的一个字段,具有实际意义,如身份证号,手机号
- 代理主键:表本身不是必须的,与个体的属性没有太大关联,如序列号,Cid,Sid等;【推荐使用】
- 原则:开闭原则,对拓展是开放的,对修改时封闭的
- 生成策略:Hibernate提供多种主键的生成策略,不需要用户自己操作
- increment:Hibernate的自增长,适用于short、int、long等类型主键,单线程使用;select max(ID) from 表,然后加1作为下一条记录,存在线程安全问题
- identity:数据库底层的自增长,不会产生线程安全问题,适用于short/int/long等,适用于有自增长的数据库产品,oracle不行
- sequence:适用于short、int、long等类型主键,适用含有序列的数据库,MySQL不支持
- uuid:字符串类型主键,Hibernate随机生成
- native:本地策略,可以视作在identity和sequence自动切换
- assigned:Hibernate不设置主键,需要手动插入
- foreign:外部,一对一的一种关联情况下使用
-
持久化类的三种状态
- 瞬时态:没有唯一的标识OID,没有被session管理
- 持久态:有唯一标识OID,被session管理
- 脱管态:有唯一标识OID,不被session管理;new 对象后,设置ID即可;将ID置为null,则转为瞬时态;
- 持久化类:**可以自动更新数据库;**Hibernate的一级缓存,也就是数据库数据的备份,存储在内存中
- 一级缓存,和session控制,生命周期与session一致;Hibernate默认自带与开启;用于减少对数据库的访问;调用session集合中的方法时,先访问缓存,没有则访问数据库,然后将其加载到一级缓存中。调用close()时,关闭session的缓存内容,clear()情况所有缓存,evict(object)清楚单个对象
- 二级缓存,需要手动开启,暂时不常用;
- 自动更新数据库:通过Hibernate缓存和快照实现,如果缓存和快照区数据不同了,那么就会将缓存更新到数据库中(事务提交时)。
-
事务
事务ACID,由隔离性引发的问题——读和写。
读问题:脏读、不可重复读、幻(虚)读
写问题:引发两类丢失更新
-
事务隔离级别
- read-un-commit: 未提交读
- read-commited:读已提交 Oracle默认
- repeatable read:重复读 MySQL默认
- Serializable:序列化
-
Hibernate的隔离级别配置:核心配置文件cfg.xml中,
<property name="hibernate.connection.isolation">1/2/4/8</property>
-
在开发中,DAO层负责单个的执行逻辑,对业务而言,service层才是处理事务的逻辑;这需要在事务的处理过程中,多个DB操作使用的是同一个连接对象(connection/session)。两种解决方法:1.向下传递同一个session对象;2. 使用ThreadLocal线程进行事务操作的绑定。
Hibernate的事物线程绑定,需要配置
<property name="hibernate.current_session_context_class">thread/jta等</property>
;配置完后即可在service包含的多个DAO操作中,通过获取当前线程中已绑定的session对象,完成;绑定线程后的session不需要再进行手动关闭,线程结束后自动关闭;
-
-
其他API
-
query:查询操作,接受HQL,查询多个对象,返回唯一结果等
示例:
public void demo4() { //Query Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //查询所有 String hql = "from Customer"; Query query = session.createQuery(hql); List<Customer> list = query.list(); // for (Customer customer : list) { // System.out.println(customer); // } //条件查询 // String hql2 = "from Customer where cust_name like ?"; // Query query2 = session.createQuery(hql2); // query2.setParameter(0, "1%"); // list = query2.list(); // for (Customer customer : list) { // System.out.println(customer); // } //分页查询 String hql3 = "from Customer"; Query query3 = session.createQuery(hql3); //起点 query3.setFirstResult(2); //size query3.setMaxResults(1); list = query3.list(); for (Customer customer : list) { System.out.println(customer); } transaction.commit(); }
-
Criteria:面向对象查询,QBC查询
public void demo() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); //查询所有 Criteria criteria = session.createCriteria(Customer.class); List<Customer> list = criteria.list(); //条件查询 //criteria.add(Restrictions.like("cust_name", "1%")); List<Customer> list2 = criteria.list(); //分页 criteria.setFirstResult(0); criteria.setMaxResults(2); List<Customer> list3 = criteria.list(); for (Customer customer : list3) { System.out.println(customer); } transaction.commit(); }
-
SQLQuery:SQL的查询,一般不常用
-
一对多的关系
案例:CRM中的客户和联系人
- 配置:一端和多端的实体都要使用实体对象的引用进行关系的关联;在各自的映射配置文件中,也需要使用关联的配置
- 级联操作:测试中,1的对象需要添加多的引用,多的集合要将1添加进来;没有在配置文件中配置级联保存或更新,则需要两端同时保存;否则保存了主体对象即可,也不需要配置双向的关联关系。
- 级联删除:删除1,多方参考的外键置为null(默认);设置了1的级联删除,则删除时同时删除关联的多方;也可以设置多方的级联,删除时同时删除关联的1方数据,且和1方关联的多方的其他数据也会删除(基本不用)
- cascade和inverse的区别:前者设置的是对象间的关联关系,后者管理的是键的管理关系;默认一方的inverse为false,表示不放弃外键的管理权。置为True后,保存1方的对象,会保存其关联(cascade)的多方对象入库,但是却没有外键
多对多的关系
- 多对多的关系,需要配置两个实体外,还需要一个关联表
- 如果进行的是双向关联,二者必须有一个放弃外键的控制,否则关联表中将会出现主键重复的冲突;非双向关联则不会出现错误
- 级联保存或更新:设置后可以只保存主体一方,否则出现瞬时对象异常;设置级联后不需要双向关联
- 级联删除:【基本不用】没有设置级联删除时,只会删除本表和关联表;设置cascade后,会将关联的表中数据一并删除
一对一的关系
- 一般转化为唯一外键对应
- 或直接主键对应