其他的动态sql比较麻烦,比如要确保不要漏掉空格,要取消掉一组字段中最后的,
很麻烦。
那mybatis就比较简单。类似于JSTL或其他的xml文本处理器。
为了更加清楚的看到sql语句的具体内容,我们打印日志。
首先在maven
的pom里面添加log4j
,不是log4j-core!
,然后在resources
里面添加log4j.properties
:
# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.org.example.user=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
这里的org.example.user
就是想要输出日志的mapper
的namespace
,也可以在namespace
后加上.${statementID}
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
如果没有传title
参数的话,那么sql语句里就没有if里面的话
choose
类似于Java里的switch
。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
按照顺序,如果有title
,那么语句就是有title
这段,如果没有,就往下找。如果有author
,那么语句就有author
这段。如果都没有,那么语句就有featured
这段。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
如果三个if
都没有匹配到,那么where
就多出来了。
如果只有第二个匹配到了,那么就是where and...
,也不对。
所以:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
有了where
标签,那么只有在标签里面有东西的时候,where
才会进入到语句,而且如果是以and or
开头的时候,也会自动取消掉。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
在trim里,会用prefix
替代prefixOverrides
:
<select id="selecttest" resultMap="testmap">
select * from
user
<trim prefix="where" prefixOverrides="and |or ">
<if test="id!=null">
id=#{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
</trim>
</select>
如果在trim
结果里面的第一个词是prefixOverrides
里的,那么会被prefix
代替,否则的话就会直接在语句开头加上prefix
。
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
会在开头加上set
,并且去掉多余的,
效果类似于:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
collection
就是要传的参数名称,item
就是for循环里的item,index
就是for循环里的index,open
就是foreach
语句的开头,close
就是foreach
语句的结尾,separator
就是每个for的分隔符。collection
可以传递任何iterable
类型的数据,比如map
和array
如果要在annotation
里使用动态sql,就要添加script
标签:
@Update({"<script>",
"update Author",
" <set>",
" <if test='username != null'>username=#{username},</if>",
" <if test='password != null'>password=#{password},</if>",
" <if test='email != null'>email=#{email},</if>",
" <if test='bio != null'>bio=#{bio}</if>",
" </set>",
"where id=#{id}",
"</script>"})
void updateAuthorValues(Author author);
bind可以定义一个变量
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
如果设置了databaseIdProvider
,那么可以在动态sql中使用_databaseId
,以针对不同数据库进行不同操作:
<insert id="insert">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
<if test="_databaseId == 'oracle'">
select seq_users.nextval from dual
</if>
<if test="_databaseId == 'db2'">
select nextval for seq_users from sysibm.sysdummy1"
</if>
</selectKey>
insert into users values (#{id}, #{name})
</insert>
新版本支持语法插件,通过实现以下接口:
public interface LanguageDriver {
ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}
可以在config.xml
里设置为默认语法:
<typeAliases>
<typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<settings>
<setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>
也可以在statement
里指定语法:
<select id="selectBlog" lang="myLanguage">
SELECT * FROM BLOG
</select>
又如果是使用的Java语言:
public interface Mapper {
@Lang(MyLanguageDriver.class)
@Select("SELECT * FROM BLOG")
List<Blog> selectBlog();
}
可以使用
apache velocity
作为动态语法
我们使用的是org.apache.ibatis.scripting.xmltags.XmlLanguageDriver
,alias为xml