hibernate3框架学习

课程内容

一、SSH综合在一起是什么样的?
1)client端发起一个请求给app server(比如tomcat)
2)这个app server会把这个请求发给struts,调用dofilter进行分发
3)struts会找到acton
4)action会调用后台的service这层进行,业务逻辑处理
5)业务逻辑处理会用到model这层,用了hibernate就是dao层
6)在dao层会访问我们的实体类,model层
7)dao会帮我们把实体类的数据persistence到数据库
8)完成一系列的操作之后dao会把结果返回service
9)service会把结果返回action
10)action会返回struts的filter
11)struts返回jsp文件给客户端

spring在哪里?
spring会贯穿在整个的过程里头,spring提倡面向接口编程,面向抽象编程,好处是将来换实现的时候非常容易
spring会帮service注入到action里面去
spring会帮dao注入到service里面去
spring还会针对service进行声明式的事务管理
hibernate3框架学习

二、hibernate的作用?
在平时想要将对象存到数据库里:
连上数据库
创建sql语句
执行
通过JDBC操作

采用hibernate的写法,创建好对象后,跟hibernate打交道:
1)创建Student对象
2)Configuration类,访问配置,new它一个对象,调用buildSessionFactory()方法
3)创建SessionFactory对象,工厂类会生产东西,SessionFactory生产Session
4)调用SessionFactory的openSession()方法,返回一个Session对象
5)当你拿到Session对象之后,直接调用save(Student s)方法,存到数据库
6)sql语句就不用管了,使用面向对象的写法,不用写面向关系的sql语句
hibernate3框架学习
O/R Mapping:
O是Object面向对象,R是Relationship面向关系,hibernate帮我们屏蔽了Relationship关系这一层的逻辑处理
把Object映射成为Relationship相关的sql语句,把sql语句从数据库里拿出来之后再组装成一个对象

三、课程内容
1. HelloWorld
  a) xml
  b) annotation
2. hibernate原理模拟 - 什么是O/RMapping以及为什么要有O/RMapping
3. 常见的O/R框架(了解)
4. hibernate基础配置(重点)
5. ID生成策略(重点掌握AUTO)
6. hibernate核心接口介绍(重点)
7. 对象的三种状态,JPA的四种状态(了解)
8. 关系映射(重点)
9. hibernate查询(HQL)
10. 在struts基础上继续完善BBS2009
11. 性能优化
12. 补充话题

四、风格
1. 先脉络,后细节
2. 先操作,后原理
3. 重Annotation,轻xml配置
  旧系统用xml,新的都用annotation
    a)JPA的annotation(java persistence api - JAVA持久化的API)
    b)hibernate - extension

五、资源
1. http://www.hibernate.org
2. hibernate zh_CN文档
3. hibernate annotation references
4. slf4j日志框架
Simple Logging Facade for Java(SLF4J)
facade模式(门面模式):门面模式要求一个子系统的外部与其内部的通信必须通过一个统一的门面(Facade)对象进行
slf4j可以帮助你匹配到各种log实现上去

六、环境准备
1. 下载hibernate 3.6.10
2. 下载slf4j 1.6.1

七、hibernate helloworld
1. 建立新的java项目,名为:hibernate_0100_HelloWorld
2. 学习建立User-library-hibernate,并加入相应的jar包
  一般添加jar包的方式:项目右键-build path-add external archives
  对jar包进行分类:window-perferences选择Java-Build Path-User Libraries(User自定义的library)
  a)项目右键-build path-configure build path-add library
  b)选择User-library,在其中新建library,命名为hibernate
  c)在该library中加入hibernate所需jar包
    i. hibernate core
    ii. /required
      hibernate下的required里的slf4j-api-1.6.1.jar只是slf4j的api接口,并没有实现
      所以还要下载sjf4j-1.6.1.zip
    iii. slf-nop jar(使用slf4j-nop-1.6.1.jar)
3. 引入mysql的JDBC驱动包
  查看mysql版本
    [[email protected] ~]# mysql -V
    mysql  Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (i386) using readline 5.1
  下载mysql-connector-java-5.1.39.zip(使用mysql-connector-java-5.1.39-bin.jar)
4. 在mysql中建立对应的数据库以及表
  mysql -uroot -p565656
  a)create database hibernate;
  b)use hibernate;
  c)create table student(id int primary key, name varchar(20), age int);
5. 建立hibernate配置文件hibernate.cfg.xml
  a)从参考文档中copy
    hibernate配置文件放在classpath即src目录下
  b)修改对应的数据库连接
  c)注释掉暂时用不上的内容
6. 建立Student类
7. 建立Student映射文件Student.hbm.xml
  hbm:hibernate mapping的缩写
  放在model类的同一级
  a)参考文档
8. 将映射文件加入到hibernate.cfg.xml
  a)参考文档
9. 写测试类Main,在Main中对Student对象进行直接的存储测试
   eclipse引入jar包快捷键:Ctrl+Shift+o/Ctrl+1
   hibernate3.6请再引入hibernate-jpa-2.0-api-1.0.1.Final.jar包
  a)参考文档
