Mybatis 使用技巧-通用的搜索

问题

        粗浅的使用过几种java的持久框架,感觉mybatis还是十分好用的,特别比较喜欢resultMapping这个feature,使得结果的封装很方便。

实际使用中,笔者遇到一个问题,就是针对不同的搜索,往往要使用很多个定义的检索sql,使得xml和DAO层繁琐复杂。 

例如对于用户表 (User)

public class User {

	private Long id;
	
	private String name;
	
	private String telphone;
	
	private String email;
	
	//getter and setters
    }

         存在使用id, name, telphone, email的搜索,所以对应的xml中,应该定于针对各种情况的搜索。

<select id="findById" resultType="User">
	   SELECT id, name, telphone, email FROM user where id = #{id}
    </select>
    <select id="findByName" resultType="User">
	   SELECT id, name, telphone, email FROM user where name = #{name}
    </select>
    <select id="findByPhone" resultType="User">
	   SELECT id, name, telphone, email FROM user where telphone = #{telphone}
    </select>
    <select id="findByEmail" resultType="User">
	   SELECT id, name, telphone, email FROM user where email = #{email}
    </select>
         如果存在更多子段的搜索,可能意味着书写更多xml,同时DAO层也需要提供更多的方法,获取相应的数据,这样会导致xml文件膨胀,DAO层接口也会随着业务增多不断增多。


我的解决方法


1. ${param} 和 #{param}的区别 

试图解决这个问题之前,先对这两种用法加以区分。 

大家应该对这样的sql很熟悉吧

String sql= "insert into user (name,pwd) values(?,?)";
ps=conn.prepareStatement(sql);
ps.setString(1, user.getName());
ps.setString(2, user.getPwd());
 


 #{param}的用法就是参数,和上面的用法可以对等转化,如果打开mybatis的log,就可以发现每次执行的sql,而${param}的用法则相当于字符串拼接。

 举个例子

<select id="findByEmail" resultType="User">
	   SELECT id, name, telphone, email FROM user where email = #{email}
    </select>

执行的方式是 

 SELECT id, name, telphone, email FROM user where email = ?

然后通过参数的方式设置对应的值。

<select id="findByEmail" resultType="User">
	   SELECT id, name, telphone, email FROM user where email = ${email}
    </select>
        则等于

SELECT id, name, telphone, email FROM user where email = test@163.com
         相当于字符串的直接拼接(假设传入的参数是 email: "test@163.com")

如果采用${param}的方式,则可能导致sql拼接错误,以及sql注入。但是它却可以为sql拼接提供解决方案。

我的通用Query框架

利用这些特性,我决定把所有的 条件拼接起来,运用$拼接sql,运用#设置需要的值,对于每个单独的条件,java类表述如下:

public class QueryItem implements Serializable{

	private String fieldName; //sql的字段 采用$获取值,拼接在sql中
	
	private Object value;//自断对应的值,采用#获取值
	
	private String compareMethod; //比较的方法,可以支持 等于,大于,小于等等
   }
     

当然,上面的定义,只是检索条件的一项我们还需要一个类,把条件项目用 list存起来,这样才能遍历所有的条件。

public class Query implements Serializable {

	private List<QueryItem> queryItems = new ArrayList<QueryItem>();

	private Integer limit;

	private Integer offset;
	
	private String order;

	private String orderDir = "ASC";
	
}
    同时对于检索,还有paging,以及排序的相关内容。 

<sql id="commonQuery">
	<if test="queryItems != null ">
		<foreach collection="queryItems" item="item" index="index"
				separator=" ">

				<if test="item.compareMethod == 'equal' ">
					AND ${item.fieldName} = #{item.value}
				</if>
				<if test="item.compareMethod == 'less' ">
				    <![CDATA[  AND ${item.fieldName} < #{item.value} ]]>
				</if>
				<if test="item.compareMethod == 'less_equal' ">
				  <![CDATA[ AND ${item.fieldName} <= #{item.value} ]]>
				</if>
				<if test="item.compareMethod == 'larger' ">
				  <![CDATA[  AND ${item.fieldName} > #{item.value} ]]>
				</if>
				<if test="item.compareMethod == 'larger_equal' ">
				  <![CDATA[  AND ${item.fieldName} >= #{item.value} ]]>
				</if>
				<if test="item.compareMethod == 'start_with' ">
				  <![CDATA[  AND ${item.fieldName} like '${item.value}%' ]]>
				</if>
				<if test="item.compareMethod == 'end_with' ">
				  <![CDATA[  AND ${item.fieldName} like '%${item.value}' ]]>
				</if>
				<if test="item.compareMethod == 'contains' ">
				  <![CDATA[  AND ${item.fieldName} like '%${item.value}%' ]]>
				</if>
			</foreach>
		</if>
     </sql>
<strong>	</strong>

上面的代码,就是通用检索最核心的部分了,遍历queryItems中的项目,然后取出条件拼接成Where Clause

${item.fieldName} like '%${item.value}%'
      注意这里的用法,前面的语句中使用#来设置值,但是对于字符串like,字符串内的内容属于拼接的部分,所以使用了$

当然还有一些关于paging和排序的设置

<sql id="orderBy">
		<if test="order != null ">
			ORDER BY ${order} ${orderDir}
		</if>
	</sql>

	<sql id="limit">
		<if test="limit != null ">
			LIMIT ${offset}, ${limit}
		</if>
	</sql>

       如果在query中设置了 orderBy和limit,则自动补全这部分在sql中

如何使用框架搜索

<select id="findUsers" resultType="User">
		select <span style="font-family: Arial, Helvetica, sans-serif;">id, name, telphone, email</span>
		from user
		where 1=1
		<include refid="commonQuery"></include>
		<include refid="orderBy"></include>
		<include refid="limit"></include>
    </select>
        

而在java代码中,则可以采用代码形式,任意定义sql的条件 例如

Query query = new Query();
    query.addQueryItem(new QueryItem("name", "liudong", CompareMethodDef.EQUAL));
    query.addQueryItem(new QueryItem("phone", 15618010153L, CompareMethodDef.EQUAL));

    List<User> users = userDao.findUsers(query);

      当然同样可以增加paging,排序等规则。这样会使得xml定义和dao层非常简单,针对不同的检索,只要在java代码中,稍作修改就可以达到目的了




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值