Java后端之二

本文是主要介绍了Struts、Spring、Hibernate框架

struts2

复习

struts有2大核心:

  1. 从前端到后端:也就是浏览器提交url,服务器根据url找到action,调用struts的对应的处理逻辑,然后返回result界面
  2. 从后端到前端:也就是前端JSP访问后端的数据,包括OGNL,Tags等,然后进行展示

重点技术是struts的拦截器,通过责任链来完成拦截器的一次调用

相关配置与helloWorld

struts流程

浏览器 - tomcat读取web.xml - 转发给StrutsPrepareAndExecuteFilter来处理 - 读取struts.xml - namespace - action - result -将请求转发给d对应的jsp

struts本质

通过这种方式来完成显示与控制的分离。

与servlet进行对比

servlet中用web.xml的方式进行配置,配置过程中,通过servlet与servlet-mapping标签,浏览器输入的url指引到对应的HttpServlet派生类中。在此类中,路线一定,service-->doGet()/doPost()等进行固定的处理。处理的返回,也是通过请求转发或重定向,将显示界面返回给浏览器。

而在struts中,在struts.xml进行配置,更加灵活。它通过action的配置,可以将url请求,指引到相应类的相应函数中去,并且可以通过result标签,根据处理返回的结果,去做不同的显示配置。

配置

  • 如何加载jar包的代码
  • 如何加载到哦从文档
  • 如何增加语法提示
  • 开发者模式自动发布
  • web应用的根目录与访问
    http://localhost:80/web应用名/

action

namesapce

  • namespace为空,可认为是一种default

路径

struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径,使用jsp中request.getContextRoot方式来拿到webapp的路径,或者用标签来确定路径

DMI:动态方法调用

  • 静态:可以在struts.xml中定义method字段来确定class调用的方法
  • 动态:在调用的输入中确定调用的方法。
  • action可以看作与.jsp.xml类似的东西:可以通过url访问,也可以通过<a href="">来指向,然后action指向对应的class来处理,通过返回值来指向其他的.jsp做显示。
  • namespace/action!method

通配符

  • 使用通配符可以将配置量降低到最低。
  • 约定大于配置:约定好Action名与method名,在配置时使用*与“{1}”,"{2}"等来调用方法与result中的jsp文件即可。
<action name="*_*" class="come.bjsxt.struts2.action.{1}Action" method="{2}">
    <result>/{1}_{2}_success.jsp<result>
</action>
  • 若有多个可以匹配,匹配最精确的那个。多个×号时,看前后顺序。

action传参:IOC概念,由容器调用传参

  • 自动传递
    webapproot/namespace/aciton!method?parameter1="1"&parameter2="2"
    在action的class类中,确定几个参数,并且做好set、get方法,struts2直接调用方法。
  • domainMode 就是model,最常用尤其是DT方式
    webapproot/namespace/aciton!method?user.name="aa"&user.age="22"
    就是类来传参,直接把类传进去。
    不匹配问题:传参与域模型不匹配不能直接调用:方案vo(value object),dto(data transfer object),用DTO对象来匹配输入,然后再有DTO对象生成域模型
  • ModelDriven 模型驱动,不常用
    将action实现implements ModelDrive接口,
    通过getModel返回User模型。

CharactorEncoding:接收参数中有中文处理

  • 有中文页面一般有post
  • <constant name="struts.i18n.encoding" value="GBK">,BUG情况下无实现
    org.apche.struts2中的default.properties中
  • web.xml中使用<filter-class>org.apache.struts2.dispathcer.FilterDispatcher</filter-class>用struts2.0

简单数据校验:后台到前台的数据传递,只不过是常用的error

在action的方法中,对参数进行校验,主要问题是,登录不成功如何向前台传递信息?
this.addFieldError("name", "name is Error!");
return ERROR;

在jsp中通过struts2标签来实现读取:
<%@taglib uri="/struts-tags" prefix="s" %>:tld文件在META-INFO中
<s:fielderror fieldName="name" theme="simple"> theme展现标签

<s:property value="errors.name[0]">:取valueStack中的属性:map, key-value,value是个数组
<s:debug></s:debug>

访问web元素:后台到前台数据的传递,servlet中的重要对象

第一种方式:依赖于容器

