DAO
1. DAO中的SQL中不要包含业务
设计不好的例子:
<update id="updateUserMoney" parameterType="com.bt.chains.bean.domain.User">
UPDATE USER
SET MONEY = (MONEY - #{money})
WHERE USER_ID = #{userId}
</update>
UPDATE USER
SET MONEY = (MONEY - #{money})
WHERE USER_ID = #{userId}
</update>
分析: 只能实现减少用户钱数的功能,如果想增加用户钱数,或者想更新用户其他字段则需要重新写接口,重用性差。
业务逻辑应该放在java service中,DAO只是简单的数据访问。
建议:针对每一个域对象添加增,删,改,查的接口,并且使用可选参数。
如一次性更新域对象所有的字段
<update id="updateUser" parameterType="com.bt.speed.bean.domain.User">
UPDATE USER
SET MONEY = #{money}
, SPECIAL_MONEY = #{specialMoney}
, LOGIN_TIME = #{loginTime}
, LAST_CONNECTED_TIME = #{lastConnectedTime}
, STATUS = #{status}
, NAME = #{name}
WHERE USER_ID = #{id}
</update>
UPDATE USER
SET MONEY = #{money}
, SPECIAL_MONEY = #{specialMoney}
, LOGIN_TIME = #{loginTime}
, LAST_CONNECTED_TIME = #{lastConnectedTime}
, STATUS = #{status}
, NAME = #{name}
WHERE USER_ID = #{id}
</update>
根据可选参数拼装SQL,只有查询需要拼装SQL,其他DB操作要避免使用拼装SQL的形式。
<select id="selectRewardConfig" resultMap="RewardConfig">
SELECT * FROM REWARD_CONFIG
WHERE 1 = 1
<if test="id != null">
AND RID = #{id}
</if>
<if test="type != null">
AND TYPE = #{type}
</if>
<if test="count != null">
AND COUNT = #{count}
</if>
</select>
SELECT * FROM REWARD_CONFIG
WHERE 1 = 1
<if test="id != null">
AND RID = #{id}
</if>
<if test="type != null">
AND TYPE = #{type}
</if>
<if test="count != null">
AND COUNT = #{count}
</if>
</select>
2. 更新表时要先查询,后更新
设计良好的例子:
UserRole userRole = roleMapper.queryRole(userId, roleId, null);
userRole.setInUse(DBConstants.InUseStatus.InUse);
roleMapper.updateUserRole(userRole);
userRole.setInUse(DBConstants.InUseStatus.InUse);
roleMapper.updateUserRole(userRole);
这样只需改变要修改的值,其他不没有改变的值不会受到影响。在update SQL通过主键进行update
3. DAO查询接口只传简单类型,不能传入域对象
不好的例子:
public UserProp queryUserProp(UserProp userProp);
这种设计每次查询的时候都需要先构造一个UserProp对象,查询很麻烦。
查询只需要传入查询条件即可。
数据库
1. 设计表时要减少数据冗余
不好的例子
USER_ID | ROLE_ID | ROLE_RANK | IS_NEW_ROLE | IN_USE |
USER_ID | ID | TYPE | OPTIME | RANK | IS_NEW_ROLE |
ROLE_RANK和RANK,以及IS_NEW_ROLE出现数据冗余,如果用户修改了这两项,需要改两张表。
可以只配置在USER_ROLE表中,通过关联查询到。
2. 状态标志设置默认值
比如用户是否激活,物品是否正在使用等标志需要设置默认值。
3. 建表字段名避免关键字
DESC是关键字,如果字段Description简写为desc建表,执行SQL会出错。
4. 大小写区分
部分虚拟主机对数据库进行了优化,SQL中表明,字段名只能使用大写字母,否则会出错
WebService
1. 输入输出只包含最小结果集
如果包含过多值,调用者会不清楚哪些需要解析哪些可以忽略,尤其对于手机应用浪费带宽,影响性能。
2. 不要返回域对象
不能把代表数据库表的对象直接返回给客户端,数据库中不是所有的字段客户端都会用到,返回无意义的数据只会降低性能和增加维护成本。
尤其是当遇到需求变化,画面数据已经不能从一张表获取时,改动量会非常大。另外如果界面数据需要做格式化而不能直接使用数据库原始数据时,修改困难。
3. 在DAO和Service之间加上Repository层
这一层可以针对业务设计接口,添加缓存。
4. 数据格式化
对于webservice来说,框架可以做到通用的格式化处理,所以对于Date等数据类型可以在输出对象中直接用java.util.Date类型定义。
5. 返回结果
1) 返回扁平化的对象,即对象层级尽量少,否则客户端解析困难。
2) 返回对象中只包含简单对象,避免使用复杂类型对象,如Map,Enum等,因为这类对象转化成json后会出现无法预期的结果
6. 返回状态码
对于业务校验,0代表成功,其他代表失败