SSH框架
1、使用hibernate进行更新操作时,首先调用了findById方法获取要修改的对象,此时session没有被关闭,接着重新创建一个对象,将要修改的属性值赋值给这个对象。调用修改方法抛出如下异常:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session
原因:在session缓存中已经存在一个与当前传递进来的修改对象具有相同标识符(主键)的对象。Hibernate的机制是只能存在一个具有唯一标示的对象,否则增删改就会出错。
解决办法:
:在使用过滤器/拦截器时,每次开启session,操作后就关闭session。
‚:session.evict(Object object),从缓存中清除指定的对象。
ƒ:session.clear(),是将session缓存中的对象全部清除,杀伤面太大了,不建议使用。
2、HibernateSessionFactory类中有一个线程ThreadLocal类的对象,它用来分配session对象,经测试后发现,由它每回获取的session都不同,有时为空,有时可以得到之前存进去的session对象。
3、如果使用struts+hibernate框架实现数据库的增删改,使用过滤器去开启和提交事务时,有时增删改会没有效果,因为action没有被过滤器过滤,这个使我困惑了很久,因为之前的项目都可以被过滤到,后面我想用拦截器拦截action,在拦截器中开启和提交事务,试验之后发现此法可行。
4、使用hibernate+struts框架开发项目时,系统抛出如下异常:
Exception:
java.lang.reflect.InvocationTargetException
root Cause:
java.lang.NoSuchMethodError: antlr. Collections.AST.getLine()I
原因:由于我用的是MyEclipse自动生成的struts和hibernate类库,hibernate中有个antlr-2.7.7.jar,而struts中有个antlr-2.7.2.jar。异常的原因就是说没有找到antlr.Collections.AST类中的getLine()方法,高版本的jar中有getLine()方法,而低版本中没有getLine()方法,系统默认使用的是低版本的jar包。
解决办法:去除struts类库中的antlr.jar包即可,还需要清理并构建这个项目,因为有的项目的配置信息一时更改不过来。
5、Struts的类型转换器用于将String类型转化为指定的数据类型,还可以将指定的数据类型转化为String类型。开发项目时很方便。
实现方法:
:新建一个类继承StrutsTypeConverter类,实现其中的两个抽象方法,作为转换器类。
‚:新建局部属性文件或者全局属性文件
局部属性文件:放置在相关action类同级目录下,文件名格式:action类名-conversion.properties
里面存放键值对,如:hobbies=util.ListConverter
hobbies就是要转化的属性名,util.ListConverter就是转换器类的完全限定名。
全局属性文件:放置在src目录下,文件名格式:xwork-conversion.properties
里面存放键值对,如:java.util.Date=util.DateConverter
java.util.Date就是要转化的数据类型,util.DateConverter
就是转换器类的完全限定名。
注意:如果我们使用<s:property/>标签,那么它会调用转换其中的convertToString(),如果使用EL表达式,那么就不会调用该方法了。
6、针对类型转换出错的处理--在页面上显示友好提示:
类型转换出错时,要抛出一个运行时异常,程序会根据建立的属性文件,显示错误提示。
实现方法:
:新建局部属性文件或者全局属性文件
局部属性文件:放置在相关action类同级目录下,文件名格式:action类名.properties
里面存放键值对,如:invalid.fieldvalue.time=mistake
invalid.fieldvalue.time就是出错的字段名,mistake是错误提示信息。
全局属性文件:放置在src目录下,文件名格式:message.properties,属性文件的名称不作要求。
还要在struts.xml中配置一个常量:
<constant name="struts.custom.i18n.resources" value="message"/>
属性文件中存放键值对,如:xwork.default.invalid.fieldvalue=fieldname is {0} is error
这是固定的格式,{0}代表错误的字段名,系统会自动赋值。
fieldname is {0} is error 便是提示信息。
7、Struts框架有类似于html的标签,但是它有一定的格式,
但是我们可以在struts.xml中配置一个常量,去掉它的格式。
<constant name="struts.ui.theme" value="simple"/>
8、当我们显示错误信息的时候,会发现错误信息会以列表的形式显示,这样就不美观了,达不到我们想要的标准。所以我们可以用另外的方式输出错误信息。
例如我现在增加了两个错误信息:
this.addFieldError("username","用户名太长!");
this.addFieldError("username","2222!");
那么我就可以使用以下四种方法输出错误信息:
<s:property value="errors.username[0]"/>
‚ <s:property value="fieldErrors.username[0]"/>
ƒ ${errors["username"][0] }
4 ${fieldErrors["username"][0] }
原理:在值栈中有fieldErrors和errors两个对象,这两个对象中存储着错误信息,利用<s:debug/>可以观察到,这两个对象其实就是map数据类型的。
获取map数据的方法:
9、Struts上传文件
jsp部分:
struts.xml部分:
action部分:
注意:
文件对象名就是表单文件控件的name
文件类型的命名=文件对象名+FileContentType
文件名称的命名=文件对象名+FileName
10、struts下载文件
jsp部分:
struts.xml部分:
action部分:
11、两级联动
演示:
原理:
将数据库中的数据封装成对象,然后将对象转化为json数据,在客户端用异步获取后台的json数据即可。
客户端jsp页面:
后台:
注意:在js中如果某个元素还未被加载,那么只可以获得该元素的引用,不能对该元素进行绑定事件。
13、在struts框架中使用json
客户端:
Struts.xml:
UserAction:
注意:struts类库里面没有提供ezmorph-1.0.6.jar文件,所以要手动添加。
14、hibernate中的cascade属性
Cascade属性是存在于set标签中,用来做级联删除和保存。
它的值有以下几种:
默认值是none,不做级联动作;
save-update:级联保存
delete:级联删除
all:级联保存和删除
注意:属性名称和属性值都严格需分大小写
15、hibernate中的inverse属性
修改街道对应的区道信息:
修改后会发现程序执行了两次修改操作:
原因:
区道与街道是一对多的关系;
由于Hibernate是双向维护外键,所以当修改区道中的街道时,会修改一次外键;在修改街道中的区道时,又会修改一次外键。
这样就会产生效率慢的问题,因为如果执行两次修改,那么第二次是无用的操作。利用inverse属性可以解决这一问题。
在区道表的映射文件里面的set标签中设置inverse属性为true;
inverse的属性值如下:
默认值为false,表示我方不放弃维护外键的权利
true,表示我方放弃维护外键的权利
一个国家有一个主席,国家有很多人,主席不可能认识国家的所有人,但是国家所有人可以认识主席。
16、延迟加载
延迟加载分为类级别延迟和关联级别延迟。
类级别延迟:
使用load(),例如:
只有当使用这个对象时才会进行查询,如输出str和str.getName()时就会执行查询语句,但是str.getId()并不会进行查询。
关联级别延迟:
使用set标签中的lazy属性,lazy的属性值有true(默认值)、false、extra(极其懒惰,要什么才查什么);
懒加载的意思就是当你使用到对象中的关联对象时,才执行查询操作。
如当lazy=”true”时,当你使用set时才执行查询操作。
如当lazy=”false”时,当你获取District对象时,同时会查出所有的Street。
如当lazy=”extra”时,用什么查什么。
如我要查询set.size(),系统会执行一下的查询语句:
17、fetch属性
fetch的属性值有select(默认值)、join、subselect
当fetch=”select”时,程序会先查询返回要查询的主体对象,然后根据lazy属性看是否懒加载。
当fetch=”join”时,程序会将主体对象和关联对象用一句连接查询的sql同时查询出来,这样以来,懒加载就无用武之地了。
subselect和select一样,不会一开始就将关联对象查出来。
subselect与select的区别:
设置不执行懒加载;
select是根据关联外键的id,每一个对象发一个select查询,获取关联的对象。
执行的sql如下所示:
而subselect是发送两条sql语句,一条是查询主体对象,而另一条是抓取在前面查询到的所有实体对象的关联集合。
执行的sql如下所示:
18、批量抓取
批量抓取的使用场景是查询出来一个集合,然后又查询每个集合对象中的集合。使用set标签中的batch-size属性实现。
数据库中只有5个区道信息;
设置batch-size=”5”,执行的查询语句如下:
而设置batch-size=”7xxx”,执行的查询语句如下:
由于发送sql数据的次数多少,所以batch-size的数值越大,效率就越高。
当batch-size为4时,首先会有4个?号,接着一个查询语句会有1个?号。
19、QBC查询
格式:
qbc的统计查询得使用projection实现,有两种方式:
(1)
(2)
查看文档发现ProjectionList和Projection的关系如下所示:
可以使用groupProperty投影对结果集进行分组(使用SQL的GROUP BY子句),当你通过某个属性分组时,程序就会查询出该属性所对应的列名。
可以使用Property.forName()来表示投影,就是查询指定的字段。
创建别名有三种方式:
20、离线查询:
离线查询使用DetachedCriteria对象设置限制条件,然后再通过session获取Criteria对象。
离线查询的使用场景:例如Biz类和Dao类,在Dao类中利用session操作CRUD,如果你想在Biz中设置限定条件,如果不使用离线查询,那么势必得获取Criteria对象,如此一来又得获取session,有点麻烦。
但是使用离线查询的话,可以直接获取DetachedCriteria对象设置限定条件,然后再将这个对象传递到Dao中即可。
概念:
投影就是指部分字段,例如我只查询学生表中的姓名,这就叫投影。
CRUD是指在做计算处理时的增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。