Map request ssesion application

  • 存.java
    request = (Map)ActionContext.getContext().get("request");
    session = ActionContext.getContext.getSession()
    application = ActionConetxt.getContext.getApplication()
    request.put("r1","r1");
    session.put("s1","s1");
    application.put("a1","a1")
  • 取.jsp
  <s:property value="#request.r1"/> | <%=request.getAttribute("r1")%>
  标签方式与JSP方式
  <s:property value="#attr.r1" /> 这个搜request,session,application

第二种方式:IoC,最常用

RequestAware,SessionAware,ApplicaionAware

@Override
setRequest(Map<String,Object> request){
this.request = request;
}

IoC(inverse of control)~DI(dependency injection);
通过反射,拿到是否有实现相应接口,然后Struts2调用相应的set*代码,将request、session、application等对象set进来。
request等属性依赖于注入(DI)。
spring中将IoC发扬光大。

第三种方式:直接拿HttpServletRequest

private HttpServletRequest request;
request = ServletAcitonContext.getRequest();
session = request.getSession();
application = session.getServletContext();

范围从小到大的获取变量。

  • 练习:
    通过使用javascript:document.f.aciton='login/login1';document.f.submit();制定不同的action

第四种方式:依赖注入

implements ServletRequestAware{
@Override
public void setServletRequest(HttpServletRequest request)
}

总结:

取得Map类型request,session,application
真实类型HttpServletRequest

包含文档

struts.xml中
<include file="login.xml" />
分模块开发,公用放在struts.xml中,各自的用包含。

Default Action

在package中,
<default-action-ref name="index"></>
默认访问主页。

学习

实例程序;helloWorld;查文档<doc,api>;一个个小程序来学知识点

问题

  1. 多重实现接口的编写
  2. 传参,在表单提交时,如何控制参数user.name=""&user.password=""
    在表单的name中写user.name
  3. 传参,没有匹配的函数
    原因通过setUser与getUser提交参数,而具体调用的函数中,没有参数。
  4. 是否可以web元素(session,ruquest,application)等,在页面中动态去显示数据。
    个人认为不行,页面处理了逻辑,不符合MVC的思想。

小项目总结

  • 功能
    登录与注册功能,当admin用户登录时,可直接登录。其他用户需要先注册,否则显示登录失败。
  • 知识点
    1. 在同一表单中,如何提交2种不同的action。用Javascript的函数实现。
    2. 前后台数据的传输,在本例中使用的是session,在处理结果与处理后界面做数据的传递。这里需要注意session的获取方式,使用Ioc控制反转的方式,由struts注入。
    3. 遇见bug
      • 对应不上,由于前一天在struts.xml的namespace处测试加了/action,造成浏览器端的输入与aciton的url不匹配。
      • string == 时出现问题,用equal函数问题解决。
    4. 后续拓展
      可以将注册的数据写入数据库,从数据库中读取数据进行对别。需要Data层来做这些封装。

Result

type:result本身就是一种跳转

  • dipatcher(服务器请求转发)服务器跳转
    必须是页面,视图,xml,.jsp
    <result type="dispatcher">/r1.jsp</result>

  • redirect(重定向)客户端跳转
    必须是页面,视图

  • chain
    forword,请求转发?服务器跳转
    访问的是action,同一个包或者不同包都可以

 <result type="chain">r1</result>
 <result type="chain">
   <param name="actionName">123</param>
   <param name="namespace">/secure</param>
 </result>
  • redirectAction:客户端跳转
    跳转到另外一个Action

global-result

<package>
<global-result>
 <result name="mainpage">/main.jsp</result>
</global-result>
</package>
<packet name="admin" namespace="/admin" extends="user">

从另外一个包中继承,继承主要是1层最好,太多的继承会影响灵活性。

dynamic-result:用处并不多?

在action的的class中,${r},action的属性都会放在值栈中,在result中,通过$取值栈中的数据。
用属性表示结果。
感觉与通配符效果有些重合。

向结果传参数

其实还是action值栈,一次request只有一个值栈。值栈是基于request的。
forward()的请求是共享值栈的

客户端挑战时,需要传参

from ValueStack<s:property value="t" >
from actioncontext:<s:proterty value="#parameters.t">

总结

值栈与上下文
其实strtus就是不停的用action处理,用jsp等去显示,不停的用不同的result来做不同的现实,基于的是一种人机操作的对话形式的系统。

OGNL&ValueStack

OGNL - object gragh navigation language:对象图导航语言

直接访问属性

<s:property value="username" />,指的是value里边的值,其实就是显示方面的东西了。访问的是值栈。

访问值栈中对象的属性(需要set get,与domain相同)

