mybatis在实际使用中参数大部分还是比较简单的,但是我们还是有必要讨论下参数的使用。我们可以通过制定参数的类型去让对应的typeHandler处理它们,具体的可以参考之前typeHandler的用法。通过指定对应的JdbcType,JavaType我们可以使用哪个typeHandler去处理参数,或者制定一些特殊的东西,但是我们需要主要:定制参数属性的时候,mybatis不允许换行。
一:参数配置
我们可以传入一个简单的参数,比如int,double等,也可以传入JavaBean。有时候我们需要处理一些特殊的情况,我们可以指定特定的类型,以确定使用哪个typeHandler处理它们,以便我们进行特殊的处理。
#{age,javaType=int,jdbcType=NUMERIC}
我们还可以指定哪个typeHandler去处理参数:
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
此外,还可以对一些数值的参数设置其保存的精度:
#{price,javaType=double,jdbcType=NUMERIC,numericScale=2}
二:存储过程支持
对于存储过程而言,存在3种参数,输入参数in,输出参数out,输入输出参数inout。mybatis的参数规则为其提供了良好的支持。我们同定制mode属性来确定是哪一种参数,它的选项有3种:IN,OUT,INOUT。当参数设置为OUT,或者INOUT的时候,mybatis会将存储过程返回的结果设置到你定制的参数中。当你返回的是一个游标(也就是我们制定JdbcType=CURSOR)的时候,我们还需要设置resultMap以便mybatis将存储过程的参数映射到对应的类型,这时mybatis就会通过我们设置的resultMap自动映射结果。
#{role,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=roleResultMap},这里的javaType是可选的,即使我们不指定,mybatis也会自动检测它。
mybatis还支持一些高级特性,比如结构体,但是当注册参数的时候,我们就需要去指定语句类型的名称(jdbcTypeName),比如下面的用法:
#{role,moe=OUT,jdbcType=STRUCT,jdbcTypeName=MY_TYPE,resultMap=droleResultMap}
在大部分的情况下,mybatis都会去推断你返回数据的类型,所以大部分情况下我们都无需去陪参数类型和结果类型。我们要设置的往往只是可能返回为空的字段类型而已。因为null值,mybatis无法判断其类型:
#{roelNo},#{roelName},#{note,jdbcType=VARCHAR}
对于备注而言,可能返回为空的,用jdbcType=VARCHAR明确告知mybatis,让它被StringTypeHandler处理即可。
这里就暂时不给出调用存储过程的测试。
三:特殊字符串替换和处理(#和$)
在mybatis中我们经常需要传递字符串,我们设置的参数#{name}在大部分的情况下mybatis会创建预编译的语句,然后mybatis为它设置值,而有时候我们需要的是传递sql语句的本身,而不是sql所需要的参数。例如在一些动态表格,我们传递sql的列名,根据某些列进行排序,或者传递列名给sql都是比较常见的场景,当然mybatis也对这样的场景进行了支持,这些hibernate是难以做到的。
例如,在程序中传递变量columns="col1,col2,col3,col3,col4...."给sql,让其组装成为sql语句。当然不想被mybatis像处理普通参数一样把它设为"col1,col2,col3,col3,col4....",那么我们就可以写成如下语句:
select ${columns} from tablename
这样mybatis就不会帮助我们转义columns,而变为直出,而不是作为sql的参数进行设置了。只是这样对sql而言是不安全的,mybatis给出了灵活性的同时,也需要自己控制参数以保证sql运转的正确性和安全性。
四:sql元素
sql元素的意义,在于我们可以定义一串sql语句的组成部分,其他的语句可以通过引用来使用它。例如,你有一条sql需要select几十个字段映射到javabean中去,第二条sql也是这几十个字段映射到javabean中去,显然这些字段写两遍不太合适。那么这时候就用sql元素来完成,例如,插入角色,查询角色列表就可以这样定义,代码如下:
<sql id="role_columns">
id,role_name,note
</sql>
<select parameterType="long" id="getRole" resultMap="roleMap">
select
<include refid="role_columns" />
from role where id=#{id}
</select>
<select parameterType="map" id="findRoles">
select id,role_name,note from role where role_name like
concat("%",#{roleName},"%")
and note like concat("%",#{note},"%")
</select>
这里用了sql元素定义了role_columns,它可以很方便使用include元素的refid属性进行引用,从而达到重用的功能。上面是一个简单的例子,在实际的环境中我们也可以定制参数来使用它们,代码如下:
<sql id="role_columns">
#{prefix}.id,#{prefix}.role_name,#{prefix}.note
</sql>
<select parameterType="string" id="getRole" resultMap="roleResultMap">
select
<include refid="role_columns">
<property name="prefix" value="r"/>
</include>
from role r where id=#{id}
</select>
这样就可以给mybatis加入参数,我们还可以这样给refid一个参数值,由程序制定引入sql,代码如下:
<sql id="someinclude">
select * from <include refid="${tableName}">
</sql>
这样把一个表名传递进来,这样就可以实现一处定义多出引入,大大减少了工作量。