第一章 耦合与解耦合
1.目标
应用逻辑和数据访问相分离:sql语句和业务分离
数据库变化,不需要修改业务逻辑
2.DAO模式
dataaccsessor:封装对数据库的访问
activedomain object: 对象bean,被业务逻辑调用
objectbean ——data accessor——数据表
3.持久层设计和资源管理模式
连接池:数据库连接,如DBCP、proxool
decorator模式
statementpool:缓存statement,一般情况statement是在connection创建后得到,当connection关闭,则statement对象也释放,但如果使用连接池,则需要对statement也缓存。
4.持久层设计和ORM
iBatis:可控制更多的数据库细节
hibernate:对持久层进行彻底封装,从而将底层细节与上层架构完全分离
第二章 hibernate
1.优点
lazy-loading 新的事件处理模型 uncheckedhibernateException
2.日志配置
在logger.properties的log4j.net.sf.hibernate=error定义级别
3.操作流程
1)初始化配置管理类Configuration
2)创建sessionFactory
3)通过sessionFactory得到session
4)使用session.save()和session.flush()完成数据保存
第三章hibernate基础
1.一个应用针对一个数据库共享一个SessionFactory实例。一个session只能由一个线程调用
2.CRUD的实现
插入:session.save(obj)
更新、删除 Queryquery=session.createQuery(hql) query.executeUpdate()
4.OR映射
hibernate有丰富的类型(CLOB BLOB currency),也可自定义类型
实体映射:主键映射(建议主键和业务逻辑无关)
<idname="类中id" column="数据表的id"type="" generator class="native 主键生成方式"/> class有native(hibernate决定),assigned(应用逻辑产生的),identity(数据库提供的主键生成机制),uuid.hex(hibernate产生的唯一的16进制数,如逻辑允许则采用),foreign(外部表字段)
映射类实现seriable接口,且不使用final修饰,无参数构造函数
5.自定义数据类型
基于设计上的考虑,如List<File>到数据表String如何自动转换
6.复合主键映射
复合主键的引入,在很大程度上标明业务逻辑已经入侵数据库存储逻辑,在新系统中应该避免,通过composite-id定义
7.blog clob字段映射
blob用于存储二进制、clob存储大量文本数据
此两种格式,不同的数据库有不同的映射,可使用自定义数据类型封装这些差异
8.实体映射策略
1)实体粒度设计
对于数据库中一个复杂表,在hbm.xml中使用component将其转换为多个对象,这些对象间是包含、组成关系
2)性能粒度设计
对于clob和blob字段,使用hibernate的延迟加载功能,则只有在调用getImage和getText才加载
3)实体层次设计
java的继承类在数据库中如何表示
方案1:tableper subclass。有一个基类表,每个子类也有表。如基类表TItem,子类表Tbook的外键是TItem的主键。适合子类的扩展。
方案2:tableper class hierachy. 所有类在一张表中,好处是查询效率高,坏处是扩展需修改原有表,并且子类种类太多,表字段会很庞大。
9.数据关联
一对一(主键相同),如公民user和护照passport使用同一主键,user使用Oneto one 配置,passport使用oneto one 和foreign
一对多(外键约束),使用<many-to-one>,多在1类中常为collection类型,如一个用户有多个地址
双向一对多:在user中配置一对多,在address中配置多对一,好处是保存对象时只执行一个SQL语句,映射到类中时address类包含一个User对象。
多对多:在两个java类中都会保存对方,性能不佳,在设计中避免大量使用。可使用延迟加载提高性能
10.数据检索
1)使用DetachedCriteria,当session失效时,仍可使用,从而实现重用
2)HQL
参数动态绑定: ?(顺位占位符) :变量名(引用占位符,可读性更强)
3)可在配置文件中制定sql-insert sql-updae sql-delete方式
4)可在配置文件中<query>配置hql语句,再通过session,getNamedQuery调用hql,例如"foruser inner join fetch user.addresses" 完成user和address的内连接,其中fetch表示address读出后立即填充到user对象,fetch只对innerjoin和leftjoin有效。
11.数据加载
1)即使加载:立刻加载其关联数据
2)延迟加载:对集合类型(一对多、多对一、多对多关系中尽量使用延迟加载); 可通过批量提交多个查询条件,一次完成多个数据的读取;可设置<classbatch-size>打开批量加载功能《10
3)预先加载:可通过一条sql语句完成实体和关联数据的读取,使用outer-join方式实现,对一对多和多对多的collection属性不推荐,而即时读取需要两条。
4)批量加载:将同类型待加载的hql批量提交,如whereid=1 or id=2
12.对象识别
1)判断两个对象相等,先调用hascode方法,若相同再调用equals方法
2)判断两实体对象相等,在hibernate重视会用ID
13.Lifecyclehe和validatable
当执行CRUD时,捕获并执行相应处理,类似于触发器,可用于对关键信息提供日志记录
14.分页
query.setFirstResult和setFetchSize实现分页
15.session管理
filter在servlet调用前执行,在servlet调用后结束,所以在filter中管理session很正常
16.数据层功能的扩展
1)延迟决策:不要实现一个大而全的基类,把功能推迟到子类中实现
2)子类方法实现不同,属性相同,则引入一标识属性type:在hibernatemap中通过subclassdiscriminator-value='value'区分
3)子类有新的属性,则引入一新表解决,新表只包含这种类型专有的数据,再通过joined-class到基类
4)在需要时保持冗余,即把joined-class转化为subclass,在业务系统中,一些大表如上10万条数据,每次实现一个子类就要增加一个新表,就会造成过度jon,这会造成数据库无谓的开销
17.优化策略
1)缓存策略:根据每个表实际情况,指定匹配的缓存模式
2)session管理:实现thread级别的重用
3)尽量使用延迟加载
4)合适的batch-size参数
5)使用UUID作为主键生成器
6)若可能,选用基于version的乐观锁代替悲观锁
7)开发中,打开sql日志输出(hibernate_show_sql)
18.开发流程
1)详细设计+ER图
2)生成java类——》生成ddl和hbm.xml文件
3)容器、session、事务
第四章hibernate可用工具
1.基础代码生成流程
基础代码包括java类、DDL、hbm.xml
ER工具——》数据库定义——》hbm.xml(MiddleGen)——》java类(hbm2java)
java类——》hbm.xml(xdoclet)——》ddl(schemaexport、hibernatesynchronizer)
初期使用middlegen根据数据库定义,在重构中使用schemaExport
2. hibernate extension
hbm2java:hbm.xml生成java文件
class2hbm:class文件生成hbm.xml
ddl2hbm: ddl生成hbm.xml
第五章hibernate的高级特性
1.hibernate持久化实现
1)对象状态:PO和VO看是否纳入hibernate管理中
2)脏数据检查:通过dynamicproxy对setter进行拦截,当其被调用,将其标记为待更新; 数据版本对比,当数据提交时,将提交版本与最近读取版本比较
2.数据缓存
1)缓存策略:
事务级缓存:在session生命周期内
应用级缓存:在多个事务间共享,由sessionFactory实现,所有sessionFactory创建的session实例共享此缓存
分布式缓存:在多个应用实例、多个JVM间共享缓存模式
2)hibernate中分为事务级和应用级两类。通过id加载数据,延迟加载时起作用
3.事务管理
指定hibernate.transaction.factory-class属性 有默认值
默认使用Jdbc实现
可使用optimistic-lock对表加入乐观锁,表和类有一version字段。乐观锁使用版本控制方式,当A提交修改时版本+1,如a的v>服务器v,则先修改并更新版本号。
4.持久层操作
1)数据加载
load/get都实现通过主键加载对象,优先考虑load
查询性能 find/iterator:find无法利用缓存,其对缓存只写不读,而iterator充分利用缓存,对频繁读取比较有利。对于大批量数据通过sql或存储过程实现。
querycache:解决完全相同的多次查询,满足条件表没有变+sql相同。在hibernate.cfg.xml中打开cache.user_query_cache选项,并query.setCacheable(true)
2)数据保存
saveOrUpdate:对参数object判断数据库中id是否存在,否则保存,有则更新
3)数据批量操作
批量导入:在JDBC中,对批量导入使用PreparedStatement.executeBatch完成,在hibernate中,设置jdbc.batch_size指定一次提交的sql数量,mysql的批量导入在hibernate不支持,需配合commit和循环指定每次提交的sql数量
批量删除:bulkdelete/update 无法保证缓存数据的一致有效性,则进行批量更新、删除时,使用迭代比较保险
5. collection
无序集:set(不允许重复)、bag(允许重复元素,使用idbag解决删除时不能唯一标识的问题)、map(键值对应)
有序集:list(保持表中数据的顺序,要求表有对应字段保存次序信息)
6.结果集排序——在hbm.xml中
JVM排序,制定sort
order-by xml中指定
7.拦截器
可以实现interceptor接口或继承EmptyInterceptor,实现对insertupdate delete load query之前的处理
8.性能检测
P6SPY(针对数据库访问操作)
SQLProfiler 使用图形界面监控:sql语句查询次数、执行时间、优化建议、statement实时刷新信息
第十章IBatis介绍
iBatis关注OR即pojo与sql间的映射,并不会在运行时自动生成sql,具体的sql由程序员编写,然后通过映射文件将sql所需的参数及返回值映射到POJO,用于解决:
1)客户只对开发团队提供几条selectsql或存储过程,具体表结构不公开
2)所有涉及业务逻辑部分的数据库操作由存储过程完成
3)熊数据量大,性能要求极为苛刻,使用高度优化的sql语句