只有先传参后,才能帮忙构造相应的对象,然后再在jsp中去调用显示。手动new也可以,但需要有默认构造方法。因为是通过调用set,get函数来往里传值,故构造时一定是通过默认构造函数来实现的实例化。

<s:property value="user.age" />

OGNL

<s:property value="cat.friend.name" />
cat对象中有一只名为friend的Dog的对象,此Dog对象中,有name属性。
也需要通过cat.friend.name=“”的输入。

访问值栈中对象的普通方法

<s:property value="password.length()">

访问action的普通方法

<s:property value="m()">

访问静态方法

<constant name="struts.ognl.allowStaticMethodAcess" value="true" />
<s:property value="@类名@方法名">
<s:property value="@@max()"> ,@@只访问Math类

访问静态属性

<s:property value="@类名@属性名">

【重点】访问集合

set,get属性
其实与访问属性类似,不过通过增加[]来访问某个元素,而通过{}来生成集合

<s:property value="users[1]" />
<s:property value="users.{age}">

将users集合中的元素的age属性生成一个集合。
map的访问"dogMap['key1']",dogMap.key1
map访问所有key,dogMap.keys
map访问所有value,dogMap.values
访问容器的大小dogMap.size();

【重点】投影(过滤)

  • ?:过滤条件
    <s:property value="users.{?#this.age=1}.{age}" />
    {}还是一个集合
  • ^:开头
    <s:property value="users.{^#this.age>1}.{age}">
    集合中第一个
  • $:结尾
    <s:property value="users.{$#this.age>1}.{age}">

[],值栈访问

<s:property value="[0]">,ognl栈里的action,服务器跳转情况下,会压入多个action

总结

服务端的数据(属性,对象)通过Get/Set方法注入到值栈中,
前端通过<s:property value="" />通过访问值栈中的对象。
可以通过include标签,将struts.xml分成几部分引用,更模块化一些。

Tags

通用标签

  • set标签:设置变量,换名用的比较多
    var,value,scope
<s:set var="adminPassword" value="password" scope="session" />
<s:property "#session.adminPassword" />

value是值栈中的value,scope是var变量所在的范围。
注意现有版本中的value为object,需要用''来转换为响应的字符串。

  • bean标签:生成对象
<s:bean name="com.bjsxt.Dog" var="myDog">
<s:param name="name" value="'oudy'"></s:param> //"name"为Dog类中的属性,param为Dog属性设置参数
</s:bean>

取值都是用#来取值。

  • include标签,少用:处理中文字符很难使。
    <s:include value="/_include.html">
    包含文件用JSP的静态包含或动态包含
    在include中使用变量
<s:set var="incPage" value="'/_include1.jsp'" />
<s:include value="%{#incPage}"></s:include>

%{}意思是不要当成String,而当成OGNL表达式。#incPage意思是取值。

  • $#%区别
    a. $用于struts2的配置文件,i18n文件中
    b. #用于取值ActionContext中的值
    c. %用于修改文本属性解析为OGNL表达式。

控制标签

  • if\elseif\else
    <s:if test="#parameter.age[0] <20">too young!</s:if>
    test:Expression to determine if body of tag is to be displayed

  • iterater

<s:iterater value="{'aaa','bbb','ccc'}" var="x">
  <s:property value="#x.toUpperCase()" />
</s:iterater>

< status="status">
status.first status.last status.odd status.even status.index

value"#{1:'a', 2:'b', 3:'c'}"
"key", "value" 
"var='x'" "#x,key"

UI标签

theme中form的的去除圆点
struts.xml中定义
<contant name="struts.ui.theme" value="simple" />

  1. 自己定义css的div来去除(覆盖struts原来的css)
  2. 覆盖单个文件
  3. 定义自己的theme
  4. 实战
    a. 把所用主题定义为theme
    b. fielderror特殊处理
    c. 自己控制其他标签的展示

总结

Tag是struts用于显示的部分,可以通过值栈,获取服务端传输的数据,可以进行控制,通用标签类似于变量声明,控制标签类似于控制语句、迭代器等。

声明式异常处理

实现

excute本身就会抛异常,在其中的处理代码中,也抛异常,但不进行catch。
在struts.xml中通过声明异常来处理。
<exception-mapping result="error" exception="java.sql.SQLException" />
并且可以放在

<package name="bbs2009_default" extends="struts-defalut">
  <global-results>
    <result name="error">/error.jsp</result>
  <global-results>
  <global-exception-mappings>
     <exception-mapping result...>
  </global-exception-mappings>
