利用MyBatis框架操作数据库1:https://developer.aliyun.com/article/1521801
like 模糊查询
在sql语句进行查询时也会经常用到like模糊查询,%表示0或多个字符,_表示一个字符,那么先使用?{}占位符来查询username中含有‘a’字符的用户信息。
xml的select标签的信息如下:
<select id="getUserInfoByLike" resultType="com.example.mybatisdemo.model.UserInfo"> select * from userinfo where username like %?{username}% </select>
测试结果:
并不能完成直接替换,那么使用#{}参数占位符来进行测试,测试结果如下:
这两种参数占位符都不能直接实现模糊查询,就需要使用mysql中的内置函数concat来进行处理,将xml文件中的select标签的内容修改如下:
<!-- 模糊查询用户信息--> <select id="getUserInfoByLike" resultType="com.example.mybatisdemo.model.UserInfo"> select * from userinfo where username like concat('%',#{username},'%') </select>
测试结果如下:
多表查询
上述的操作都是在单表的基础上进行,但是查询还存在多表查询,常见的表关系有一对一、一对多和多对多,那么利用MyBatis就可以实现一对一和一对多的多表查询。
一对一的多表查询
在mycnblog数据库中有userinfo和articleinfo表,两个表的字段设置如下所示:
其中articleinfo表的uid对应userinfo表的的id。
查询文章对应的用户信息。
首先在model包下创建ArticleInfo类,将articleinfo表的字段作为ArticleInfo类的属性,并添加UserInfo属性。
@Data public class ArticleInfo { private int id; private String title; private String content; private String createtime; private String updatetime; private int uid; private int rcount; private int state; private UserInfo userInfo; }
在Mapper包下创建ArticleMapper接口,定义id获取文章信息的方法:
//通过文章id来获取文章信息 public ArticleInfo getUserInfoByArticleInfoId(@Param("id") Integer id);
在mybatis包下创建ArticleMapper.xml文件,添加select标签,由于要实现多表查询,select标签的ResultType标签就无法满足需求了,就需要添加一个resultMap标签, 其id为标签名,type为要映射的实体类的路径,在该标签中设置主键(id)和其他普通的字段(result),其中column为数据库字段名,property为程序中的属性名,并且在UserMapper.xml文件中也添加resultMap标签,然后在ArticleMapper.xml的resultMap标签中继续添加association标签,property代表要连接的表在程序中的属性名,resultMap为UserMapper.xml文件中的resultMap标签名称,由于userinfo表和articleinfo表中有同名的字段名,就使用columnPrefix属性,表示在原有字段名前添加设置的columnPrefix属性值,UserMapper.xml文件的resultMap标签如下:
<resultMap id="baseMapper" type="com.example.mybatisdemo.model.UserInfo"> <!--设置主键属性--> <id column="id" property="id"></id> <!--设置其他属性--> <result column="username" property="username"></result> <result column="password" property="password"></result> <result column="photo" property="photo"></result> <result column="username" property="username"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="state" property="state"></result> </resultMap>
ArticleMapper.xml文件的内容如下:
<resultMap id="baseMapper" type="com.example.mybatisdemo.model.ArticleInfo"> <!--设置主键--> <id column="id" property="id"></id> <!-- 设置其他属性--> <result column="title" property="title"></result> <result column="content" property="content"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="uid" property="uid"></result> <result column="rcount" property="rcount"></result> <result column="state" property="state"></result> <association property="userInfo" resultMap="com.example.mybatisdemo.mapper.UserMapper.baseMapper" columnPrefix="u_"> </association> </resultMap> <select id="getUserInfoByArticleInfoId" resultMap="baseMapper"> select a.*,u.id u_id,u.username u_username,u.password u_password,u.photo u_photo from articleinfo a left join userinfo u on a.uid=u.id where a.id=#{id} </select>
最后在生成的test类中编写测试方法:
//通过id获取文章信息,实现一对一的多表查询 @Test void getUserInfoByArticleInfoId() { ArticleInfo articleInfo = articleMapper.getUserInfoByArticleInfoId(1); log.info(String.valueOf(articleInfo)); }
测试结果:
日志中的信息:
createtime等字段为null因为在查询的时候就没有select这些字段。
一对多的多表查询
一个用户对应多篇文章,就需要使用一对多的多表查询。
先在UserInfo类中增加一个存放文章信息的集合:
private List<ArticleInfo> atrlist;
然后再UserMapper接口中定义查询方法:
//根据id查询用户信息,并实现一对多的多表查询 public UserInfo getUserInfoAndArtInfoById(@Param("id") Integer id);
在UserMapper.xml文件的resultMap标签中添加collection标签,其属性与association标签的属性值类似:
<collection property="atrlist" resultMap="com.example.mybatisdemo.mapper.ArticleMapper.baseMapper" columnPrefix="a_"> </collection>
再添加select标签:
<!-- 通过id获取到用户信息,实现一对多的多表查询--> <select id="getUserInfoAndArtInfoById" resultMap="baseMapper"> select u.*,a.id a_id,a.title a_title,a.content a_content from userinfo u left join articleinfo a on u.id=a.uid where u.id=#{id} </select>
在生成的测试类中编写如下的代码:
@Test void getUserInfoAndArtInfoById() { UserInfo userInfo = userMapper.getUserInfoAndArtInfoById(1); log.info(String.valueOf(userInfo)); }
测试结果:
日志中的文章信息如下:
四、动态SQL
在上述的操作中都使用的是固定的参数,并且有时会多写,等都会出现报错,但动态SQL就能很好的解决上述问题。
if标签
if标签的test属性可以判断参数是否有值,如果没有值,就会隐藏if标签中的参数。
非必传的参数就可以使用if标签。
例如新增一个Userinfo信息,username和id为必传信息,但是photo信息为非必传。
那么UserMapper的insert标签如下:
<insert id="addUserInfoByIf"> insert into userinfo(username,password <if test="photo!=null"> ,photo </if>) values(#{username},#{password} <if test="photo!=null"> ,#{photo} </if> ) </insert>
在传入参数的时候未传入photo参数:
@Test void addUserInfoByIf() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("老6"); userInfo.setPassword("1234"); int i = userMapper.addUserInfoByIf(userInfo); Assertions.assertEquals(1,i); }
测试结果:
trim标签
trim标签有如下的属性:
- prefix:整个语句块,以prefix的值作为前缀;
- suffix:整个语句块,以suffix的值作为后缀;
- prefixOverrides:表示整个语句块要去除掉的前缀;
- suffixOverrides:表示整个语句块要去除掉的后缀。
那么, 上面新增一个Userinfo信息就可以使用trim标签,修改xml标签的内容如下:
<insert id="addUserInfoByIf"> insert into userinfo <trim prefix="(" suffix=")" suffixOverrides=","> username,password <if test="photo!=null"> ,photo </if> </trim> values <trim prefix="(" suffix=")" suffixOverrides=","> #{username},#{password} <if test="photo!=null"> ,#{photo} </if> </trim> </insert>
测试结果:
where标签
where标签可以实现查询中的where语句替换,如果where中没有任何查询条件,那么就会删除where语句,如果有查询条件,就会自动生成相应的sql语句,并可以自动去除最前面的and标签,where标签通常搭配if标签来进行使用。
例如利用名字和密码查询用户信息:
UserMapper.xml的查询标签如下所示:
<!--通过where标签查询用户信息--> <select id="getUserInfoByWhere" resultType="com.example.mybatisdemo.model.UserInfo"> select * from userinfo <where> <if test="username!=null"> username=#{username} </if> <if test="password!=null"> and password=#{password} </if> </where> </select>
当传入用户名和密码之后测试结果如下:
where标签也可以使用<trim>标签进行替换:
<trim prefix="where" suffixOverrides="and">
</trim>
set标签
set标签是针对update更新语句的,可以代替update标签中的set关键字来完成。
set标签通常需要搭配if标签来进行使用。
例如利用id来修改用户信息。
在xml文件中的update标签如下:
<update id="updateUserInfoById"> update userinfo <set> <if test="username!=null"> username=#{username}, </if> <if test="password!=null"> password=#{password} </if> </set> where id=#{id} </update>
在测试类中的测试代码如下:
@Test void updateUserInfoById() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("王五"); userInfo.setPassword("9087"); userInfo.setId(3); int i = userMapper.updateUserInfoById(userInfo); Assertions.assertNotNull(i); }
测试结果:
set标签也可以用trim标签进行替代
<trim prefix="set" suffixOverrides=",">
</trim>
foreach标签
对集合遍历时通常会使用该标签,在in关键字之后通常使用,该标签有如下的属性:
collection:绑定方法参数的集合,如List、Set、Map以及数组等;
item:遍历时的每个对象;
open:语句块开头的字符串;
close:语句块结束的字符串;
separator:每次遍历之间的字符串。
例如删除id在指定集合的用户信息:
xml文件中的delete标签如下:
<delete id="deleteUserInfoByList"> delete from userinfo where id in <foreach collection="list" item="uid" open="(" close=")" separator=","> #{uid} </foreach> </delete>
在生成的test类编写的测试代码如下:
@Test void deleteUserInfoByList() { List<Integer> list = new LinkedList<>(); list.add(4); list.add(3); list.add(5); int i = userMapper.deleteUserInfoByList(list); log.info(String.valueOf(i)); }
测试结果: