写在前面: 这是个悲伤的故事.....................................................
系统中经常会碰到这样的情况, 表里面有个状态字段, 有各种各样的状态, 比如用户表可能有下面的状态:
用户状态枚举类(这里就是为了说名举的例子,将就着用吧 - -! )
package com.haogrgr.buka.consts; public interface UserConst { public enum UserStatus { SYSTEM("系统用户", "2"), NORMAL("正常用户", "1"), BLOCK("冻结用户", "-1"), DEL("删除用户", "-2"),; UserStatus(String desc, String value) { this.desc = desc; this.value = value; } private String desc; private String value; public String getDesc() { return desc; } public String getValue() { return value; } } }
当我们需要查询出可用用户(SYSTEM或NORMAL) 时 :
sql : select * from user where status = '2' or status = '1' 或者: sql: select * from user where status != '-1' and status != '-2'
这样会有问题, 当我们改变常量值时, 比如以前 是 SYSTEM(2), NORMAL(1), BLOCK(-1), DEL(-2); 现在变成了 SYSTEM(11), NORMAL(10), BLOCK(-10), DEL(-12);
虽然这种情况很少,但是还是可能会出现的, 比如说, 我不哭~~~~
当碰到改变常量值的情况时: 我们就得小心了.... 得找到所有引用的地方, 然后一个个的改, 比如这里要改成
sql : select * from user where status = '11' or status = '10'
如果到条件到处都是写死在sql中~~~~~~嘿嘿, 有得你改了, 你得找出所有用到了的地方~~~而且可能在其他的sql文件中也用到了这个状态过滤~~~~~~~
总之....这么写, 一旦改了常量值~~~~蛋蛋疼~~~~
那么如何改呢?
可以这样: select * from user where status = #{systemStatus} or status = #{normalStatus}
然后dao和service这么写(我用的是Spring帮我动态代理生成的mapper实现类, 所以mapper不需要写实现类~~~)
UserMapper: public List<User> findAvailableUser(String systemStatus, String normalStatus); UserService; public List<User> findAvailableUser(){ return userMappser.findAvailableUser(UserStatus.SYSTEM.getValue(), UserStatus.NORMAL.getValue()); }
这么写是ok啦, 就是有那么点蛋疼~~~特别是查询条件复杂的情况下, 要传很多的参数~~~~接口不干净~~~~
现在解决办法来了
mybatis的sql文件很灵活, 因为里面有些标签可以使用OGNL表达式
比如说<bind> 标签 , (ognl表达式不知道的去百度,google吧~~~我这里就不讲了....)
于是我们可以这样用了(注意:OGNL是通过反射来获取值的,所以一定要保证你的类或get方法的可见性, public 声明)
<select id="findAvailableUser" resultMap="BaseResultMap"> <bind name="_SYSTEM" value="@[email protected]"/> <bind name="_NORMAL" value="@[email protected]"/> select * from user where status = #{_SYSTEM} or status = #{_NORMAL} </select> 然后mapper接口也变得简洁了: UserMapper: public List<User> findAvailableUser();
现在接口清晰多了, 而且常量也没有写死. (如果你的常量是static变量, ognl也能获取到~~~百度去吧~~~)
总结: 总的来说, 就是通过bind标签, 来写ognl表达式来获取值, 所以ognl能获取到的东西,都能用到sql中去....
注意:使用了这种方式后, 还有问题: 比如改包名, 将 com.haogrgr.buka.consts.UserConst 改成 com.haogrgr.buka.consts.user.UserConst 那么执行sql会报错
但是有一点好的就是, 当改了常量类包名或者类名或者常量名时, 执行sql就会报错, 能够尽早的被发现.
当然,使用这总方式还会损失点性能~~~~就那么一点点啦,就那么一点点啦,哈哈哈哈哈哈哈哈哈哈哈哈
其实一般项目哪会经常改常量的值啊~~~~搞这么复杂干什么~~~~但是写代码嘛, 总是追求更好的做法, 否则挺无聊的.
(ps:我不是第一个想到这么做的~~~)
最后听说写文章要首位呼应, 于是
写在最后:是怎样的经历才会让一位少年想出如此蛋疼的搞法.....................................................
发现个天大的bug, 对于已有数据的系统~~~~你改了常量值....数据库中已有记录的值还是存的老值~~~所以还是少改常量值的好~~~蛋蛋疼.