Mybatis实战2:标签详解
一、select标签
1.标签属性
- id 唯一的名称,对应dao中mapper的接口名称
- paramterType 定义传入的参数类型
- resultType 返回数据类型对应实体类
- resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用
- flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false
- useCache 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:true
- timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动),若设置10,则表示10秒内数据库没有返回结果就抛出异常
- fetchSize 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动),比如设置为20,而你要查询的总记录是100条,驱动会每次批量查询20条,共查询5次,myabtis会将这5次结果聚合一起返回100条。注意Mysql是不支持fetchSize的
- statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED
- resultSetType FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)
- databaseId 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
- resultOrdered 这个设置仅针对嵌套结果 select 语句适用:如果为true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至导致内存不够用。默认值:false。
- resultSets 这个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。
2.查询示例
1.简单查询
mapper接口
// 根据 id 获得数据库中的 username 字段的值
String getUserNameById(Integer id);
mapper.xml
<!--
指定 resultType 返回值类型时 String 类型的,
string 在这里是一个别名,代表的是 java.lang.String
对于引用数据类型,都是将大写字母转小写,比如 HashMap 对应的别名是 'hashmap'
基本数据类型考虑到重复的问题,会在其前面加上 '_',比如 byte 对应的别名是 '_byte'
-->
<select id="getUserNameById" resultType="java.lang.String">
select user_name from user_info where id = #{id}
</select>
2.查询返回JavaBean
返回Java实体类可以使用resultType
属性
多个查询条件,可以使用@Param
来指定
mapper接口
// 多个查询条件,可以使用
UserInfo selectByNamePwd(@Param("userName") String userName, @Param("password") String password);
<!--通过用户名和密码查询-->
<select id="selectByNamePwd" resultType="com.gqlofe.userinfo.bean.entity.UserInfo">
select
<include refid="Base_Column_List" />
from user_info
where user_name = #{userName} and password = #{password}
</select>
3.返回list类型
mapper方法返回类型是List,则查询的结果就是List,xml中resultType指定的是返回List的元素的类型
List<UserInfo> selectAll();
<select id="selectAll" resultType="com.gqlofe.userinfo.bean.entity.UserInfo">
select * from user_info
</select>
4.返回Map类型
- 如果查询的结果是一条,我们可以把查询的数据以{表字段名, 对应的值}方式存入到Map中
MyBatis 还支持将查询的数据封装成Map
。其中key是数据库表字段名,即是下划线格式
// 根据 id 查询信息,并把结果信息封装成 Map
Map<String, Object> getMapById(Integer id);
<select id="getMapById" resultType="hashmap">
select * from user_info where id = #{id}
</select>
- 如果查询的结果是多条数据,我们也可以把查询的数据以{表中某一字段名, JavaBean}方式来封装成
Map
。
@MapKey
中的值表示用数据库中的哪个字段名作 key
@MapKey("id")
Map<Integer, UserInfo> getAllUserInfoAsMap();
<!--本可以使用resultType="com.gqlofe.userinfo.bean.entity.UserInfo"-->
<!--但由于数据库字段名和实体类属性名不一致,所以使用resultMap,表示map的value的类型-->
<select id="getAllUserInfoAsMap" resultMap="BaseResultMap">
select * from user_info
</select>
二、insert,update,delete标签
属性名称 | 释义 | 示例 |
---|---|---|
id | 唯一的名称,对应dao中mapper的接口名称 | selectById |
paramterType | 定义传入的参数类型 | long |
flushCache | 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false | fasle |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动),若设置10,则表示10秒内数据库没有返回结果就抛出异常 | 10 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED | PREPARED |
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server这样的关系数据库管理系统的自动递增字段, oracle使用序列是不支持的,通过selectKey可以返回主键),默认值:false。 | true |
keyProperty | (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 | id |
keyColumn | (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 | id |
databaseId | 如果配置了 databaseIdProvider,MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
三、sql标签
定义一些常用的sql语句片段
<sql id="selectParam">
id, username, password, sex, birthday, address
</sql>
四、include 标签
引用其他的常量,通常和sql一起使用
<select>
select <include refid="selectParam"></include>
from user_info
</select>
五、if 标签
基本都是用来判断值是否为空,注意Integer
的判断,mybatis会默认把0变成 ‘’
<if test="item != null and item != ''"></if>
<!-- 如果是Integer类型的需要把and后面去掉或是加上or-->
<if test="item != null"></if>
<if test="item != null and item != '' or item == 0"></if>
六、别名typeAliases标签
经常使用的类型可以定义别名,方便使用,mybatis也注册了很多别名方便我们使用,详情见底部
<typeAliases>
<typeAlias type="com.gqlofe.userinfo.bean.entity.UserInfo" alias="User"/>
</typeAliases>
七、where标签
当使用if
标签进行条件判断时有可能第一个条件不满足,会导致where语句中多一个and 或者or,如下:
<select id="selectByNamePwd" resultType="com.gqlofe.userinfo.bean.entity.UserInfo">
select
<include refid="Base_Column_List" />
from user_info
where
<if test="userName != null">
user_name = #{userName}
</if>
<if test="password != null">
and password = #{password}
</if>
</select>
如果userName= null,则sql语句就变成
select * from user_info where and password = #{password}
显然有问题,where
标签可以去除where语句中的第一个and 或 or。
用法:
<select id="selectByNamePwd" resultType="com.gqlofe.userinfo.bean.entity.UserInfo">
select
<include refid="Base_Column_List" />
from user_info
<where>
<if test="userName != null">
user_name = #{userName}
</if>
<if test="password != null">
and password = #{password}
</if>
</where>
</select>
八、set标签
update语句中,set标签可以去除多余的逗号,用法:
<update id="updateByPrimaryKeySelective" parameterType="com.gqlofe.userinfo.bean.entity.UserInfo">
update user_info
<set>
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="password != null">
password = #{password,jdbcType=VARCHAR},
</if>
<if test="phone != null">
phone = #{phone,jdbcType=VARCHAR},
</if>
<if test="icon != null">
icon = #{icon,jdbcType=VARCHAR},
</if>
<if test="sex != null">
sex = #{sex,jdbcType=INTEGER},
</if>
<if test="age != null">
age = #{age,jdbcType=INTEGER},
</if>
<if test="birthday != null">
birthday = #{birthday,jdbcType=BIGINT},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
九、trim标签
where
标签只能去除第一个and或or,不够灵活,trim标签功能更加强大。
trim标签的属性如下:
- prefix 在trim标签内容前面加上前缀
- suffix 在trim标签内容后面加上后缀
- prefixOverrides 移除前缀内容。即 属性会忽略通过管道分隔的文本序列,多个忽略序列用 “|” 隔开。它带来的结果就是所有在 prefixOverrides 属性中指定的内容将被移除。
- suffixOverrides 移除前缀内容。
<insert id="insertSelective" parameterType="UserInfo" useGeneratedKeys="true" keyProperty="id">
insert into user_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="userName != null">
user_name,
</if>
<if test="password != null">
password,
</if>
<if test="phone != null">
phone,
</if>
<if test="icon != null">
icon,
</if>
<if test="sex != null">
sex,
</if>
<if test="age != null">
age,
</if>
<if test="birthday != null">
birthday,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="userName != null">
#{userName,jdbcType=VARCHAR},
</if>
<if test="password != null">
#{password,jdbcType=VARCHAR},
</if>
<if test="phone != null">
#{phone,jdbcType=VARCHAR},
</if>
<if test="icon != null">
#{icon,jdbcType=VARCHAR},
</if>
<if test="sex != null">
#{sex,jdbcType=INTEGER},
</if>
<if test="age != null">
#{age,jdbcType=INTEGER},
</if>
<if test="birthday != null">
#{birthday,jdbcType=BIGINT},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
</trim>
</insert>
十、foreach标签
foreach元素的属性主要有item,index,collection,open,separator,close.
- collection 要做foreach的对象,作为入参时,List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键。当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = "ids".如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id",必填
- item 合中元素迭代时的别名,必选
- index 在list和数组中,index是元素的序号,在map中,index是元素的key,可选
- open foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。可选
- separator 元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样,可选。
- close foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。可选
<select id="countByUserList" resultType="_int" parameterType="list">
select count(*) from user_info
<where>
id in
<foreach item="item" collection="list" separator="," open="(" close=")" index="">
#{item.id, jdbcType=NUMERIC}
</foreach>
</where>
</select>
<select id="dynamicForeach2Test" resultType="Blog">
select * from t_blog where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
十一、choose,when,otherwise标签
功能有点类似于Java中的 swicth - case - default
<select id="getUser" resultType="com.cat.pojo.User">
SELECT * FROM user
<where>
<choose>
<when test="id != null and test.trim() != '' ">
id = #{id}
</when>
<when test="name != null and name.trim() != '' ">
name = #{name}
</when>
<otherwise>
age = 17
</otherwise>
</choose>
</where>
</select>
七、resultMap标签
在平时的开发中,我们没有办法一定能保证表中的字段名和表对应实体类的属性名称是完全相同的,resultMap可以解决表字段和实体属性名不一致的问题。
表结构
CREATE TABLE `user_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '密码',
`phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机',
`icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '头像链接地址',
`sex` int(5) NOT NULL DEFAULT '3' COMMENT '性别: 1 男,2 女, 3 保密',
`age` int(5) NOT NULL DEFAULT '0' COMMENT '年龄',
`birthday` bigint(15) DEFAULT '0' COMMENT '出生年月',
`create_time` bigint(15) NOT NULL DEFAULT '0' COMMENT '创建时间',
`update_time` bigint(15) NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `index_name` (`user_name`) USING BTREE COMMENT '用户名唯一索引',
KEY `index_phone` (`phone`) USING BTREE COMMENT '手机号索引'
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户表';
实体类
@Data
@Accessors(chain = true)
public class UserInfo implements Serializable {
// 用户id
private Integer id;
// 用户名
private String userName;
// 密码
private String password;
// 手机
private String phone;
// 头像链接地址
private String icon;
// 性别: 1 男,2 女, 3 保密
private Integer sex;
// 年龄
private Integer age;
// 出生年月
private Long birthday;
// 创建时间
private Long createTime;
// 更新时间
private Long updateTime;
private static final long serialVersionUID = 1L;
}
可以看出数据库字段一般是以下划线的格式,而Java实体类是以驼峰格式,为了保证能正确映射,就需要使用resultMap标签
<resultMap id="BaseResultMap" type="com.gqlofe.userinfo.bean.entity.UserInfo">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="user_name" jdbcType="VARCHAR" property="userName" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="phone" jdbcType="VARCHAR" property="phone" />
<result column="icon" jdbcType="VARCHAR" property="icon" />
<result column="sex" jdbcType="INTEGER" property="sex" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="birthday" jdbcType="BIGINT" property="birthday" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
</resultMap>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user_info
where id = #{id,jdbcType=INTEGER}
</select>
使用resultMap将数据库字段名和Java实体类属性名一一映射,在查询sql中使用resultMap=BaseResultMap
,其中 BaseResultMap 是resultMap的id。