</package>

然后其他package从此package中继承即可。

原理

责任链chain of responsibility
使用拦截器实现
由拦截器拦截到异常,然后取相应的result,然后将excetpion入栈。

I18N原理

i18N原理

a) ResourceBuncle res = ResourceBundle.getBundle("app", local.CHINA);
res.getString("welcome.msg");
app_en_US.properties
app_zh_CN.proper
b) propertiesEditor
编辑用utf-8,无法用中文打开,需要用上述插件打开使用。
将相应的feature与plugin放到MyEclipse下即可。

struts的i18n

action级别

在action中,将proterties文件,命名为与action文件相同的文件名前部分。
properties: LoginAction_en_US.properties
action: LoginAction.java
_zh_CN
_en_US

在JSP中使用时
<s:propery value="getText('login.username')" />

package级别

app级别

拦截器源码解读【重点】

拦截器用责任链方式完成,在actionInvocation与conceptor中来回的调用,知道所有的拦截器完成。从总体上看,像是一个一个的拦截器依次调用。

Project

规定

  1. 库名:项目名

  2. 表名:Module与Table名相同:User与_User.

  3. 字段名:字段名与属性名相同。id与id.

  4. 包名:包的名字都要小写
    com.xxx.service;
    com.xxx.model;
    com.xxx.dto;
    com.xxx.action;
    用层来划分包。

  5. 文件名
    JSP:-
    如:user_add.jsp user_delete.jsp

  6. 实例类
    User Category, Article

  7. 配置文件名
    package "action"

开发顺序

  1. 创建界面原型
  2. 建立struts.xml
    a. 确定namespace
    b. 确定package
    c. 确定Action名字
    d. 确定result
    e. 将界面原型页面进行修改,匹配现有设置
    f. 测试
  3. 建立数据库
  4. 建立Model层
  5. 建立Service层
    a. 此时可以使用Juint进行单元测试
  6. 着手开发

类型转换

上传与下载

interceptor

防止重复提交

开发

概念

  • 板块、子版块
    属性包括:名称,子版块,帖子,一些统计信息:帖子数,最新文章,发帖人,时间,版主或者版主权限。
  • 帖子
    属性包括:主题,发帖人,内容,时间,所属板块,回复(回复可以看作也是帖子)。
    在这里不同的论坛可能有不同的处理,回复若有长短限制,则与帖子不是同一类的内容(如微信等),若没有限制(如天涯)则可认为是同一类的存储。
  • 用户;
    属性包括:用户名,密码,级别,(对板块与帖子)权限,发的帖子,关注的主题或者板块,
  • 关系
    说白了是用户发帖子,而板块是帖子的一种归纳组织方式。

设计

根据要求,只做最简单的板块管理。
板块管理在后台,增删改权限都在这里,这里修改后,需要在前台展示出相应的修改来。
其实这里可以增加最基础的用户,用户对板块的权限的内容。
现在难处是对现有的结构,不知道如何去增删改板块。

ACTION:模板CATEGORYACTION:增删改操作模板的ACTION
MODEL:CATEGORY类
DAO:创建与数据库相关的操作
SERVICE,在我看来就是ACTION

Hibernate

复习

Hibernate的知识点只有一个O/R Mapping
纵向看,操作包括CRUD,存、取、删、改。最多的就是存与删
横向看,包括对关系映射、集合映射、继承映射的CRUD

环境

  • 下载hibernate-distribute(core)3.3.2
  • 下载hibernate-annocation 3.4
  • 注意hibernate

课外话

ejb2,hibernate,ejb3,JPA,hibernate annocation
@不给提示,在window,property中的content assistant下

HelloWorld,框架

O/R Mapping

对象与关系数据库之间的映射

实现

Configuration cfg = new Configuration();
cfg.Configuration();
SessionFactory sf = cfg.buildSessionFactory();
Session s = sf.openSession();
s.beginTransation();
s.save(student);
s.getTransation().commit();
s.close();
sf.close();

O/R映射关系

  • xml
  • @的Entity

Hibernate原理模拟

常见的O/R框架

hibernate
toplink
jdo
JPA()=JDBC一种接口

hibernate基础配置

hbm2ddl.auto

create:能新建表
update:不能新建表,但能扩字段
create-drop:在现实关闭SessionFactory是,drop掉表
validate: 每次操作验证是否匹配

