需求缘起
第一小节我们用了纯 xml 的形式来使用MyBatis,第二节中我们使用了接口和注解(注解不能单独使用)相结合的形式来操作MyBatis,那有没有可能使用 xml 和 接口结合起来使用呢?答案是肯定的,而且这种用法会更加的灵活强大,使用纯xml的时候,当参数复杂且为多个的时候,使用xml方式很不方便,而且无法避免很多重复的代码;当使用接口和注解的相结合的时候又失去了灵活性(参考动态SQL那一小节);当使用xml和接口相结合的时候就可以完美解决这两者缺点,这一节我们就来学下 xml 结合接口的使用方式
本小节代码
mybatis-demo-article(4)
1.定义接口
使用第二节中的 UserMapper 接口,去掉其中的 sql 注解,另外添加第三节中用到的几个接口,结果如下
package com.mybatis.demo.mapper;
import com.mybatis.demo.model.UserInfo;
import java.util.List;
/**
* @auther kklu
* @date 2019/10/14 12:18
* @describe
*/
public interface UserInfoMapper {
//根据用户名和性别查询
List<UserInfo> selectUserInfoByUsernameAndSex(UserInfo userInfo) throws Exception;
//根据 id 修改 user_info 表数据
void updateUserInfoById(UserInfo userInfo) throws Exception;
//根据某一个条件查询
List<UserInfo> selectUserInfoByChoose(UserInfo userInfo) throws Exception;
//根据一组用户 id 查询用户
List<UserInfo> selectUserByListId(UserInfoForm userInfoForm) throws Exception;
//根据 id 查询 user_info 表数据
UserInfo selectUserInfoById(int id) throws Exception;
//查询 user_info 表所有数据
List<UserInfo> selectUserInfoAll() throws Exception;
//根据 id 查询 user_info 表数据
List<UserInfo> selectLikeUserName(String username) throws Exception;
//向 user_info 表插入一条数据
void insertUserInfo(UserInfo userInfo) throws Exception;
//根据 id 删除 user_info 表数据
void deleteUserInfoById(int id) throws Exception;
}
2.注册接口
在配置文件 mybatis-config.xml mybatis-config.xml 中修改 标签中的 参数
<mappers>
<!--xxxMapper.java 接口文件的路径,注册单个接口的方式-->
<!--<mapper class="com.mybatis.demo.mapper.UserInfoMapper"/>-->
<!--注册多个接口的方式,该包名下所有的接口-->
<package name="com.mybatis.demo.mapper"/>
</mappers>
3.编写xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间是接口的全类名-->
<mapper namespace="com.mybatis.demo.mapper.UserInfoMapper">
<!-- 定义 sql 片段 -->
<sql id="selectUserByUserNameAndSexSQL">
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
</sql>
<!-- 根据 id 查询 user_info 表中的数据
id:唯一标识符,此文件中的id值不能重复
resultType:返回值类型,一条数据库记录也就对应实体类的一个对象
parameterType:参数类型,也就是查询条件的类型
-->
<!--在配置文件 mybatis-config.xml 中如果没有配置别名,则需要写全类名-->
<select id="selectUserInfoByUsernameAndSex" resultType="UserInfo" parameterType="UserInfo">
select * from user_info
<trim prefix="where" prefixOverrides="and | or">
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="selectUserByUserNameAndSexSQL"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</trim>
</select>
<!-- 根据 id 更新 user_info 表的数据 -->
<update id="updateUserInfoById" parameterType="UserInfo">
update user_info u
<!--prefix:标签; suffixOverrides:去掉最后一个逗号(也可以是其他的标记)-->
<trim prefix="set" suffixOverrides=",">
<if test="username != null and username != ''">
u.username = #{username},
</if>
<if test="sex != null and sex != ''">
u.sex = #{sex},
</if>
</trim>
where id=#{id}
</update>
<select id="selectUserInfoByChoose" resultType="UserInfo" parameterType="UserInfo">
select * from user_info
<where>
<choose>
<when test="id !='' and id != null">
id=#{id}
</when>
<when test="username !='' and username != null">
and username=#{username}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
<select id="selectUserByListId" parameterType="com.mybatis.demo.model.UserInfoForm" resultType="UserInfo">
select * from user_info
<where>
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from user where 1=1 and id in (1,2,3)
-->
<foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
#{id}
</foreach>
</where>
</select>
<select id="selectUserInfoById" resultType="UserInfo" parameterType="int">
<!-- 这里和普通的sql 查询语句差不多,对于只有一个参数,后面的 #{id}表示占位符,里面不一定要写id,写啥都可以,但是不要空着,如果有多个参数则必须写pojo类里面的属性 -->
select * from user_info where id = #{id}
</select>
<select id="selectUserInfoAll" resultType="UserInfo">
select * from user_info
</select>
<select id="selectLikeUserName" resultType="UserInfo" parameterType="String">
select * from user_info where username like '%${value}%'
<!-- select * from user where username like #{username} -->
</select>
<!-- 向 user_info 表插入一条数据 -->
<insert id="insertUserInfo" parameterType="UserInfo">
insert into user_info(id,username,password,high,age,sex)
value(#{id},#{username},#{password},#{high},#{age},#{sex})
</insert>
<!-- 根据 id 删除 user_info 表的数据 -->
<delete id="deleteUserInfoById" parameterType="int">
delete from user_info where id=#{id}
</delete>
</mapper>
4.测试
package com.mybatis.demo.mapper;
import com.mybatis.demo.model.UserInfo;
import com.mybatis.demo.model.UserInfoForm;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* @auther kklu
* @date 2019/9/29 15:49
* @describe
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class UserInfoMapperTest {
private static SqlSessionFactory sqlSessionFactory;
private static SqlSession sqlSession = null;
private static UserInfoMapper userInfoMapper;
@BeforeClass
public static void init() {
try {
//将工具类读入 reader
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//创建 SqlSessionFactory 对象,该对象包含了mybatis-config.xml相关配置信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
sqlSession = sqlSessionFactory.openSession();
userInfoMapper = sqlSession.getMapper(UserInfoMapper.class);
reader.close();
} catch (IOException ignore) {
ignore.printStackTrace();
}
}
@Test
public void testSelectUserInfoByUsernameAndSex() {
try {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("Jack");
userInfo.setSex(1);
List<UserInfo> result = userInfoMapper.selectUserInfoByUsernameAndSex(userInfo);
log.info("result={}", result);
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
//根据 id 更新 user 表的数据
@Test
public void testUpdateUserInfoById() {
try {
//如果设置的 id不存在,那么数据库没有数据更改
UserInfo userInfo = new UserInfo();
userInfo.setId(4L);
userInfo.setUsername("令狐冲");
// userInfo.setSex(1);
userInfoMapper.updateUserInfoById(userInfo);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
//根据 id 更新 user 表的数据
@Test
public void testSelectUserInfoByChoose() {
try {
UserInfo userInfo = new UserInfo();
// userInfo.setId(4L);
// userInfo.setUsername("Text");
userInfo.setSex(1);
List<UserInfo> listUser = userInfoMapper.selectUserInfoByChoose(userInfo);
for (UserInfo info : listUser) {
log.info("info={}", info);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
@Test
public void testSelectUserByListId() {
try {
UserInfoForm userInfoForm = new UserInfoForm();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(50);
userInfoForm.setIds(ids);
List<UserInfo> listUser = userInfoMapper.selectUserByListId(userInfoForm);
for (UserInfo info : listUser) {
log.info("info={}", info);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
@Test
public void testSelectUserInfoById() {
try {
UserInfo listUser = userInfoMapper.selectUserInfoById(4);
log.info("info={}", listUser);
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
@Test
public void testSelectUserInfoAll() {
try {
List<UserInfo> listUser = userInfoMapper.selectUserInfoAll();
for (UserInfo info : listUser) {
log.info("info={}", info);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
@Test
public void testSelectLikeUserName() {
try {
List<UserInfo> listUser = userInfoMapper.selectLikeUserName("明");
for (UserInfo userInfo : listUser) {
log.info("userInfo={}", userInfo);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
//向 user 表中插入一条数据
@Test
public void testInsertUserInfo() {
try {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("王二");
userInfo.setPassword("123456");
userInfo.setSex(1);
userInfo.setAge(21);
userInfo.setHigh(175);
userInfoMapper.insertUserInfo(userInfo);
//提交插入的数据
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
//根据 id 删除 user 表的数据
@Test
public void testDeleteUserInfoById() {
try {
userInfoMapper.deleteUserInfoById(1);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
//不要忘记关闭 sqlSession
sqlSession.close();
}
}
}
5.注意事项
- UserInfoMapper.xml 中的命名空间是接口的全类名,否则会找不到
- UserInfoMapper.java 接口与 UserInfoMapper.xml 所在的包名要一致,其中 UserInfoMapper.xml 也可以放在reourcces 下面,但是要建一个相同的包名
- UserInfoMapper.java 接口中的方法要与 UserInfoMapper.xml 中定义的id保持一致
- UserMapper接口输入参数类型要和 UserMapper.xml 中定义的 parameterType 一致
- UserMapper接口返回数据类型要和 UserMapper.xml 中定义的 resultType 一致
6.总结
简单总结下使用MyBatis的几种方式
- 接口可以单独使用
- 注解不能单独使用,必须结合接口使用
- 接口不能单独使用,可以结合XML 或者注解使用