第二周
Tomcat运行原理
http://blog.csdn.net/pzxwhc/article/details/47129675 Tomcat执行流程
http://www.importnew.com/17124.html Tomcat server.xml配置示例
1、JavaWeb应用的概念
在Sun的Java Servlet规范中,对Java Web应用作了这样定义:“Java Web应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在各种供应商提供的实现Servlet规范的 Servlet容器 中运行。”
Servlet容器为JavaWeb应用提供运行时环境,它负责管理Servlet和JSP的生命周期,以及管理它们的共享数据。Servlet容器也称为JavaWeb应用容器,或者Servlet/JSP容器。
目前最流行的Servlet容器软件括:Tomcat,Resin,J2EE服务器(如Weblogic)中也提供了内置的Servlet容器。
2、Tomcat简介
Tomcat 是一个免费的开放源代码的 Servlet 容器,它是 Apache 软件基金会的一个顶级项目,由 Apache,Sun和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持,最新的 Servlet 和 JSP 规范总是能在 Tomcat 中的到体现。
3、Tomcat Server组件
Tomcat是一个基于组件的服务器,他的构建组件都是可以配置的,其中最外层的组件是Catalina Servlet容器,其他组件一定要按照一定的格式要求配置在这个顶层的容器中。
<Server> 顶层类元素,可包含多个service
<Service> 顶层类元素,可包含一个Engine和多个Connector
<Connector/> 链接类容器,代表通信接口
<Engine> 容器元素,为Service处理客户请求,含多个Host
<Host> 容器元素,为Host处理客户请求,含多个Context
<Context/> 容器元素,为Web应用处理客户请求
</Host>
</Engine>
</Service>
</Server>
1) Server
A Server element represents the entire Catalina servlet Container. (Singleton)单实例的。
2) Service
Service是一个集合。它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求。
3) Connector 表示客户端和service之间的连接
一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户。
TOMCAT有两个典型的Connector,一个直接侦听来自browser的http请求,一个侦听来自其它WebServer的请求。
Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求。
Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。
4) Engine 表示指定service中的请求处理机,接收和处理来自Connector的请求
Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名。当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理。Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理。
5) Host 表示一个虚拟主机
代表一个Virtual Host,虚拟主机,每个虚拟主机和某个网络域名Domain Name相匹配。每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context path
当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理。匹配的方法是“最长匹配”,所以一个path==""的Context将成为该Host的默认Context。所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。
6) Context 表示一个web应用程序
一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成。
4、Web.xml文件
一个Context对应于一个Web App,每个Web App是由一个或者多个servlet组成的。
当一个Web App被初始化的时候,它将用自己的ClassLoader对象载入“部署配置文件web.xml”中定义的每个servlet类。
它首先载入在$CATALINA_HOME/conf/web.xml中部署的servlet类
然后载入在自己的Web App根目录下的WEB-INF/web.xml中部署的servlet类
web.xml文件有两部分:servlet类定义和servlet映射定义
每个被载入的servlet类都有一个名字,且被填入该Context的映射表(mapping table)中,和某种URL PATTERN对应
当该Context获得请求时,将查询mapping table,找到被请求的servlet,并执行以获得请求回应
分析一下所有的Context共享的web.xml文件,在其中定义的servlet被所有的Web App载入。
5、处理HTTP请求过程
假设来自客户的请求为:
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
http://localhost:8080/wsota/wsota_index.jsp
1) 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
2) Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
3) Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host
4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
5) localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context
6) Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)
7) path="/wsota"的Context获得请求/wsota_index.jsp,在它的mapping table中寻找对应的servlet
8) Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
10)Context把执行完了之后的HttpServletResponse对象返回给Host
11)Host把HttpServletResponse对象返回给Engine
12)Engine把HttpServletResponse对象返回给Connector
13)Connector把HttpServletResponse对象返回给客户browser
6、tomcat部署一个java应用
建立一个符合web应用目录的程序结构MyWebContent。需要将类生成文件配置到WEB-INF的classes目录下。
将MyWebContent复制到E:\apache-tomcat-7.0.34-noinstall\webapps目录下,打开
http://localhost:8080/manager/html
打开
可以看到
WEB-INF目录下的classes和lib目录都可以存放Java的类文件,在Servlet容器运行时,Web应用程序的类加载器将首先加载classes目录下的,其次才是lib目录下的类。如果这两个目录下存在同名的类,起作用的将是classes目录下的类。
JdbcTemplate使用笔记
1、JdbcTemplate简介
- 为了使 JDBC 更加易于使用,Spring 在 JDBC API 上定义了一个抽象层,以此建立一个 JDBC 存取框架。
- 作为 Spring JDBC 框架的核心,JDBC 模板的设计目的是为不同类型的 JDBC 操作提供模板方法。 每个模板方法都能控制整个过程,并允许覆盖过程中的特定任务。通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低。
2、用sql更新数据库
例如:
3、批量更新数据库
例如:
4、查询单行记录
例如:
5、查询多行记录
例如:
6、单值查询
例如:
7、调用存储函数
第二种
8、调用存储过程
9、返回结果集
返回结果集,通过把游标作为一个out参数来返回的。
Java调用
10、blob和clob处理
BLOB和CLOB都是大字段类型,BLOB是按二进制来存储的,而CLOB是可以直接存储文字的。其实两个是可以互换的的,或者可以直接用LOB字段代替这两个。但是为了更好的管理ORACLE数据库,通常像图片、文件、音乐等信息就用BLOB字段来存储,先将文件转为二进制再存储进去。而像文章或者是较长的文字,就用CLOB存储,这样对以后的查询更新存储等操作都提供很大的方便。
插入成功!
读取并且复制
Java规范学习笔记
1、Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
正例: "test".equals(object);
2、关于基本数据类型与包装数据类型的使用标准如下:
所有的 POJO 类属性必须使用包装数据类型。
RPC 方法的返回值和参数必须使用包装数据类型。
所有的局部变量推荐使用基本数据类型。
3、在集合迭代过程中,不能直接调用集合的add,remove方法,会报java.util.ConcurrentModificationException异常。应该使用迭代器的移除方法。
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
// Iterator<String> iterator = list.iterator();
// while(iterator.hasNext()){
// if(iterator.next().equals("a")){
// iterator.remove();
// }
// }
for(String s : list){
if(s.equals("a")){
list.add("bbb");
}
}//java.util.ConcurrentModificationException
4、高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。
5、并发修改同一记录时,避免更新丢失,要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。
> 说明: 如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次。
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
6、如果使用要 if-else if-else 方式表达逻辑,【强制】请勿超过 3 层,超过请使用状态设计模式。
http://blog.csdn.net/hguisu/article/details/7557252 状态设计模式
7、避免用 Apache Beanutils 进行属性的 copy。
> 说明: Apache BeanUtils 性能较差,可以使用其他方案比如 Spring BeanUtils, CglibBeanCopier。
8、后台输送给页面的变量必须加$!{var}——中间的感叹号。
> 说明: 如果 var=null 或者不存在,那么${var}会直接显示在页面上。
Maven学习笔记
1、目前所存在的问题
1.一个项目就是一个工程。项目非常庞大,用package不适合划分。最好是一个模块对应一个工程。
可以利用maven将一个项目拆分成多个工程。
2.项目里面的jar包都是手动复制和添加。这样,同一个jar包会出现在多个项目中。
3.jar包需要自己下载。Jar包依赖关系。
2、Maven概述
一款服务于java平台的自动化构建工具。Make、Ant、Maven、Gradle
运行时环境:就是一组jar包的引用。并没有正真放入工作目录。
编译------------部署------------搭建
构建过程的各个环节
1.清理,将以前的字节码class文件删除
2.编译,将java源程序编译成class文件
3.测试,自动测试,调用junit程序
4.报告,测试结果
5.打包,web工程打war包,java工程打jar包
6.安装,将打包文件复制到仓库的指定位置
7.部署,将web动态工程生成的war包复制到severvlet容器的指定目录下。
原工程与编译结果对比图
3、Maven核心概念
1.约定的目录结构
2.POM,项目对象模型
3.坐标,利用三个向量,在仓库中定义一个Maven工程
GroupId: 公司或组织域名倒序+项目名
ArtifactId:模块名,比如Hello
Version:版本,比如1.1.0,release可分离的稳定版,snapshot快照版迭代快
4.依赖,
Maven解析依赖信息时,会到本地仓库中查找被依赖的jar包。
对于自己开发的maven工程,使用install命令来安装,就可以进入仓库。
依赖范围:<scope>compile</scope>
Compile 对主程序是否有效,对测试程序是否有效,是否参与打包。
Test
Provided
5.仓库,本地仓库和远程仓库。
6.声明周期/插件/目标
7.继承
8.聚合
4、Maven工程目录结构
①目录结构
Hello 工程名
|---src 源码
|---|---main 主程序
|---|---|---java 源码
|---|---|---resources 框架和其他配置文件
|---|---test 存放测试程序
|---|---|---java
|---|---|---resources
|---pom.xml Maven核心配置文件
②POM文件内容
Project Object Model项目对象模型
Document Object Model 文档对象模型DOM
import static junit.framework.Assert.*; 静态导入。类里所有的静态资源可以直接用了。
assertEquals(“….”,results);断言结果与给定字符串一致。
5、Maven常用命令
执行与构建(编译、测试、打包)过程相关的命令,必须进入pom.xml文件所在目录。
1. mvn clean: 清理
2. mvn compile: 编译
3. mvn test-compile: 编译测试程序
4. mvn test: 执行测试程序
5. mvn package: 打包
6. mvn install: 将本地jar包安装到本地仓库中
7. mvn site: 生成站点
先找本地仓库,没有相关jar包,就联网下载。
6、Maven生命周期
各个构建环境执行的顺序,顺序执行。
定义了抽象声明周期,具体由插件完成。
自动化构建的特点,不论要执行生命周期的哪一个阶段,都是从生命周期最初的位置开始执行。
可以将目标看做调用功能的命令。
7、jar包依赖
各个构的环境执行的顺序,顺序执行。
排除jar包
依赖原则:路径最短优先。路径相同时,先声明优先。
传递依赖,非compile范围内的不能传递依赖。
引用版本号:方便更改。
聚合:由于有继承后,需要先安装父工程。聚合的作用就是一键安装各个参与聚合的模块。
比如:在Parent模块中配置如下,
8、部署到服务器上
方法1(手动):
可以将web引用,package先打包成war包。将war包复制到Tomcat安装的webapps目录下。
方法2(自动):
配置build标签后,最好用cmd来运行deploy命令,否则需要手动关闭Tomcat。
9、下载源码和javadoc
方法1:命令
命令使用方法:首先进入到相应的pom.xml目录中,然后执行以下命令:
mvn dependency:sources
mvn dependency:resolve -Dclassifier=javadoc
第一个命令是尝试下载在pom.xml中依赖的文件的源代码。
第二个命令是尝试下载对应的javadocs
但是有可能一些文件没有源代码或者javadocs
方法2:配置文件
打开maven配置文件 setting.xml文件(.../.m2/settings.xml) 增加如下配置:
- <profiles>
- <profile>
- <id>downloadSources</id>
- <properties>
- <downloadSources>true</downloadSources>
- <downloadJavadocs>true</downloadJavadocs>
- </properties>
- </profile>
- </profiles>
- 10.
11. <activeProfiles>
- 12. <activeProfile>downloadSources</activeProfile>
13. </activeProfiles>
方法3:配置myeclipse 推荐使用
10、jar包查找总站
Hibernate学习笔记
1、hibernate简介
ORM:Object Relation Mapping 对象/关系映射
ORM 主要解决对象-关系的映射
ORM的思想:将关系数据库中表中的记录映射成为对象,以对象的形式展现,程序员可以把对数据库的操作转化为对对象的操作。
ORM 采用元数据来描述对象-关系映射细节,元数据通常采用 XML 格式, 并且存放在专门的对象-关系映射文件中。(描述类、对象、属性和表的行列对应关系)
元数据:描述数据的数据。
对象关系映射文件***.hbm.xml
2、hibernate开发步骤
1)hibernate配置文件hibernate.cfg.xml
2)创建对象-关系映射文件*.hbm.xml
编写持久化类: POJO + 映射文件
获取 Configuration 对象
获取 SessionFactory 对象
获取 Session,打开事务
用面向对象的方式操作数据库
关闭事务,关闭 Session
3)Configuration 类负责管理 Hibernate 的配置信息。包括如下内容:
配置1:Hibernate 运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等(对应 hibernate.cfg.xml 文件)。
配置2:持久化类与数据表的映射关系(*.hbm.xml 文件)
4)SessionFactory针对单个数据库映射关系经过编译后的内存镜像,是线程安全的。 SessionFactory 对象一旦构造完毕,即被赋予特定的配置信息。SessionFactory是生成Session的工厂。构造 SessionFactory 很消耗资源,一般情况下一个应用中只初始化一个 SessionFactory 对象。
5)Session 是应用程序与数据库之间交互操作的一个单线程对象,是 Hibernate 运作的中心,所有持久化对象必须在 session 的管理下才可以进行持久化操作。此对象的生命周期很短。Session 对象有一个一级缓存,显式执行 flush 之前,所有的持久层操作的数据都缓存在 session 对象处。相当于 JDBC 中的 Connection。
取得持久化对象的方法: get() load()
持久化对象都得保存,更新和删除:save(),update(),saveOrUpdate(),delete()
开启事务: beginTransaction().
管理 Session 的方法:isOpen(),flush(), clear(), evict(), close()等
注意红色部分,是以斜杠隔断。
3、Session 概述
Session 接口是 Hibernate 向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存,更新, 删除和加载 Java 对象的方法.
Session 具有一个缓存,位于缓存中的对象称为持久化对象,它和数据库中的相关记录对应。Session 能够在某些时间点,按照缓存中对象的变化来执行相关的 SQL 语句,来同步更新数据库,这一过程被称为刷新缓存(flush)。
站在持久化的角度,Hibernate 把对象分为 4 种状态:临时状态,持久化状态,游离状态,删除状态。 Session 的特定方法能使对象从一个状态转换到另一个状态。
4、Session缓存
在 Session 接口的实现中包含一系列的 Java 集合,这些 Java 集合构成了 Session 缓存。只要 Session 实例没有结束生命周期,且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期。
Session 缓存可减少 Hibernate 应用程序访问数据库的频率。
Flush使得数据表中的记录和session缓存中的状态保持一致,可能会发送对应的SQL语句。
在Transaction的commit()方法中先调用flush方法,再commit。
Flush()方法可能会发送sql语句,但是不会提交事务,也就是数据表的记录不会改变。
3. 注意: 在未提交事务或显式的调用 session.flush() 方法之前,也有可能会进行 flush() 操作。
* 1). 执行 HQL 或 QBC 查询,会先进行 flush() 操作,以得到数据表的最新的记录
* 2). 若记录的 ID 是由底层数据库使用自增的方式生成的,则在调用 save() 方法时,就会立即发送 INSERT 语句。
* 因为 save 方法后,必须保证对象的 ID 是存在的!
Refresh会强制发送 SELECT 语句,以使 Session 缓存中对象的状态和数据表中对应的记录保持一致!
5、持久化对象的状态
站在持久化的角度,Hibernate 把对象分为 4 种状态:Transient,Persist,Detached,Removed。Session 的特定方法能使对象从一个状态转换到另一个状态。
临时对象(Transient):
在使用代理主键的情况下,OID 通常为 null
不处于 Session 的缓存中
在数据库中没有对应的记录
持久化对象(也叫”托管”)(Persist):
OID 不为 null
位于 Session 缓存中
对应性:若在数据库中已经有和其对应的记录,持久化对象和数据库中的相关记录对应
同步性:Session 在 flush 缓存时,会根据持久化对象的属性变化,来同步更新数据库
唯一性:在同一个 Session 实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象。如果一个session的数据库记录有两个对象,那么以哪个更新呢?所以是只有一个。
游离对象(也叫”脱管”) (Detached):类似于公司中员工请假了,不受公司管理,但是还属于公司
OID 不为 null
不再处于 Session 缓存中
一般情况需下,游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录
删除对象(Removed)
在数据库中没有和其 OID 对应的记录
不再处于 Session 缓存中
一般情况下,应用程序不该再使用被删除的对象
1. save() 方法
* 1). 使一个临时对象变为持久化对象
* 2). 为对象分配 ID.
* 3). 在 flush 缓存时会发送一条 INSERT 语句.
* 4). 在 save 方法之前的 id 是无效的
* 5). 持久化对象的 ID 是不能被修改的!
2. persist(): 也会执行 INSERT 操作
* 和 save() 的区别 :
* 在调用 persist 方法之前,若对象已经有 id 了,则不会执行 INSERT,而抛出异常
3. get VS load:
* 1. 执行 get 方法:会立即加载对象
* 执行 load 方法:若不使用该对象,则不会立即执行查询操作,而返回一个代理对象
* get 是 立即检索,load 是延迟检索
* 2. load 方法可能会抛出 LazyInitializationException 异常:在需要初始化
* 代理对象之前已经关闭了 Session
* 3. 若数据表中没有对应的记录,Session 也没有被关闭
* get 返回 null
* load 若不使用该对象的任何属性,没问题。若需要初始化了,抛出异常
4. update:
* 1. 若更新一个持久化对象,不需要显示的调用 update 方法。因为在调用 Transaction的 commit() 方法时,会先执行 session 的 flush 方法
* 2. 更新一个游离对象,需要显式的调用 session 的 update 方法。可以把一个游离对象变为持久化对象
* 需要注意的:
* 1. 无论要更新的游离对象和数据表的记录是否一致,都会发送 UPDATE 语句
* 如何能让 update 方法不再盲目的出发 update 语句呢 ? 在 .hbm.xml 文件的 class 节点设置
* select-before-update=true (默认为 false)。但通常不需要设置该属性
* 2. 若数据表中没有对应的记录,但还调用了 update 方法,会抛出异常
* 3. 当 update() 方法关联一个游离对象时
* 如果在 Session 的缓存中已经存在相同 OID 的持久化对象,会抛出异常。因为在 Session 缓存中
* 不能有两个 OID 相同的对象!
5. saveOrUpdate:同时包含了save和update方法
6.delete: 执行删除操作。只要 OID 和数据表中一条记录对应,就会准备执行 delete 操作
* 若 OID 在数据表中没有对应的记录,则抛出异常
* 可以通过设置 hibernate 配置文件 hibernate.use_identifier_rollback 为 true
* 使删除对象后,把其 OID 置为 null
可以在删除方法调用后,将OID立即置为null
7.evict: 从 session 缓存中把指定的持久化对象移除
6、调用存储过程
Work 接口: 直接通过 JDBC API 来访问数据库的操作。
Session 的 doWork(Work) 方法用于执行 Work 对象指定的操作,即调用 Work 对象的 execute() 方法。Session 会把当前使用的数据库连接传递给 execute() 方法
7、触发器协同工作
Hibernate 与数据库中的触发器协同工作时,会造成两类问题:
1)触发器使 Session 的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中,它执行的操作对 Session 是透明的。
即,session操作导致触发器更改了数据库内容,需要同步,要立即调用flush和refresh方法
2)Session 的 update() 方法盲目地激发触发器:无论游离对象的属性是否发生变化,都会执行 update 语句,而 update 语句会激发数据库中相应的触发器。
因此,需要在映射文件的<class>元素中设置select-before-update属性:当 Session 的 update 或 saveOrUpdate() 方法更新一个游离对象时,会先执行 Select 语句,获得当前游离对象在数据库中的最新数据,只有在不一致的情况下才会执行 update 语句。
8、hbm.xml文件
hibernate-mapping.xml
类层次:class
主键:id
基本类型:property
实体引用类: many-to-one | one-to-one
集合:set | list | map | array
one-to-many
many-to-many
子类:subclass | joined-subclass
其它:component | any 等
查询语句:query(用来放置查询语句,便于对数据库查询的统一管理和优化)
每个Hibernate-mapping中可以同时定义多个类。但更推荐为每个类都创建一个单独的映射文件
1)class标签中,dynamic-update:若设置为 true,表示当更新一个对象时,会动态生成 update 语句,update 语句中仅包含所有取值需要更新的字段。默认值为 false。
2)类型映射
9、时间类型的映射
在 Java 中,代表时间和日期的类型包括: java.util.Date 和 java.util.Calendar. 此外,在 JDBC API 中还提供了 3 个扩展了 java.util.Date 类的子类: java.sql.Date,java.sql.Time 和 java.sql.Timestamp,这三个类分别和标准 SQL 类型中的 DATE,TIME 和 TIMESTAMP 类型对应。
所以在持久化类中,应设置为java.util.Date类型,这样就可以接收数据库所有类型。
如何映射:type设置为date、time、timestamp三类Hibernate类型
10、blob类型的映射
在 Java 中, java.lang.String 可用于表示长字符串(长度超过 255),字节数组 byte[] 可用于存放图片或文件的二进制数据。此外,在 JDBC API 中还提供了 java.sql.Clob 和 java.sql.Blob 类型,它们分别和标准 SQL 中的 CLOB 和 BLOB 类型对应。CLOB 表示字符串大对象(Character Large Object),BLOB表示二进制对象(Binary Large Object)。
11、组成关系映射
问题来源:建立域模型和关系数据模型有着不同的出发点:
域模型:由程序代码组成,通过细化持久化类的粒度可提高代码的可重用性,简化编程。
类,越多越细化越好
在没有数据冗余的情况下,应该尽可能减少表的数目,简化表之间的参照关系,以便提高数据的访问速度。
数据表,越少越好
Hibernate 把持久化类的属性分为两种:
值(value)类型:没有 OID,不能被单独持久化,生命周期依赖于所属的持久化类的对象的生命周期
实体(entity)类型:有 OID,可以被单独持久化,有独立的生命周期
显然无法直接用 property 映射 pay 属性
Hibernate 使用 <component> 元素来映射组成关系,该元素表名 pay 属性是 Worker 类一个组成部分,在 Hibernate 中称之为组件。
12、一对多关联关系
在领域模型中,类与类之间最普遍的关系就是关联关系。
在 UML 中,关联是有方向的。以 Customer 和 Order 为例: 一个用户能发出多个订单,而一个订单只能属于一个客户。从 Order 到 Customer 的关联是多对一关联;而从 Customer 到 Order 是一对多关联。
单向关联
n-1:order里面有一个对customer的引用
1-n:customer中有order的集合的引用
双向关联
1)单向n-1
单向 n-1 关联只需从 n 的一端可以访问 1 的一端。
域模型:从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性,而在 Customer 类中无需定义存放 Order 对象的集合属性。
关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
在order.hbm.xml中配置
Session.save()保存的时候需要先保存一customer的一端。
查询多的一端order的时候,进行了延迟加载,没有查出一的customer一端。若先关闭了session再使用customer会报懒加载异常LazyInitalizationException。
在不设定级联关系下,删除一的customer一端会报错。
2)双向n-1
双向 1-n 与 双向 n-1 是完全相同的两种情形
双向 1-n 需要在 1 的一端可以访问 n 的一端,反之依然.
域模型:从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性,而在 Customer 类中需定义存放 Order 对象的集合属性。
关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键。和上面的数据表设计一样。
在java,Customer类中这样设置:
在Customer.hbm.xml中这样配置:
3)1-1
1对1关联关系,利用了多对一关联关系来建立。域模型:一个部门只能有一个领导,一个领导也只能管理一个部门。
关系数据库模型,有两种:
一、按照外键映射,利用多对一,但是多的那一端需要加上unique关键字。即在配置many-to-one那一端会有一个外键生成。
配置如下:
Department.hbm.xml
Manager.hbm.xml,注意需要property-ref属性指定出了所关联实体主键以外的关联字段!!!左外连接
二、按照主键映射
基于主键的映射策略:指一端的主键生成器使用 foreign 策略,表明根据”对方”的主键来生成自己的主键,自己并不能独立生成主键。 <param> 子元素指定使用当前持久化类的哪个属性作为 “对方”。
Department.hbm.xml中配置。注意是当前持久化类的哪一个属性作为主键配置!!!
在Manager.hbm.xml中配置
3)单向多对多
域模型:商品,列表。一个商品可以属于多个列表类,一个列表类也可以有多个商品。
关系数据模型:
在Category.hbm.xml中配置
在Item.hbm.xml中配置
13、继承关系映射
子类和父类公用一张数据表。父类中没有的字段值为空。有一列为TYPE辨别者列,作为类型区分。
对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念。Hibernate 的继承映射可以理解持久化类之间的继承关系。例如:人和学生之间的关系。学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到。
1)使用 subclass 进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。
只用配置父类Person.hbm.xml文件
2)使用 joined-subclass 进行映射: 对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
3)使用 union-subclass 进行映射:域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。
14、hibernate检索方式
导航对象图检索方式:根据已经加载的对象导航到其他对象。比如,customer得到order
OID 检索方式:按照对象的 OID 来检索对象,get,lod
HQL 检索方式:使用面向对象的 HQL 查询语言
QBC 检索方式:使用 QBC(Query By Criteria) API 来检索对象。这种 API 封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口。
本地 SQL 检索方式:使用本地数据库的 SQL 查询语句。
1)HQL
HQL(Hibernate Query Language) 是面向对象的查询语言,它和 SQL 查询语言有些相似。在 Hibernate 提供的各种检索方式中,HQL 是使用最广的一种检索方式。它有如下功能:
在查询语句中设定各种查询条件
支持投影查询,即仅检索出对象的部分属性
支持分页查询
支持连接查询
支持分组查询,允许使用 HAVING 和 GROUP BY 关键字
提供内置聚集函数,如 sum(),min() 和 max()
支持子查询
支持动态绑定参数
能够调用 用户定义的 SQL 函数或标准的 SQL 函数
2)QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这种 API 封装了 SQL 语句的动态拼装,对查询提供了更加面向对象的功能接口
3)本地SQL查询来完善HQL不能涵盖所有的查询特性