日志slf4j与log4j

  • slf4j-api-1.5.8.jar(接口)
  • slf4j-nop-1.5.8.jar(实现)
  • log4j1.2.15(log4j实现)
  • slf4j-log4j12-1.5.8.jar

show_sql与format_sql

Annotation

  • 类名与表名匹配
    @Table(name="表名")
  • 属性与字段匹配
    @Column(name="字段名")
  • 不参与持久化的属性
    @Transient
  • 日期类型
    @Temporal(TemporalType.Date)
  • 枚举
    @Enumerated(EnumType.Spring)

联合主键

联合主键有3种形式:

  1. pk类上写@@Embeddable,再引入类上@Id即可,pk类上要直线序列号接口,并且重写equals()与hashCode()函数
  2. 引入类上直接写@EmbeddedId
  3. 引入类上用@IdClass(TeacherPK.class),需要写联合主键属性,在主键上直接写@Id即可。

实践

  • 不好使的原因在于Student.cfg.xml写的不对,是联合主键的形式。
  • 还有一个是connection.pool_size满的,要去掉。

hibernate核心接口

session

  • getCurrentSession(), thread | jta
  • openSession()

对象的三种状态

  • transient:内存中刚new出来的对象,没有交给session来处理
  • pesistent:通过session的save方法,将对象交给了session来搭理,并且执行了commit使数据库中也存在着此对象
  • deptch:session关闭后,对象不再与session有关。

save增

delete删

直接调用,通过主键删除。

update改

  • 与对象的三种状态息息相关,从库里读出后,可以通过直接修改session中处理pesistent状态的对象,不同update,直接commit就可完成。
  • Query方式,通过CreateQuery("sql语句"),excuteQuery()对象来实现语句的直接使用,效率较上一个高。

saveOrUpdate

Session s = sf.openSession();
s.beginTransaction();
s.saveOrUpdate(t);
s.getTransaction().commit();

get与load查

  • get先从session缓存中找,找不到检索数据库,没有返回null
  • load先从session缓存中找,找不到如果是lazy,则创建代理对象,在对象使用时,才检索数据库。

clear

  • 清楚session中的对象,

flush

  • 将session中的对象,刷新到数据库。

拓展:hibernate的二级缓存机制

  • what
    what(Hibernate缓存原理是怎样的?)Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存。

1.Hibernate一级缓存又称为“Session的缓存”。
Session内置不能被卸载,Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事务)。
一级缓存中,持久化类的每个实例都具有唯一的OID。

2.Hibernate二级缓存又称为“SessionFactory的缓存”。
由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。
Hibernate提供了org.hibernate.cache.CacheProvider接口,它充当缓存插件与Hibernate之间的适配器。

3.Hibernate查找对象如何应用缓存?
当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;
查不到,如果配置了二级缓存,那么从二级缓存中查;
如果都查不到,再查询数据库,把结果按照ID放入到缓存删除、更新、增加数据的时候,同时更新缓存。

  • how
    1.一级缓存的管理:
    evit(Object obj) 将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象。
    clear() 将一级缓存中的所有持久化对象清除,释放其占用的内存资源。
    contains(Object obj) 判断指定的对象是否存在于一级缓存中。
    flush() 刷新一级缓存区的内容,使之与数据库数据保持同步。

2.一级缓存应用:
save()。当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中。 get()和load()。当session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。 使用HQL和QBC等从数据库中查询数据。

3.二级缓存的管理:
evict(Class arg0, Serializable arg1)将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源。
sessionFactory.evict(Customer.class, new Integer(1));
evict(Class arg0) 将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源。
sessionFactory.evict(Customer.class);
evictCollection(String arg0) 将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源。
sessionFactory.evictCollection("Customer.orders");

4.二级缓存的配置
常用的二级缓存插件
EHCache org.hibernate.cache.EhCacheProvider
OSCache org.hibernate.cache.OSCacheProvider
SwarmCahe org.hibernate.cache.SwarmCacheProvider
JBossCache org.hibernate.cache.TreeCacheProvider

关系映射

对象一对一

  • 单向
    @OneToOne(mappedBy="wife")

    @OneToOne
    @JoinColumn(name="")
    

    制定列名

  • 双向
    两个类之间都有各自的指向,然后通过制定mappedBy=""属性来指定表中谁用foreignKey
    @One2One(mappingBy)

  • 1对1单向主键

  • 1对1双向主键

联合主键

可以通过@JoinColums来制定联合主键的列名

组件映射componet

在组件上对象上,get函数前使用@Embedded标签,说明是组件即可。

