《“爱读书”--给你讲技术》,我来看书,你来进步,让我们开始吧!
本书简介
书名为《轻量级JavaEE企业应用实战》,是本人在学习JavaEE框架的时候阅读的第一本书,本书对于框架及相关基础知识讲述的比较详细和浅显,适合初学者和需要全面了解JavaEE知识的人群。
本文内容为本书第五章
![f202e137008cb72b45db1661cae03406.png](https://i-blog.csdnimg.cn/blog_migrate/b062fa77228ef08e03d3a24b1dfdfbb6.jpeg)
ORM和Hibernate
1.对象关系数据库映射
ORM的全称是Object/Relation Mapping,对象/关系数据库映射。ORM实现了面向对象的编程语言到关系数据库的映射,它既可利用面向对象语言的简单易用性,又可利用关系数据库的技术优势。ORM作用是把对持久化对象的保存、删除、修改等操作,转换成对数据库的操作。
JPA规范就是一种ORM规范,JPA规范并不提供任何ORM实现,只提供了系列面向的编程接口
2.基本映射方式
ORM有如下几条映射关系:
- 数据表映射类:持久化类被映射到一个数据表。当时用持久化类来创建实例、修改属性、删除实例时,系统将自动转换成对这个表的CRUD操作。
- 数据表的行映射对象(即实例):持久化类会生成很多实例,每个实例就对应数据表中的一行记录。
- 数据表的列映射对象的属性:当修改某个持久化对象的指定属性时,ORM将转换成对数据表中指定数据行和数据列的操作。
Hibernate实现数据库操作
PO(持久化对象),作用是完成持久化操作,可通过该对象进行增删改查操作。Hibernate直接采用了POJO作为PO,不要求继承任何父类或实现任何接口。仅仅JavaBean并不具备持久化操作能力,需要结合映射文件。所以说PO=POJO+映射文件
除此之外,数据库的基本配置需要通过Hibernate配置文件来实现。默认的配置文件为hibernate.cfg.xml。
为了使用Hibernate进行持久化操作,通常步骤如下:
(1)开发持久化类,由POJO加映射文件组成
(2)获取SessionFactory
(3)获取Session,打开事务
(4)用面向对象的方式操作数据库
(5)关闭事务,关闭Session
PO的三种状态
- 瞬态:如果PO实例从未与Session关联,则PO处于瞬态
- 持久化:如果PO实例与Session关联起来,且该实例对应到数据库记录,则处于持久化态
- 托管:如果PO实例曾与Session关联过,但因为Session关闭等原因,PO实例脱离了Session的管理,则处于托管状态
对PO的操作必须在Session管理下才能同步到数据库。Session由SessionFactory工厂产生,SessionFactory是数据库编译后的内存镜像,通过一个应用对应一个SessionFactory。SessionFactory由Configuration对象产生,Configuration对象负责加载Hibernate配置文件
Hibernate体系结构
![c0dd945a3c8ad4eb20f359a48ff0f7d5.png](https://i-blog.csdnimg.cn/blog_migrate/5dfdb25da543237464e76a8833413d24.jpeg)
PS:由上图可见Hibernate体系结构是有PO+映射文件实现了应用对数据库的操作
Hibernate 持久化解决方案如下图:
![1c6ce7cec84a1ba4fc4902d5c5edb2f0.png](https://i-blog.csdnimg.cn/blog_migrate/e94e58319712a43c27cbd7a6baa373dd.jpeg)
PS:Hibernate持久化解决方案将用户从原始的JDBC访问中释放出来,用户无需关注底层的JDBC操作,而是以面向对象的方式进行持久层操作。底层数据连接的获取、数据访问的实现、事务控制都无需用户关心。
下面我们逐一解释图中的一些关键词
- SessionFactory:这是Hibernate关键对象,它是单个数据库映射关系经过编译后的内存镜像,它是线程安全的,是生成Session的工厂。
- Session:它是应用与持久化层之间交互操作的一个单线程对象,也是Hibernate持久化操作的关键对象,所有持久化对象必须在Session的管理下才可以进行。它底层封装了JDBC连接,是Transaction工厂。Session对象持有一个必选的以一级缓存,显示执行flush前,所有数据都缓存在Session中。
- 持久化对象:系统创建的POJO实例,一旦与Session关联,并对应数据表的指定记录,该对象处于持久化状态。在程序中对持久化对象执行的修改,都将自动被转换为持久层的修改。
- 事务(Transaction):代表一个原子操作,它具有数据库事务的概念。Hibernate事务是对底层具体的JDBC、JTA的抽象。在某些情况下,一个Session可能包含多个Transaction对象,所有的持久化操作都应该在事务管理下进行,即使是只读操作。
- 连接提供者(ConnectionProvider):它是生成JDBC连接的工厂。它通过抽象将应用于底层的DataSource或DriverManager隔离开。实际应用中ConnnectProvider通常由DataSource充当,由于SessionFactory底层封装了ConnnectProvider,因此SessionFactory底层封装了DataSource。
- 事务工厂(TransactionFactory):它是生成Transaction实例的工厂。该对象无须应用直接访问,它负责对底层具体的事务实现进行封装,将底层具体的事务抽象成Hibernate事务。
深入Hibernate配置文件
1.创建Configuration对象
每个Hibernate配置文件对应一个Configuration对象。Configuration实例的唯一作用是创建SessionFactory实例,一旦SessionFactory创建完成,它就被丢弃了。
可通过如下几种方式配置Hibernate,他们创建Configuration实例的方式不同:
- 使用hibernate.properties文件
![4fdf5c4de89d32026676d2a6b8030866.png](https://i-blog.csdnimg.cn/blog_migrate/300b6c66024a6567fc38f417b8d679e4.jpeg)
![9915a5292ed20b532b1365dccfc260be.png](https://i-blog.csdnimg.cn/blog_migrate/42a7d1a0b51924bb52f7078feff1f99e.jpeg)
![e747ca91c0d0c653395c4edf53dcaa76.png](https://i-blog.csdnimg.cn/blog_migrate/5211e0f6d3050e9128bf54add9833547.jpeg)
2.配置的JDBC连接属性
![1aba2a976159c4d6d362096e03203533.png](https://i-blog.csdnimg.cn/blog_migrate/3c73bc5d232dd19100138d4cdb79e299.jpeg)
3.数据库方言
Hibernate底层依然使用SQL语句来执行数据库操作,但不同关系型数据库的SQL都略有不同,所以我们需要告诉Hibernate底层使用了哪种数据库,这就是数据库方言。设置了方言后,Hibernate将自动应付底层数据库访问所存在的差异。
![412eaccb3f75edf095d3201f58fa62c0.png](https://i-blog.csdnimg.cn/blog_migrate/614fa1a16e363571ba119f65a8541cd4.jpeg)
![730921c72855acd7d8c567e654c97f94.png](https://i-blog.csdnimg.cn/blog_migrate/2f461b2d27fd41775325dc3b98b22774.jpeg)
4.二级缓存相关属性
![b02bcdbb379ba2d77f332735365331af.png](https://i-blog.csdnimg.cn/blog_migrate/fd2e2519deb8f821d6a192686ebb6e3f.jpeg)
5.其他常用配置属性
- hibernate.show_sql:是否在控制台输出Hibernate生成的SQL语句,只能是true或false
- hibernate.format_sql:是否将SQL语句转成格式良好的SQL,只能使true或false
- hibernate.use_sql_comments:是否在Hibernate生成SQL语句中添加注释,true或false
- hibernate.jdbc.fetch_size:指定JDBC抓取数据数量的大小
- hibernate.jdbc.batch_size:指定JDBC批量更新的大小
- hiberante.connection.autocommit:设置是否自动提交,不建议打开
- hibernate.hbm2ddl.auto:设置创建SessionFactory时,是否根据映射文件自动建立数据库表。如使用create-drop,则关闭SessionFactory时将drop刚建的数据表。该属性可以为update、create、create-drop。
深入Hibernate映射文件
1.映射文件结构
映射文件的根元素为,该元素下可以拥有多个子元素,每个子元素对应一个持久化类的映射。
元素属性:
- schema:指定所映射数据库的schema名,如果制定了该属性,则表名会自动添加schema前缀
- catalog:指定所映射数据库的catalog名,如果指定了该属性,则表名会自动添加catalog前缀
- default-cascade:设置默认级联风格,默认值none。当配置java属性映射和集合映射时还可指定cascade属性,用于覆盖默认值。
- default-access:指定默认的属性访问策略,默认值property,即使用getter和setter方法来访问属性。如果指定access="field",则会忽略getter和setter方法,而通过反射来访问成员变量。
- default-lazy:设置默认延迟加载策略,默认值true,即启动延迟加载策略。当配置java属性映射和集合映射时还可指定lazy属性,用于覆盖默认值。
- auto-import:设置是否允许在查询语言中使用非全限定类名。默认值true。
- package:指定一个包前缀,用于映射文件中没有指定全限定类名,则默认使用该包前缀
元素属性:
- name:指定该持久化类的全限定类名
- table:指定该持久化类的表名,默认已持久化类的类名作为表名
- dynamic-update:指定用于更新记录的update语句是否在运行时动态生成,并且只更新那么些改变过的字段。默认false。
- dynamic-insert:指定用于插入记录的insert语句是否在运行时动态生成,并且只插入那些非空字段。默认false。
- select-before-update:指定在更新某个持久化对象之前是否需要先进行一次查询。如果为true,则可以保证只有当持久化对象的状态被修改过时,才会使用update语句来保存其状态。默认false。
- where:指定一个附加的SQL语句中过滤条件。
- batch-size:指定来抓取实例时每批抓取的实例数。默认1
- optimistic-lock:指定乐观锁策略。默认值version
2.映射主键
Hibernate需要给每个持久化类定义一个标识属性,用于唯一的标识某个持久化实例,该标识属性需要映射到数据库的主键。
标识属性通过元素指定,元素的属性如下:
- name:指定持久化类标识属性名。
- type:指定该标识属性的数据类型。既可以是Hibernate内建类型,也可以是java类型,java类型需使用全限定类名。
- column:设置标识属性所映射的数据列的列名
- access:指定访问标书属性的访问策略
主键生成器使用元素,class属性为生成器策略:
- increment:为long、short、int类型主键生成唯一标识。多进程下不要使用。
- indentity:在DB2、MySQL、SQL Server等提供自增主键的数据库中使用。
- sequence:在Oracle等提供序列支持的数据库中使用。
- uuid:用128位的UUID算法生成字符串类型的标识符。
- native:根据底层数据库的能力选择indentity、sequence或hilo中的一个
- assigned:让应用在save()之前为对象手工设置一个标识符
- foreign:表明直接使用另一个关联的对象的标识属性值
举例如下:
![637c77d7c7a64468190713a0af45cff2.png](https://i-blog.csdnimg.cn/blog_migrate/45f50ab9d7bff97c66b48a9f452ba269.jpeg)
3.映射普通属性
使用元素来映射普通属性。元素属性如下:
- name:映射持久化类的属性名
- column:配置该属性所对应的数据表的列名
- type:指定普通属性的数据类型
- update、insert:用于设置生成的update或insert语句中是否需要包含该字段,默认true
- formula:指定一个SQL表达式,指定该属性的值将根据表达式来计算
- access:指定访问该属性的访问策略,默认是property
- lazy:指定当该实例属性第一个被访问时,是否启动延迟加载。默认false
- unique:设置是否为该属性所映射的数据列添加唯一约束
- not-null:设置是否为该属性所映射的数据列添加not null约束
- optimistic-lock:设置该属性在进行更新时是否需要使用乐观锁。默认true,即属性值发生改变时,版本号增加
- generated:设置该属性映射的数据列的值是否由数据库生成。包括never、insert、always
- length:指定该属性所映射的数据列的字段长度
- precision:指定该属性所映射数据列的有效数字位数
- scale:指定该属性所映射数据列的小数位数
4.映射集合属性
两个持久化对象不能共享一个集合元素的引用
集合映射元素包括:
- list:用于映射List集合属性
- set:用于映射Set集合属性
- map:用于映射Map集合属性
- array:用于映射数组集合属性
映射集合属性的元素包含如下属性:
- name:该集合属性的名称
- table:指定保存集合属性的表名
- schema:指定集合属性的数据表schema名称
- lazy:设置是否启动延迟加载,默认true
- inverse:指定该集合关联的实体在双向关联中不控制关联关系
- cascade:指定对持久化对象的操作是否会级联到它所关联的子实体
- order-by:用于设置数据库对集合元素排序
- sort:指定集合的排序顺序
- where:指定任意的SQL语句中where条件
- batch-size:定义延迟加载时每批抓取集合元素的数量,默认1
- access:指定访问集合属性的访问策略,默认property
因为集合属性都需要保存到另一个数据表中,所以保存集合属性的数据表必须包含一个外键列,通过在、元素中使用子元素来映射,key属性如下:
- column:指定外键字段的列名
- on-delete:指定外键约束是否打开数据库级别的级联删除
- property-ref:指定外键引用的字段是否为原表的主键
映射集合元素的索引列:
- :用于映射List集合、数组的索引列
- :用于映射Map集合、基本数据类型的索引列
映射集合的集合元素:
- :集合元素是基本类型、字符串和日期是使用
- :集合元素是复合类型时使用
- 或:集合元素是其他持久化对象的引用时使用
(1)List集合属性
![34e43641041a32b8162c51912b602773.png](https://i-blog.csdnimg.cn/blog_migrate/3fcfcbab11ed776b9a960c54ed17d4e4.jpeg)
(2)数组属性
![ef0f359913de8712633c54ceeabf3477.png](https://i-blog.csdnimg.cn/blog_migrate/3463259564a3da27ae587a1618c0ce08.jpeg)
(3)Set集合属性
![a68451afae2950772507d59f1fae5d33.png](https://i-blog.csdnimg.cn/blog_migrate/f69fc62a2d79eda25167726530329fb4.jpeg)
(4)Map集合属性
![6c20728b86a46d6e74ebf2a9ecbcac2f.png](https://i-blog.csdnimg.cn/blog_migrate/0cead28486c16bc400f39eb057d29c3d.jpeg)
5.映射组件属性
组件属性意思是持久化类的属性的类型是复合类型的对象,它仅被当做值类型,并非引用另一个持久化实体。
我们使用元素来映射组件属性
- name:指定该组件属性的名称
- class:指定组件类的类名
- lazy:设置该组件是否在持久化对象第一次被访问时启动延迟加载。默认值true
- optimistic-lock:设置更新该组件属性是否需要获取乐观锁
一个自定义类通常包括其他属性,通过为元素增加子元素来实现。
例如:
![3cce6dea6e4909258614b9d96bb569b2.png](https://i-blog.csdnimg.cn/blog_migrate/4038497605084820a20bc4662857b3b3.jpeg)
![2c9d4c0e94a371379f4df348e9b2bfc9.png](https://i-blog.csdnimg.cn/blog_migrate/b25ed9a83195f7e7b6129f3c31058166.jpeg)
使用JPA Annotation标注实体
用注解来定义一个实体类
![317ab79870b03d5ba658269b747f2d0c.png](https://i-blog.csdnimg.cn/blog_migrate/cad80cb4874de3853234a0a29473dd7f.jpeg)
![ac243218141ee61de167f32583ceb35e.png](https://i-blog.csdnimg.cn/blog_migrate/4c6ca73b1aacbd60de29af50c2ac973d.jpeg)
@Entity用于标注该类是一个持久化类
@EmbeddedId用于标注符合类型的标识属性
@Embedded用于标注一个组件属性
配置了上面的注解,也就不再需求*.hbm映射文件了,接下来我们需要配置hibernate.cfg.xml让Hibernate去加载指定实体类,而不是根据映射文件加载。配置如下图:
![39d8b472ff7ecf07090811cd2b3a1435.png](https://i-blog.csdnimg.cn/blog_migrate/634a7ccc9089f04343af5a5210388f65.jpeg)