10. FAQ
  a)要调用new Configuration().configure().buildSessionFactory(),而不是省略
    configure,否则会出hibernate dialect must be set的异常
11. Note
  a)请务必建立自己动手查文档的能力
  b)重要的是:
    i. 要建立自己动手查一手文档的信心 要穿一手鞋,不要穿二手鞋
    ii. 还有建立自己动手查一手文档的习惯
    iii. 主动学习,放弃被动接受灌输的习惯

八、建立annotation版本的helloworld
1. 创建teacher表,
create table Teacher (id int primary key, name varchar(20), title varchar(20));
2. 创建teacher类
3. 在hibernate lib中加入annotation的jar包
  a)hibernate annotation jar(hibernate3.6.10已有)
  b)ejb3 persistence jar(hibernate3.6.10已有)
  c)hibernate common annotation jar(hibernate3.6.10已有)
  d)hibernate3.6.10,此版本已经包含了Hibernate Annotations 和 Hibernate EntityManager
4. 参考Annotation文档建立对应的注解
5. 在hibernate.cfg.xml中建立映射<mapping class=.../>
6. 参考文档进行测试
7. 加注解
  a)在teacher类上加上@Entity,entity是实体,表示它是一个实体类
    用eclipse提示快捷键,Alt + /

    它依赖的包是javax.persistence.Entity,没有依赖于hibernate,说明JPA是一个标准,hibernate是它的一个实现
  b)第二个加注解的是主键
    @id,主键加在get方法上面,或者加在属性上也可以
  c)hibernate.cfg.xml加入映射类的配置
    <mapping class="com.bjsxt.hibernate.model.Teacher" />
  d)如果报错MySQLSyntaxErrorException: Table 'hibernate.Teacher' doesn't exist
    MySQL建表时将teacher改成大写Teacher,因为没有用@Table标注指定表名

九、What is and Why O/R Mapping
1. JDBC操作数据库很繁琐
2. Sql语句编写并不是面向对象的
3. 可以在对象和关系之间建立关联来简化编程
4. O/R Mapping简化编程
5. O/R Mapping跨越数据库平台
6. Hibernate_0200_OR_Mapping_Simulation
7. FAQ:@不给提示
  Window - Preferences - Java - Editor - Content Assist
  里面的activation加上@符号

十、O/R Mapping Frameworks
测试驱动开发:先想好当你写完那些类之后,该对那些类怎样进行测试,这样你就明白了那些类里面是怎么实现的了
1. hibernate
2. toplink
3. jdo
4. ibatis
5. JPA
  a)意愿一统天下


十一、hibernate基础配置
1. 对应项目:hibernate_0300_BasicConfiguration
2. 介绍MySQL图形化客户端
  ems mysql manager
3. hibernate.cfg.xml:hbm2ddl.auto
  a)hbm2ddl.auto
    取值 validate | update | create | create-drop
    create:数据库如果没这张表,它会自动帮你创建
    update:如果增加了新的属性,会自动在表上加上
  b)先建表还是先建实体类
    实际中先建表,建表工具powerdesigner
4. 搭建日志环境并配置显示DDL语句
  a)slf4j是一个接口或标准,下面的都是它的实现
hibernate3框架学习
    在我们的lib里面:
    slf4j-api-1.6.1.jar对应的是它的接口,slf4j-nop-1.6.1.jar对应的是它的实现
    现在我想把实现换成log4j,下载log4j-1.2.17(原因见下面),在lib里移除slf4j-nop-1.6.1.jar,加入log4j-1.2.7.jar
  b)如何将slf4j的api和log4j的实现对应起来
    需要一个转换器,把slf4j的接口转换成log4j的接口
    在slf4j的包里有转换器slf4j-log4j12-1.6.1.jar,看名字就是slf4j和log4j 1.2之间做转换的jar包,所以下载log4j-1.2.17
    这个转换器jar包,是什么样的设计模式?
    适配器模式,adapter
  c)在src目录下建立log4j.properties文件
    运行原项目,就会看到有很多调试信息打印出来
5. 搭建JUnit环境
  a)建立一个User Library,名字叫MyJUnit,加入:junit-4.12.jar、hamcrest-core-1.3.jar
  b)项目右键 - new - source folder,建立一个源代码目录,名字叫test,专门放测试代码
  c)一个比较好的测试习惯,你要对哪个类进行测试,建的包就和这个类的包一样
  d)eclipse自动生成测试类
    点右键 - new - Junit Test Case
  e)JUnit3.8测试类要继承testCase,JUnit4不用
  f)单例,static语句块
    static静态语句块是在类加载完之后,其他还没有执行时,它就会执行了
  g)JUnit注解:
    @Test:标注它是一个测试方法
    @BeforeClass:标注在对象初始化之前,class落到内存之后,马上就执行的方法
  h)注解分好几种
    第一种,写给编译器看的javac,比如@Overwrite,是不是重写了方法
    第二种,写给运行环境看的java.exe,在运行的时候帮你做一些事情
    第三钟,写给容器看的?