多对一与一对多

  • 组与成员的关系:group与user
  • 在group中保存user的集合(set)此为一对多:@Many2One
  • 在user中保存group对象,此为多对一:@One2Many
  • 双向(两个都写时),需要在group中指定mappedBy="group",可以用这种方式去除hibernate自动的中间表关系,而改用外键方式。

多对多

  • 学生与老师的关系:teacher与student
  • 在老师中保存学生,而学生中不保存老师。@Many2Many。
  • 使用中间表的方式来建表。可以用@JoinTable(name="中间表名", joinColomns={@JoinColumn(name="中间表外键名1")}, inverseJoinColumns={@JoinColumn(name="中间表外键2")}),来制定中间表的表名、列名。

CRUD

  • 设定cascade可以在持久化对关联对象的操作(CUD,R归fetch管)
  • 双向关系在程序中要设定双向关联
  • 双向关系需要设置mappedBy
  • FetchType.Eager 与 FecheType.Lazy
    在设置读取时,One的一方默认是Lazy,指的是读取时不级联读取More的一方。而More的一方默认是Eager,指的是读取时默认级联读取One的一方。
    可以通过fetch=FetchType.Eager等来修改这种情况。

O/R Mapping编程模型

  • 映射模型

    • hibernate xml
    • jpa annotation
    • hibernate annotation extension
    • jpa xml(未果)
  • 编程接口

    • jpa
    • hibernate
  • 数据查询语言

    • HQL
    • EJBQL(JPQL)

集合映射

list

支持@OrdeBy(value="字段 DESC/ASC")以什么的方式排序

map

需要制定map的key值@MapKey(name="id"),此id的类型要与设定的Map的key值相同。

for(Map.Entry<Integer, User> entry : g.getUsers().entrySet()){
  System.out.println(entry.getValue().getName());
}

继承映射

  • Inheritance
    父类上写Inheritace(strategy=InheritanceType.JOINED)
    子类上不再需要写其他,即可完成映射。

singleTable

  • 通过字段区分父类、子类,可以通过相应的属性指定字段数值

Joined

  • 父类表包括父类的属性,子类的表只包括子类属性,子表与父表通过主键映射的关系来关联。
  • 可以通过@PrimaryKeyJoinColumn注解来自定子表的主键ID

Table per class

  • 父类与子类分开存储,字段不关联。

树映射

树映射,通过自身对自身的一对多,多对一来进行映射。
在One2Many与Many2One来进行关联。

Hibernate查询QL【查询时用的很多】

简介

native QL-->HQL-->EJQL-->QBC-->QBE
面向对象的查询语言

查询

  • from,list
Query q = s.createQuery("from Topic");
for(Object t : q.list()){
}
  • :占位,setParameter()
Query q = s.createQuery("from Topic t where t.id>? and t.id<?")
  .setParameter(0, 2).setParameter(1, 4);
  • native查询,Object[]
Query q = s.createQuery("select t.title,count(*) from Topic t group by t.title");
  
  for(Object o : q.list()){
    Object[] arr = (Object[])o;
  }
  • QBC
List<Topic> topics =(List<Topic>)s.createCriteria(Topic.class).list();
for(Topic t : topics){
  System.out.println(t.getId() + "--" + t.getTitle());
}

修改

删除

性能优化

内存泄漏

  • 在大集合中进行遍历,遍历msg,取出含有敏感字样的对象
  • 另外一种形式的内存泄漏://面试题,Java有内存泄漏吗
  • 注意使用seesion.clear(),尤其在不断分页循环的时候。

1+N问题

  • 关联的数据被拿出来
  • lazy
  • BatchSize(size=5)
  • left join fetch
    from Topic t left join fetch t.category

list和iterate不同

  • list取所有
  • iterate先去ID,等用到之后再向数据库查
  • iterate使用session级缓存

一级缓存,二级缓存,查询缓存

  • 以及session级
  • 二级sessionFactory,所有session
  • 查询缓存是两个查询语句相同时
  • 缓存算法:LRU(Least Recently Use),LFU(Least Freqently Used),FIFO(First In First Out)

事物并发

  • ACID特性

问题

  • dirty read脏读
    读了未提交的数据:lost update
  • non-repeatable read不可重复读
    两次读的数据不不同,被另一个事物修改并提交
  • phantom read幻读

隔离级别

  • read-uncommitted 1
    可以读取未提交的数据
  • read-commited 2
    不能读取未提交的数据
    不能解决non-repeatable read
  • repeatable read 4
    加读锁
  • serializable 8
    所有都串行

