框架:
一:hibernate(持久层数据库)
1、优点:对跨数据库,事务封装,ORM(object-relational mapping)映射,延迟加载等提供了良好的解决方案(以bean的形式操作),真正实现面向对象开发,增强了维护性。
2、主键生成策略:
identity: 主键可以自增的数据库(mysql)
assinged: 程序中定义主键
Sequence :序列对象的数据库(oracle)
Increment: hibernate管理主键,插入前先获取当前最大值,再+1作为新的主键(须Integer型)
3、session
A、Session相当于jdbc中的statement对象,因频繁调用,所以设计‘非线程安全’,解决此问题,hibernate将session放到ThreadLocal中,因此我们使用的HibernateSessionFactory.java中的Session是线程安全的(HibernateSessionFactory.getSession() )。
B、轻量级,可以频繁创建和销毁。
C、ThreadLocal
Threadlocal 是一个类似于Map的存储结构,将需要共享的变量T放到TreadLocal中( TreadLocal<T> local = new TreadLocal<T>),每个线程a来访问时通过local.get()获取变量的一个副本T(每个线程只能访问自己的副本变量,因为TreadLocal中存储为 键:当前线程a对应的treadlocal变量——值:变量T),解决多线程并发访问的安全问题(空间换时间,同步机制需要排队,耗时间)。(参照threadlocal的get和set方法http://www.cnblogs.com/dolphin0520/p/3920407.html)
4、hibernate缓存:
A、一级缓存(session级别的缓存或事务级别的缓存)
Hibernate自带的,缓存的是对象,放在session中,生命周期同session一致,针对一个事务来说,通过ID访问对象时用对象的ID判断是否有相同对象可用。
B、二级缓存(sessionFactory级缓存)
周期随sessionFactory的生命周期(sessionFactory是线程安全并且重量级的———消耗内存大,创建过程复杂,使用时间长,生命周期很长,系统启动就初始化,一般一个数据库对应一个sessionfactory),缓存的是对象,session可以用,也是针对通过ID访问对象时,查找缓存中有无该对象。
作增、删、改操作时会更新对象。
C、查询缓存sessionFactory级缓存)
主要用于缓存对象的普通属性,如果是实体,只缓存对象的ID。
原理:查询缓存的一般过程如下:
①:Query Cache保存了之前查询执行过的SelectSQL,以及结果集等信息组成一个Query Key
②:当再次遇到查询请求的时候,就会根据QueryKey从QueryCache中找,找到就返回,但当数据表发生数据变动的话,hbiernate就会自动清除QueryCache中对应的Query Key
我们从查询缓存的策略中可以看出,Query Cache只有在特定的条件下才会发挥作用,而且要求相当严格:
①:完全相同的SelectSQL重复执行
②:重复执行期间,QueryKey对应的数据表不能有数据变动
(因此生命周期不定)
三种缓存都开启,查询顺序:
a、查询普通属性:查询缓存—>数据库
b、实体:查询缓存中找id—>(一/二)级缓存中找—>数据库
开启缓存:(需要导入缓存包)
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
<property name="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider</property>
二、在src目录下加入ehcache.xml文件,文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="150000"
eternal="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
</ehcache>
三、在需要从缓存读数据的DAO查询代码中加入setCacheable(true)。
5、Hibernate缓存N+1问题:
在多对一关系中(如students和class),因为每个student中有一个class属性,当查询多(students)时,需要一条sql——select * from students,此条语句查询出N个学生,此时每一个学生在用class属性时,会根据关联class的id查询出各自的class属性(明明一条sql可以查出所有学生,却发出了N+1条语句),所以出现N+1问题。
6、Hibernate对象的状态:
A、瞬时:随时可以销毁
B、游离
C、持久化:比如保存在缓存中(如session.save()),缓存关闭后变为游离
7、Inverse和cascade:
两张表,A和B(一对多)
Inverse=true,控制权交给对方。 A的set属性中配置inverse=true,保存A和B的对象时,只有两条insert语句,B(与A关联的外键A_id)中自动保存A的id
Inverse=false,控制权交给自己。A的set属性中配置inverse=false,保存A和B的对象时,有2条insert语句和1一条update语句,B(与A关联的外键A_id)中不会自动保存A的id,此update语句就是修改A_id=A的id,效率降低。
Cascade用来设置主外键的关联方式,A中set(B),B中set(A),配置cascade=“all”,用一个save()保存A时也可以同时保存B,否则只能保存A。
8、Hibernate检索方式:HQL(语言)和QBC(面向对象)
HQL:
A、List和iterator查询
List每次发起新的select,iterator会先从缓存中根据id取(如果缓存没有,iterator效率低,因为要先发起一条select查出所有id,根据每个id又去查询)。
B、绑定参数时,?用:参数名称 代替
eg:(”from user where id=?,name=?“); query。Set(0,22); query.set(1,”张三”)
(from user where id=:id,:name); query.set(“id”,22); query.set(“name””张三”);
Spring
1、IOC: spring提供来管理实体bean的容器,称为控制反转(原来的控制权在bean中,需要new,现在交给IOC来控制)。也称为DI(依赖注入),因为接口的实现类依赖IOC容器赋值。
2、获取bean: BeanFactory, 延迟获取,第一次getBean才创建对象,ApplicationContext在自身被容器初始化时就创建全部的类对象。(BeanFactory管理bean,factoryBean生成bean)
ApplicationContext常用实现类:FileSystemXmlApplicationContext;
ClassPathXmlApplicationContext XmlWebApplicationContext
Eg:
ApplicationContext context = new ClassPathXmlApplicationContext ( “ applicationContext . xml ” ) ;
Teacher teacher = (Teacher) context.getBean(“Teacher”); //通过配置文件applicationContext . Xml 获取实体Teacher
3、set属性注入:(A中有B,在A中提供B的set和get方法)
A、基本数据类型<property name=”aa” value=”bb”>
B、引用数据类型<property name=”aa” ref=”bb”>
C、Null型<property name=”aa”><null /></property>
D、Properties型<property name=”properties”>
<props>
<prop key=”1”>11</prop>
<prop key=”2”>22</prop>
</props>
</property>
E、Set 、 map、list注入
4、构造方法注入:(A中有B,B中有构造方法,可能是多个,在配置文件中配置B时,用构造方法的方式,并且根据配置的类型确定使用B中的哪个构造函数)
Eg:
<bean id=”bb” class=”B”>
<constructor-arg type=”java.lang.String” value=”hello”></constructor-arg>
<constructor-arg type=”java.lang.String” value=”word”></constructor-arg>
</bean>(说明使用B中参数为两个String的构造方法)
<bean id=”aa” class=”A”>
<property name=”bb” ref=”bb”></property>
</bean>
ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
A a = (A) context.getBean(“aa”); //获取bean时就注入,执行构造方法中的内容。
注入外部属性文件的属性值,如数据库连接文件
<bean id=”property_configer” class=”org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer”>
<property name=”locations”>
<list>
<value>db_connection_info.properties</value>
</list>
</property>
</bean>
<bean id=”aa” class=”A”>
<property name=”username” value=”${username}”></property>
<property name=”password” value=”${password}”></property>
</bean>
PreferencesPlaceholderConfigurer是spring操作外部属性文件的类
A类中有两个属性,需要引用外部文件的值
5、bean作用域
<bean id=”xx” class=”xxxx” scope=”prototye”>//多例 线程安全
<bean id=”xx” class=”xxxx” scope=”singleton”>//单例 线程不安全( 默认)
还有request ; session; globalSession.
6、生命周期
在xml中指定初始和销毁方法
<bean id=”” class=”” init-method=”” destroy-method=””>
7、bean的延迟加载:
在<bean >或<beans>中配置lazy-init=”true”
8、多个applicationContext.xml使用
每个模块有自己的applicationContext.xml(假如叫other.xml),用一个主配置文件applicationContext.xml,在头文件下,<bean ></bean>的上面配置:<import resource=”other.xml”>,用多个import引入多个分配置文件,通过加载主配置文件可以加载多个分配置文件。
AOP:面向切面编程,将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统(说白了就是化繁为简, 将不同的关注点分离出来 ,最后融合在一起,避免主逻辑代码看着很多很乱,难以维护)。
1、
a、通知(advice):说明什么时候干,干什么东西
通知的类型:before after around after-returning after-throwing
b、连接点(JoinPoint):spring允许通知的地方,比如方法的前、后或者抛出异常时等。
c、切点(pointcut):满足条件的规则,也就是具体的需要切面的哪个方法上。
d、切面(aspect):就是要植入到系统的某种功能(通知和切点的结合),说白了就是独立出来的那段代码。
2、静态代理:保证代理和被代理对象实现同一个接口,并保持接口始终不变(保证不改变被被代理类中的代码,实现其功能并添加新功能)。
Eg: 接口:AA 方法say();
实现类:AAA实现AA 方法say(){ 我是李凡}
代理类:BBB实现AA
在BBB中声明接口 AA aa, 构造方法为
public BBB(AA aa){
Super();
this.aa=aa;
}
Public void say(){
我是张三
aa.say();
我是李四
}
Main(){
AA bbb = new BBB(new AA());
Bbb.say();
}
运行结果为:
我是张三
我是李凡
我是李四
静态代理缺点:因为代理类绑定了固定的接口,扩展性不好,代理多个类,需要创建多个代理类。
3、动态代理:由InvocationHandler来实现,它代表任意接口。
动态代理类:
Public class CC implements InvocationHandler{ //可以用具体的接口来强转CC
Object object; //代表可以是任意接口的任意实现类对象
//声明bind();
Public Object bind(Object object){ //此Object代表被代理的具体类型
This.object = object;
Return Proxy.newProxyInstance ( object.getClass().getClassLoader(),
object.getClass().getInterfaces() , this);
//将object的类和接口进行动态关联,避免静态代理中接口固定的缺点,把面向接口转为面向实现类的开发(this代表代理类CC的对象,也和被代理类object关联起来了)
}
//重写invoke();
Public Object invoke(Object obj , Method method, Object[] arg )throws Throwable{
Object obje = null;
我是张三 //需要增加的功能
obje = method.invoke(object , arg); //object为上面的任意接口的实现类对象
我是李四 //需要增加的功能
return obje;
}
//用上面的AA和AAA为例:
Main(){
CC cc = new CC(); //获取该动态代理类的对象cc
AA aa = (AA)cc .bind( new AAA() ); //bind中传入具体的实现类对象,
通过bind返回的是AA的类型。
aa.say();
}
}
运行结果为:
我是张三
我是李凡
我是李四
优点:InvocationHandler代表任意接口,代理类中Object代表任意接口对象,所以可以根据需要传不同的接口和实现类。变更新功能只需要重写invoke中的内容,在传入对应的被代理类即可。
STRUTS2
Struts2基于MVC模式的框架,分别指 (M业务逻辑层--javabean组件,V视图层--jsp文件,C控制层--servlet)。
1、拦截器:
Action中的属性能接收jsp的值并自动设值,是因为拦截器的作用(它只能拦截,到action中去的数据)。
自定义拦截器:
实现Interceptor或继承AbstractInterceptor,重写intercept方法。如:
Public class Lanjieqi extends AbstractInterceptor{
@Overide
Public String intercept(ActionInvocation arg0) throws Exception{
System.out.print(“action内容前”);
String resultValue = arg0.invoke(); //invoke的作用就是执行action中的内容。
System.out.print(“action内容后”);
Return resultValue;
}
}
//自定义拦截器可不改变action代码,扩展功能。
在struts.xml中的配置:
<package>
<interceptors> //配置拦截器
<interceptor name=”abc”class=”自定义拦截器的类”>
</interceptor>
<interceptor name=”特定拦截器”class=”自定义拦截器的类2”>
</interceptor>//某个action独立使用的
<interceptor-stack name=”myInterceptorStack”>//定义一个拦截器栈,把自定义和默认的拦截器引入。
<intercptor-ref name=”defaultStack”></intercptor-ref>
//引入默认的拦截器
<intercptor-ref name=”abc”></intercptor-ref>
//引入自己的拦截器
</interceptor-stack >
</interceptors>
<default-interceptor-ref name=”myInterceptorStack”/>
//用默认拦截器栈引入自定义栈,这样每个action都可以用到自定义栈中的拦截器。但是action要使用自己特定的拦截器,只能到action中引入,不能写到公用的里面,如下:
<action name=”login” class=”LoginAction”>
<result name=””>/xx.jsp</result>
<intercptor-ref name=”特定拦截器”></intercptor-ref>
</action >
</package>
2、解析和生成xml文件
(1)dom4j解析xml文件(先引入dom4j-1.6.1.jar):
struts.xml文件如下:
<mymvc>
<actions>
<action name="list" class="com.Controller">
<result name="toListJsp">
/list.jsp
</result>
<result name="toUserJsp" type="redirect">
/user.jsp
</result>
</action>
</actions>
</mymvc>
解析如下:
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Reader{
public static void main(String args[]){
SAXReader reader = new SAXReader();
Document document = reader.read(reader.getClass().
gerResourceAsStream("/struts.xml"));
//获取mymvc层
Element mymvcElement = document.getRootElement();
system.out.println(mymvcElement.getName()); //结果是mymvc
Element actionsElement = mymvcElement.element("actions");
system.out.println(actionsElement.getName()); //结果是actions
List<Element> actionList = actionsElement.element("action"); //可能有多个action
for(int i=0;i<actionList.size();i++){
Element actionElement = actionList.get(i);
system.out.println(actionElement.getName()); //结果是action system.out.println("name="+actionElement.attribute("name").getValue());
//结果是name=toUserJsp
system.out.println("class="+actionElement.attribute("class").getValue()); //结果是com.Controller
List<Result> resultList = actionElement.elements("result");
for(int j=0;j<resultList.size();j++){
Element resultElement = resultList.get(j);
system.out.println("result name="+resultElement.attribute("name").getValue());
//结果是result name=toListJsp
Attribute typeAttribute = resultElement.attribute("type");
if(null!=typeAttribute){
system.out.println("type="+typeAttribute.getValue());
}else{
system.out.println("");
}
//第一个结果是"",第二个是redirect;
system.out.println(resultElement.getText().trim());
//结果是/list.jsp和/user.jsp
}
}
}
(2)dom4j生成xml文件(先引入dom4j-1.6.1.jar):
import java.io.FileWriter;
import java.io.IOExeption;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
public class Writer{
public void static main(String[] args){
Document document = DocumentHelper.createDocument();
Element mymvcElement = document.addElement("mymvc");
Element actionsElement = mymvcElement.addElement("actions");
Element listActionElement = actionsElement.addElement("action");
listActionElement.addAttribute("name","list");
listActionElement.addAttribute("class","com.Controller");
Element resultElement = listActionElement.addElement("result");
resultElement.addAttribute("name","toListJsp");
resultElement.setText("/list.jsp");
Element resultElement = listActionElement.addElement("result");
resultElement.addAttribute("name","toUserJsp");
resultElement.setText("/user.jsp");
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(new FileWriter("struts.xml"),format);
writer.write)(document);
writer.close();
}
3、Struts2 自动刷新功能:
//实体类
public class User {
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
//action类
public class Loginextends ActionSupport {// 继承ActionSupport
private Useruser;
// 提供set,get
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public void validate() {// 重写validate方法
super.validate();
if("".equals(this.user.getName())){
this.addFieldError("name","用户名不能为空");
// 通过ActionSupport中的addFieldError方法,可以对错误信息进行处理,在通过jsp显示
} else if ("".equals(this.user.getPassword())) {
this.addFieldError("password","密码不能为空");
}
}
public String execute() {
if (1 == 1) {//数据库验证,如果正确
return "OKJSP";
} else {
return "NOJSP";
}
}
}
//struts.xml配置
<struts>
<constant name="struts.devMode" value="true" />//不写这行默认为false,true代表修改此文件后不用重启服务器
<package name="Struts.login" extends="struts-default">
<action name="login" class="controller.Login">
<result name="OKJSP">/ok.jsp</result>
<result name="NOJSP">/no.jsp</result>
<result name="input">/login.jsp</result>
//如果action中调用了ActionSupport的addFieldError方法,说明验证没有通过,则会到struts.xml中找<result name="input">xxx.jsp</result>的配置,并在xxx.jsp中可以获取该错误信息
</action>
<constant name="struts.ui.theme" value="simple" />
//该配置可以屏蔽struts2自动生成的大量table、tr、td等HTML标签
//当然,使用该配置后,struts的s:textfield标签会失去lable属性
</package>
</struts>
(如果struts.xml没有配置<constant name="struts.ui.theme"value="simple" />,那么使用以下struts标签可以自动显示错误信息,但是为了屏蔽大量HTML标签需要配置,所以用jsp文件2中原生的form标签的方式来获取错误信息
)
//jsp文件1
<s:form action="login" method="post">
//需要使用struts标签才能获得action中刷新验证的错误信息
姓名:<s:textfieldname="user.name" />
密码: <s:textfield name="user.password" />
<s:submit value="提交"></s:submit>
</s:form>
//jsp文件2,在jsp中加入<s:debug></s:debug>
<body>
<s:debug></s:debug>
<br />
<form action="login" method="post" >
姓名:<input type=”text”name="user.name" />
${errors.name[0]}
</br>
密码: <input type=”text” name="user.password" />
${errors.password[0]}
<br/>
<input type=”submit” value=”提交”>
</form>
</body>
Mybatis
1、常用标签的使用:
Mybatis
1、常用标签的使用:
<resultMap type=”实体类/map”id=”userResult”>
<result column="数据库字段" property="实体类属性/map的key" javaType="String" jdbcType="VARCHAR">
</resultMap>
<sql id="usersql">
id,name,age ……要从数据库查询的字段
</sql>
<select id="selectUser" resultType="map" parameterType="String" resultMap="userResult">
//select中返回类型为map,参数的类型String,结果集放在id为userResult的resultMap标签中。
select
<include refid="usersql"> //调用id为usersql的sql标签中的字段
from t_user
where id=#{id,jdbcType="varchar"};
</select>
<insert id="userInsert" parameterType="UserInfo">
<if test="name!=null">
insert into t_user values(#{id,jdbcType="varchar"},#{name,jdbcType="varchar"})
</if>
<if test="name==null">
insert into t_user values(#{id,jdbcType="varchar"},)
</if>
</insert>
<choose></choose>
//set标签,用来执行update
<update id="updateUser" parameterType="UserInfo">
update t_user
<set>
<if test="id!=null">id=#{id,jdbcType="varchar"},</if>
<if test="name!=null">name=#{name,jdbcType="varchar"},</if>
</set>
<if test="id!=null">where id=#{id,jdbcType="varchar"}</if>
</update>
//foreach标签,用来有规律的生成sql语句,一般用在in条件中
//其中,collection代表传入参数的类型(可以是list,可以是array,
也可以是多个list或array等封装的map的key),index代表迭代的当前位置
<select id="selectUserList" parameterType="list" resultType="map">
select * from t_user where id in
<foreach collection="list" item="eachId" index="currentIndex"
open="(" separator="," close=")"> //循环以"("开始,以","分隔,以")"结束
#{eachId}
</foreach>
</select>
<insert id=”insert” parameterType=”map”>
<selectKey keyProperty=”id” order=”BEFORE” resultType=”java.lang.Long”>
Select idauto.nextval from dual //插入时主键取的oracle序列idauto的值
</selectKey>
Insert into xxxx values(xxxx);
</insert>