sulong 于 2007-12-05
没有评论 »
Annotation是java 5加入的新功能,可以加在java代码的类,域,方法和参数上,丰富程序语义。我一度认为引入annotation后,可以轻松地抛弃html,但是现在我发现annotation也有不好的地方:
- 侵入java代码,被标注代码会对标注产生依赖,比如,如果在类里加了javax.persistence.Entity标注,这意味着编译时得把javax.persistence.Entity所在包加入类路径,即使你并不实际使用这个标注。如果编译期不检测,到运行期才寻找Annotation定义的话,会好很多。xml则不会对代码有任何入侵。
- 需要重新编译才能升效。用XML时,只要更新一下XML重部署,现在是要把java代码也得重新编译。
- 要配置的信息很多时,多个annotation加在同一个目标上,格式很难排,不易读。
- 配置信息散在文档各个地方,不易于查找。
我觉得,使用Annotation时,最好要想清楚,你的代码是不是不会迁移到其它坏境,和annotation的耦合也是没问题可以接受的,否则,不要用annotation了。如果真的要用,最好只用annotation来做标注,但不要来做“配置”。比方说,如果你在用一个标注来配合做权限控制,在调用被标注的方法前,做一些权限的检测。那么,最好只在方法前的标注里说明这个方法需要被做权限检测,但不要说明需要被做怎么样的权限检测,例如下面的这个就很好,
@NeedPermission(methodName="writePost")
但是下面这个就不好
@NeedPermission(methodName="writePost", permission="read,write,admin" condition="and")
上面的写法,暴露了太多的细节(配置信息),而这些信息很可能会随着业务变化而变动。我觉得,把配置的细节统一存放到一个XML中,再用annotation来定义这些配置应该应用到哪里。
sulong 于 2007-12-05
没有评论 »
1、到底在哪用cascade=”…”?
cascade属性并不是多对多关系一定要用的,有了它只是让我们在插入或删除对像时更方便一些,只要在cascade的源头上插入或是删除,所有cascade的关系就会被自己动的插入或是删除。便是为了能正确的 cascade,unsaved-value是个很重要的属性。Hibernate通过这个属性来判断一个对象应该save还是update,如果这个对象的id是unsaved-value的话,那说明这个对象不是persistence object要save(insert);如果id是非unsaved-value的话,那说明这个对象是persistence object(数据库中已存在),只要update就行了。saveOrUpdate方法用的也是这个机制。
2、到底在哪用inverse=”ture”?
inverse属性默认是false的,就是说关系的两端都来维护关系。这个意思就是说,如有一个Student, Teacher和TeacherStudent表,Student和Teacher是多对多对多关系,这个关系由TeacherStudent这个表来表现。那么什么时候插入或删除TeacherStudent表中的记录来维护关系呢?在用hibernate时,我们不会显示的对 TeacherStudent表做操作。对TeacherStudent的操作是hibernate帮我们做的。hibernate就是看hbm文件中指定的是”谁”维护关系,那个在插入或删除”谁”时,就会处发对关系表的操作。前提是”谁”这个对象已经知道这个关系了,就是说关系另一头的对象已经set 或是add到”谁”这个对象里来了。前面说过inverse默认是false,就是关系的两端都维护关系,对其中任一个操作都会处发对表系表的操作。当在关系的一头,如Student中的bag或set中用了inverse=”true”时,那就代表关系是由另一关维护的(Teacher)。就是说当这插入Student时,不会操作TeacherStudent表,即使Student已经知道了关系。只有当Teacher插入或删除时才会处发对关系表的操作。所以,当关系的两头都用inverse=”true”是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是 inverse=”false”或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。
在一对多关系中inverse就更有意义了。在多对多中,在哪端inverse=”true”效果差不多(在效率上)。但是在一对多中,如果要一方维护关系,就会使在插入或是删除”一”方时去update”多”方的每一个与这个”一”的对象有关系的对象。而如果让”多”方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。当然这时也要遍历”多”方的每一个对象显示的操作修关系的变化体现到DB中。不管怎样说,还是让”多”方维护关系更直观一些。
sulong 于 2007-11-30
8 篇评论 »
在不分层的系统里,我们可以将所有的代码都写到一个地方,比如struts的Action类。在这里,我们不仅要处理页面逻辑,还要做业务逻辑,还要做数据访问。比如说:
public String addUser
() {
if(user
== null) {
return FAIL_NO_USER
;
}
Result result
= null;
if(Role.
ADMIN.
equals(user.
getRole())) {
result
= doSomethingForAdmin
(user
) ;
} else {
result
= doSomethingForOthers
(user
);
}
Transaction trans
= sess.
beginTransaction();
Query query
= sess.
createQuery("update Result set level = :level");
query.
setParameter("level", result.
getLevel());
query.
executeUpdate();
trans.
commit();
sess.
close();
return SUCCESS
;
}
那么上面的代码,哪些部分是页面的部分,哪些是业务处理,哪些是数据访问呢?我认为,这个划分方法是:Action里只做和页面相关的事,不操作业务对象;Service不依赖于任何表现技术,不操纵任务用于表现的对象,对于业务对象,尤其是跨多个业务对象的操作,要放到Service里面来;最后,单纯的业务对象的存取,组装放到DAO里完成。上面所说的业务对象,就是像上例中role, result等和业务相关的对象,而SUCCESS, inputID等,则是页面相关的部分。因些,可以将上例改为:
public String addUser
() {
if(user
== null) {
return FAIL_NO_USER
;
}
Result result
= service.
process(user
);
dao.
update(result
);
return SUCCESS
;
}
在service里:
public Result process(User user) {
Result result = null;
if(Role.ADMIN.equals(user.getRole())) {
result = doSomethingForAdmin(user) ;
} else {
result = doSomethingForOthers(user);
}
return result;
}
在dao里:
public void update(Result result) {
Transaction trans = sess.beginTransaction();
Query query = sess.createQuery("update Result set level = :level");
query.setParameter("level", result.getLevel());
query.executeUpdate();
trans.commit();
sess.close();
}
这样分层,看起来会显得很麻烦,但事实上确实是大有好处,首先:
- 代码更易读。每一层的每个方法的意义和目的更加明确,读以起来受的干扰更少。
- 拆开后的每一层都更容易测试。
具体如何分层,还需要在开发中,多多体会,这没有绝对的界限,也许一开始放在action里的页面的控制后来会上升为业务规则,并被其它地方重用,然后被移入service;也许某一块对数据的存取也变得非常复杂,包含了业务逻辑,然后被移入service;也有可能发现以前写的service根本没有想像的那样的业务逻辑,只是帮助做了一些页面的流程控制,然后被重构成Action的一个方法,等等。
sulong 于 2007-11-20
3 篇评论 »
SQL 中的大小写规则在语句的不同部分是不同的,而且还取决于所引用的东西以及运行的操作系统。下面给出相应的说明:
■ SQL 关键字和函数名。关键字与函数名是不区分大小写的。可按任意的大小写字符给出。
■ 数据库与表名。MySQL 中数据库和表名对应于服务器主机上的基本文件系统中的目录和文件。因此,数据库与表名是否区分大小写取决于主机上的操作系统处理文件名的方式。运行在 UNIX 上的服务器处理数据库名和表名是区分大小写的,因为UNIX 的文件名是区分大小写的。而Windows 文件名是不区分大小写的,所以运行在Windows上的服务器处理数据库名和表名也是不区分大小写的。如果在UNIX 服务器上创建一个某天可能会移到Windows 服务器上的数据库,应该意识到这个特性:如果现在创建了两个分别名为abc 和ABC 的表,它们在Windows 机器上将是没有区别的。避免这种情况发生的一种方法是选择一种字符(如小写),总是以这种字符创建数据库和表名。这样,在将数据库移到不同的服务器时,名称的大小写便不会产生问题。
■ 列与索引名。MySQL 中列和索引名是不区分大小写的。
■ 别名。别名是区分大小写的。可按任意的大小写字符说明一个别名(大写、小写或大小写混合),但是必须在任何查询中都以相同的大小写对其进行引用。不管数据库、表或别名是否是区分大小写的,在同一个查询中的任何地方引用同一个名称都必须使用相同的大小写。对于SQL 关键字、函数名或列名和索引名没有这个要求。可在同一个查询中多个地方用不同的大小写对它们进行引用。当然,如果使用一致的大小写而不是“胡乱写”的风格(如SelECt NamE FrOm …),相应的查询可读性要强得多。