总结

spring

复习

spring核型就是Ioc与AOP
Ioc就是将所有对象都放在spring容器中去获取,
Aop就是面向切片的变成,用于声明式事务管理

MVC模型

model

dao-daoimpl

service

test:JUnit4

IOC

IOC控制反转(DI=Dependency Injection:依赖注入)

  • 交给容器来控制,

    • 把自己new的东西改为由容器提供
      初始化具体值
      装配
    • 用反射来完成
  • 将daoimpl的选择放在配置文件中
    配置文件为xml格式,用JDom来解析;
    然后通过反射的原理,生成DAO;
    同时,为完成对不同数据库的多态,使用工厂模式,将不同的DAO放在Factor中

  • 将对不同数据的Service,需要装载各自相应的数据,将这些service也放在配置文件中去执行
    其实,这是一种典型的工厂模型,只不过又增加了对service与DAO之间的解耦

  • IOC:Inverse Of Control
    service与DAO之间的关联交给了spring,只需通过配置来实现不同的切换,这在c++方面是没法实现的,而我觉得这一切都归功于Java的反射,所以这部分需要好好补一下。

  • DI:dependency Injection
    依赖注入,就是service的功能依赖于spring将dao注入到其中,它们之间是组合的关系,但这种关系不再需要我们手动的去实现,而是spring帮助我们去实现。

IOC的xml

  • 注入类型

    • setter
    • constructor
  • ID-Name

  • 简单类型注入

    • 在beans.xml中写入注入的参数
    • <constructor-arg />
  • 集合注入
    在beans.xml进行相关的配置

  • scope

    • beans的获取方式
    • singloton:单例
    • protoType:每次都获取新的
    • 一般默认使用singloton
  • lifeCircle

    • 在为singloton情况下制定init-method以及destroy-method
    • 会在构建与析构时候做一些处理。
  • autowire

    • "byType"自动装载所需要的bean
    • byName

IOC的annotation

  • xml配置
    需要增加

    xmlns:context="http://www.springframework.org/schema/context"
      http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
    <context:component-scan base-package="com.sun"/>
    

    至此就可以将其他的bean的配置删除,由spring去搜索base-package中的代码

  • @component,service,controllor,Repository
    在类上增加这些注解,spring会将他们增加到bean中
    @Component("userName")

  • @Resource
    在引用时,setter上使用@Resource即可
    @Resource(name="userName")

AOP

  • 面向切面编程。在以后类逻辑的基础上,通过动态代理横向给多个类注入新的逻辑,适合做一些权限检测,日志等功能。

实现

  • 代理:
    最常用的是与原类实现相同的接口,然后通过组合方式,将原类组合进代理类。在实现接口上,先实现代理逻辑,然后再调用组合的原类逻辑。从而实现代理。
    组合上也可以用继承来实现,但不如组合灵活。
  • 动态代理:可能在C/C++上,不太好实现。
    首先是将原来静态代理分成了2部分:1.InvocationHandler() 2.Proxy.newProxyInstance();
    InvocationHandler()方面主要是实现代理的组合功能,需要重写Invoke方法。
    Proxy.newProxyInstance()通过将被代理类的class、接口、对应的InvocationHandler,来自动生成动态代理类。

Annotation

  • 引入
    beans.xml中引入相应的xsd文件及aop:aspectj-autoproxy/
    Jar包引入aspectj的2个包
  • 使用
    具体就是在什么条件下,使用哪个类的,哪个方法。
    条件分为:advice-包括Before,After,Around等等;切入点语法"execution(public * (..))"类似
    哪个类:需要在切片类上写@Aspact。
    哪个方法:需要在切片类方法上写上条件即可。@Before("execution(public * com.bjsxt.service..
    .add(..))")

xml:切入点-什么时候切入;切入什么;

  • 同样是什么条件下,植入哪个类的哪个方法

    <bean id="logInterceptor" class="com.bjsxt.aop.LogInterceptor"></bean>
    <aop:config>
    <aop:aspect id="logAspect" ref="logInterceptor"> //类
      <aop:before method="before" pointcut="execution(public * com.bjsxt.service..*.add(..))" />  // 条件及方法
    </aop:aspect>
    </aop:config>
    

整合Hibernate