6. hibernate.cfg.xml:show_sql
  会打印sql语句
7. hibernate.cfg.xml:format_sql
  会把sql语句format一下,显得更漂亮
8. 表名和类名不同,对表名进行配置
  a)Annotation:@Table标注指定类对应的表名,引入类是JPA标准的类
    @Table(name="Teacher")
  b)xml:自己查询
    <class name="Student" table="student">
9. 字段名和属性相同
  a)默认为@Basic
    Annotation默认都加映射,不写注解默认加了@Basic注解
    老美认为,有两样东西比死记硬背更重要,第一是查的能力,第二是综合运用的能力
  b)xml中不用写column
10. 字段名和属性名不同
  a)Annotation:@Column
    在get方法上加,@Column(name="_name")
  b)xml:自己查询
11. 不需要presistence的字段
  a)Annotation:@Transient(透明的)
  b)xml不写
12. 映射日期与时间类型,指定时间精度
  a)Annotation:@Temporal(时间精度)
    在注解里面如果有一个属性叫value,value可以不写,直接写后面的值

    @Temporal(TemporalType.DATE)
  b)xml:指定type
13. 映射枚举类型
  a)@Enumerated
    @Enumerated(EnumType.STRING) 按字符串保存
    @Enumerated(EnumType.ORDINAL) 按int类型保存
  b)xml:麻烦
14. 字段映射的位置(field或者get方法)
  a)best practice:保持field和get set方法的一致
    放在成员变量上也是可以的,放在get方法上也是可以的
    因为成员变量大多数是私有的,放在成员变量上破坏了Java的封装性,hibernate通过Java反射机制可以获得私有成员变量
15. @Lob
16. 课外:CLOB BLOB类型的数据存取
17. 课外:hibernate自定义数据类型
18. hibernate类型

十二、ID生成策略
1. 对应项目:hibernate_0400_ID
2. 注意:
  a)我们观察hibernate生成表的结构并不是为了将来就用它生成,(可能还有自己的
    扩展,比如index等),而是为了明白我们应该建立什么样的表和实体类映射

3. xml文件生成id
  a)generator
    <id name="id">
        <generator class="uuid"></generator>
    </id>
  b)常用四个:native identity sequence uuid
4. annotation生成id
  @Id
  @GeneratedValue
    是javax.persistence的GeneratedValue
   
GeneratedValue有下面4种取值方式:AUTO、IDENTITY、SEQUENCE、TABLE
    默认是AUTO
  a)自定义ID(Teacher1)
  b)AUTO(Teacher2)
    i. 默认:对MySQL,使用auto_increment
    ii. 对Oracle,使用hibernate_sequence(名称固定)
  c)IDENTITY(Teacher3)
    @GeneratedValue(strategy=GeneratedType.IDENTITY)
  d)SEQUENCE(Teacher4)
    i. @SequenceGenerator
  e)TABLE
    i. @TableGenerator
      用一张表来生成主键
      很少用,可以跨数据库平台,只有你自己写了API可以在所以数据库上部署的情况下
5. 联合主键
  在面向对象设计中,联合主键要单独的设计一个类做为主键类
  在主键类里要重写equals,重写hashCode,实现serializable接口
  a)xml:composite-id
    <composite-id name="pk" class="com.bjsxt.hibernate.StudentPK>
        <key-property name="id"></key-property>
        <key-property name="name"></key-property>
    </composite-id>
    i. 为什么要重写equals和hashCode
      重写equals:内存中,主键对象区分是否相同
      重写hashCode:如果对象被装在hash表里,用hashCode查找对象

      假如我们写了一个程序,要把一系列的student对象装到hash表里头去,这个时候需要
      计算student对象的hash码才能装到表里头去。我计算student主键对象的哈希码,如果
      两个主键对象计算出来哈希码相同,他们会被装在同一个位置上。假如将来我们要找对象
      先找到哈希码,再比较这个哈希码下面的一串对象哪个和我们的对象equals。

    ii. 为什么要实现serializable
      用于将对象写入虚拟内存中(硬盘)
  b)Annotation
    i. 将组件类(做为主键的类)注解为@Embeddable,并将组件的属性注解为@Id
      @Embeddable可以被嵌入的
    ii. 将组件的属性注解为@EmbeddedId
      @EmbeddedId表示是嵌入进来的一个组件作为主键
      组件就是一个类的一部分,就是一个组件,一个Component
    iii. @IdClass
      将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id

      以teacher类为例,分别在id和name上加上@id,在teacher类上加上@IdClass(TeacherPK.class)
      这样使用时就不用new主键类了,直接set属性名

      在annotation里面,如果只有一个属性是“value=”的话,可以省略value

    常用第2种和第3种,第1种注解起来比较麻烦