目录
本文集各家之长,自学整理,若有错误,欢迎留言指出!!!
固定格式
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.scau.demo.mapper.UserMapper">
## ...具体内容...
</mapper>
其中,namespace
用于绑定Mapper接口。不同mapper接口对应到不同的xml。
前置操作
1、在application.yml
中添加:
mybatis:
# 设置别名,这样,在xml文件中就不用写全名
type-aliases-package: com.scau.demo.entity
# resources文件夹下创建mapper文件夹,内含xxxMapper.xml文件
mapper-locations: classpath:mapper/*.xml
2、在启动类前添加:
// mapper接口所在包路径
@MapperScan(basePackages = "com.scau.demo.mapper")
顶级元素
<xx>
内最外层可以包含的元素。
- cache – 配置给定命名空间的缓存。
- cache-ref – 从其他命名空间引用缓存配置。
- resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
- parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
- sql – 可以重用的 SQL 块,也可以被其他语句引用。
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
select
补充说明:
id
:对应mapper接口中的函数定义,如:
parameterType
:入参类型,可以使用的有基本数据类型和Java复杂数据类型- 基本数据类型:包含int,String,Date等。基本数据类型作为传参,只能传入一个。通过#{参数名} 即可获取传入的值
- 复杂数据类型:包含JAVA实体类、Map。通过#{属性名}或#{map的KeyName}即可获取传入的值
// 基本类型
<select id="get" parameterType="String" resultType="User">
select * from `scau_log` where `_openid`=#{_openid};
</select>
// 复杂类型 - 实体类
<select id="selectTeacher" parameterType="com.myapp.domain.Teacher" resultType="com.myapp.domain.Teacher">
select * from Teacher where c_id=#{id}
</select>
resultType
:结果类型,与mapper接口中的函数定义的返回值一致
// 返回一般数据类型的值
<select id="Sel" resultType="java.lang.String">
select username from user_test where id = #{id}
</select>
// 返回类型是javaBean
<select id="Sel" resultType="com.tx.springboottestdemo.entity.User">
select * from user_test where id = #{id}
</select>
// 返回是List类型
List<User> getUsers(); // mapper 接口
// SQL映射文件,这里需要注意的是返回是List类型 但是resultType依然是javaBean
<select id="getUsers" resultType="com.tx.entity.User">
select * from user
</select>
// 返回类型是Map结构
// 当我们在查询并返回一条数据的时候,可以把{字段名,字段值}封装成Map结构
Map<String, Object> findUserByName(Integer id); // mapper 接口
<select id="findUserByName" resultType="string">
select userName from user where id=#{id};
</select>
// 传入多个参数 - 1
// 可以看做是加了注解
public List<User> findUser(@Param("name1") String name1, @Param("name2") String name2);
// 对应的SQL文件:
<select id="findUser" resultType="com.tx.springboottestdemo.entity.User">
select * from user_test where userName = #{name1} and realName = #{name2}
</select>
// 传入多个参数 - 2
// 可以把参数封装到Map里面 有些时候我们的业务数据查询没有定义对应的POJO,就进行参数的封装操作。
public List<User> findUser1(Map<String, Object> map);
// 对应的SQL文件:
<select id="findUser1" parameterType="java.util.Map" resultType="com.tx.springboottestdemo.entity.User">
select * from user_test where userName = #{username} and realName = #{realname}
</select>
insert,update,delete
数据变更语句 insert,update 和 delete 在它们的实现中非常相似。
补充说明:
useGeneratedKeys、keyProperty
:如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就 OK 了。例如使用下列语句,这样每次插入数据时,就可以省略掉 id 列了。(注:当数据库中的字段不是自增的时,useGeneratedKeys 不起作用。)
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio})
</insert>
如果你的数据库还支持多行插入, 你也可以传入一个数组或集合,并返回自动生成的主键。
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (name, age) VALUES
<foreach collection="list" item="user" index="index" separator="," >
(#{user.name}, #{user.age})
</foreach>
</insert>
keyColumn
:用于指定数据库table中的主键。通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。- 插入的时候系统时间值可以直接用
now()
xml语法
总体说来mybatis 动态SQL 语句主要有以下几类:
- if 语句 (简单的条件判断)
- choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似.
- trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)
- where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误)
- set (主要用于更新时)
- foreach (在实现 mybatis in 语句查询时特别有用)
if 语句
在mapper接口中定义一个函数名,其中@Param
指定xml中对应的名称,后面会用到。
List<Map<String,Object>> getByItem(@Param("item") String item, @Param("val") String val);
在controller类和service类中:
@RequestMapping(value = "/getByItem")
public Result getByItem(String item, String value){
return userService.getByItem(item, value);
}
public Result getByItem(String item, String value){
return Result.ok(userMapper.getByItem(item, value));
}
Result 类是封装的一个返回类,可以先不用管。
XML中:
<select id="getByItem" resultType="User">
select * from `scau_log` where
<if test="item == '_id'">
_id=#{val}
</if>
</select>
postman发送:
但如果item!=_id
,则语句就变成了select * from
scau_logwhere
而报错,可以使用<where >
。
where 语句
where
元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
将上面的xml改为如下即可:
<select id="getByItem" resultType="User">
select * from `scau_log`
<where>
<if test="item == '_id'">
_id=#{val}
</if>
</where>
</select>
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim
元素来定制 where 元素的功能。
trim 语句
和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides、suffixOverrides
属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides(suffixOverrides)
属性中指定的内容,并且插入 prefix(suffix)
属性中指定的内容。
set 语句
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。
<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 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
来看看与 set 元素等价的自定义 trim 元素,注意我们覆盖了后缀值设置,并且自定义了前缀值。:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
foreach
对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
<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>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item
)和索引(index
)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
你可以将任何可迭代对象(如 List
、Set
等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index
是当前迭代的序号,item
的值是本次迭代获取到的元素。当使用Map
对象(或者 Map.Entry 对象的集合)时,index
是键,item
是值。
foreach元素的属性主要有item,index,collection,open,separator,close。
- item表示集合中每一个元素进行迭代时的别名。
- index指定一个名字,用于表示在迭代过程中,每次迭代到的位置。
- open表示该语句以什么开始。
- separator表示在每次进行迭代之间以什么符号作为分隔符。
- close表示以什么结束。
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
- 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
- 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
- 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。
// 单参数List的类型
public List<User> dynamicForeachTest(List<Integer> ids); // 对应的Mapper
<select id="dynamicForeachTest" resultType="com.mybatis.entity.User">
select * from t_user where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
// 数组类型的参数
public List<User> dynamicForeach2Test(int[] ids); // 对应的Mapper
<select id="dynamicForeach2Test" resultType="com.mybatis.entity.User">
select * from t_user where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
// Map类型的参数
public List<User> dynamicForeach3Test(Map<String, Object> params); // 对应的Mapper
<select id="dynamicForeach3Test" resultType="com.mybatis.entity.User">
select * from t_user where username like '%${username}%' and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
choose(when,otherwize) 语句
<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 1 = 1
<choose>
<when test="title != null">
and title = #{title}
</when>
<when test="content != null">
and content = #{content}
</when>
<otherwise>
and owner = "owner1"
</otherwise>
</choose>
</select>
when
元素表示当when
中的条件满足的时候就输出其中的内容,当when中有条件满足的时候,就会跳出choose
,即所有的when
和otherwise
条件中,只有一个会输出;当所有的条件都不满足的时候就输出otherwise
中的内容。
所以上述语句的意思非常简单,当title!=null
的时候就输出and titlte = #{title}
,不再往下判断条件,当title
为空且content!=null
的时候就输出and content = #{content}
,当所有条件都不满足的时候就输出otherwise
中的内容。
模糊查找
<if test="infoTemplateAll.templateName != null">
AND template_name LIKE '%${infoTemplateAll.templateName}%'
</if>
批量插入
<insert id="insertSelectives" parameterType="java.util.List">
INSERT INTO oap_detail_income
(
income_seq_num,
interest_terms
)
VALUES
<foreach collection="list" item="file" index="index"
separator=",">
(
#{file.incomeSeqNum},
<choose>
<when test="file.interestTerms != null">
#{file.interestTerms},
</when>
<otherwise>
0,
</otherwise>
</choose>
)
</foreach>
</insert>
… …
其他
MySQL时区错误
打开my.ini,搜索[mysqld],在[mysql]节点下加上这一行
default-time-zone='+08:00'
重启mysql服务
IDEA快速创建xml
File -> Setting -> File and Code Templates - > ‘+’号新建 -> 填写Name和Extension -> 自行填写内容 -> OK
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xx.mapper.xxMapper">
<select id="GetUserByID" parameterType="int" resultType="com.test.springtest.dao.MUser">
select * from `student` where id = #{id}
</select>
<insert
id="saveUser" parameterType="com.test.springtest.User" useGeneratedKeys="true">
insert into student(NAME,AGE) values (#{name},#{age})
</insert>
</mapper>