Datasource:引入JDBC

  • dataSouce其实就是将相应的Datasource作为bean被spring所管理,然后再使用时,通过IOC引入到具体的DAOImpl中去实现相应的数据库功能。

  • 具体使用dbcp的方式来使用

  • beans.xml中的具体配置

    <bean id="dataSource" 
          class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost/spring"/>
        <property name="username" value="root"/>
        <property name="password" value="sun12346"/>
    </bean>
    
  • 在使用时,通过@Resource(name="dataSource")引入Datasource

    try {
      Connection conn = datasource.getConnection();
      conn.createStatement().execute("insert into user values(null, 'Mr.Zhang')");
      conn.close();
    } catch (SQLException e){
      e.printStackTrace();
    }
    

Hibernate引入

  • Hibernate的引用其实是将Hibernate的sessionFactory作为bean被spring来管理,在使用时与Datasource的使用类似。

  • beans.xml配置上

    <bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    
      <property name="dataSource" ref="dataSource" />
      <property name="hibernateProperties">
        <value>
          hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
        </value>
      </property>
      <property name="annotatedClasses">
        <list>
          <value>com.sun.dao.UserDAOImpl</value>
        </list>
      </property>
    </bean>
    

原则就是配数据源、配方言、配O/R mapping,O/R mapping的配法比较多,可以指定相应的xml,可以直接写annotation的某个类,也可以通过PackageScan方法来制定包,自己搜索。

  • 使用时与Datasource相同

Annotation-Transcation

  • 事物的管理其实是基于AOP的arround的,就是在Service层相应的方法上加上事物,同时进行回滚与处理。
  • beans.xml配置
  • 使用@Transaction
  • 相关的属性
    • propagation
      propagation.REQUIRED, 默认情况下,被调用函数与调用函数使用同一个事物。
    • readOnly
      对于只读性的get方法,使用readOnly时效率更高。

xml-Transaction

  • 其实就是将Annotation-Transcation与切入点语法相关联

  • 本意就是在什么条件下,使用事物管理。这些事物管理可以配不同的类型,最常见的就是将get方法配为readOnly

  • 配置

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true"/>
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="add*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut id="serviceOperation" expression="execution(public * com.sun.service..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
    </aop:config>
    
  • 实体类包扫描配置

    <property name="packagesToScan">
    <list>
      <value>com.sun.model</value>
    </list>
    </property>
    

hibernate-tempelate

  • 就是Tempelate-Method设计模式(钩子函数),将sessionFactory等的try..Catch等连接管理的东西包含进HiberanteTempelate,而将具体的实现交给用户即可。用户通过调用Tempelate的save方法,即可。

  • 可以将父类注入Tempelate,而所以其他子类都从它继承,即可完成。其实也不好,因为继承之后就不能继承别的其他类了。

  • 模板模式
    将原来固定的与非固定的封装到2个类中,其中一个类完成固定部分,另一个使用接口类,由用户来完成非固定部分的传入.在Java中,由于有匿名类的存在,使接口类的实现可以一步完成,比较风骚.
    如本例中,将hibernate中固定部分:try--catch--finally结构中的getCurrentSession(),beginTransaction(),commit(),close(),rollback()函数封装在HibernateTemplete()中,而将需要非固定部分方法如save,update,delete封装在HibernateCallBack接口中,统一的抽象接口为doInHibernate().
    函数级别的多态.

  • 在模板方法设计模式中,还有另外一种模板.
    由父类定义一个方法中固定的部分,而由子类实现变化部分.
    如Application与document.
    application的openDocument()函数中,定义打开一个文档的顺序:create()-->open()-->read()-->close().在application的子类中,实现这具体的方法create()...等.

  • 特点
    类中有很多模板性的固定顺序的部分,又有一部分又是不固定的.

  • 使用

    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">  
        <property name="sessionFactory" ref="sessionFactory"></property>  
    </bean>
    

    在各自的DAO中,使用hibernateTemplate的对象来实现save,update,等等方法.

hibernateDaoSupport

  • 原因:
    由于每个DAO都要注入sessionFactory或者hibernateTemplate,而每次注入太浪费代码,所以抽象出父类.
    在父类中注入sessionFactroy,然后各个DAO子类完成.
  • 实现:
    父类继承自hibernateDaoSupport,然后通过annotation方式注入sessionFactory,再调用supper.setSessionFactory函数,将注入的sessionFactory传递给父类.
    子类DAO直接调用this.getHibernateTemplate.save()来实现存储.
  • 知识点:
    注意:在beans.xml中实现的内容是单例的,不能用来继承.
# 语言 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×