一.什么是Mybatis?
是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
二.什么是持久化?
将内存中数据保存在磁盘中
三.什么是持久层?
利用Mybatis操作代码Mapper/dao,实现数据的持久化
四.什么是高级映射?
对象与数据表的映射
对象中属性与数据表的字段映射
总结: Mybatis是持久层框架,内部整合了JDBC,以对象的方式操作数据库.
五.创建Mybatis项目
5.1新建项目
5.2导入pom.xml依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--添加lombok的包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
5.3安装插件
查看链接即可harrylyj.blog.csdn.net/article/det…
5.4链接数据库
#配置端口号
server:
port: 8091
#管理数据源
spring:
datasource:
#高版本驱动使用
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
#设定用户名和密码
username: root
password: root
#SpringBoot整合Mybatis-plus
mybatis:
#指定别名包
type-aliases-package: com.jt.pojo
#扫描指定路径下的映射文件
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
# 一二级缓存默认开始 所以可以简化
#打印mysql日志
logging:
level:
com.jt.mapper: debug
5.5项目的目录
六.增删改查
6.1Mybatis新增
6.1.1 新增测试案例
@Test
public void testInsert(){
User user = new User();
user.setId(100).setName("元宵节").setAge(18).setSex("女");
//写法1: 不需要服务器返回值
userMapper.saveUser(user);
//写法2: 需要返回值,返回影响的行数
int rows = userMapper.saveUser2(user);
System.out.println("影响的行数:"+rows);
}
6.1.2编辑Mapper接口文件
void saveUser(User user);
int saveUser2(User user);
6.1.3编辑Mapper映射文件
<!--1.新增操作
语法:
1.取值操作 #{属性名称}
2.只有查询需要写resultType
3.如果是"更新"操作可以自动返回影响的行数
4.#{id}:填写的值要与
-->
<insert id="saveUser" >
insert into demo_user(id,name,age,sex)
value (null,#{name},#{age},#{sex})
</insert>
<insert id="saveUser2">
insert into demo_user(id,name,age,sex)
value (null,#{name},#{age},#{sex})
</insert>
6.2Mybatis修改案例
6.2.1修改测试案例
/**
* 要求:将ID=232的数据,将name改为"清明节"
*/
@Test
public void testUpdate(){
User user = new User();
user.setId(232).setName("清明节");
userMapper.updateUserById(user);
}
6.2.2编写Mapper接口文件
void updateUserById(User user);
6.2.3编写Mapper映射文件
<!--
关于取值操作的说明: #{属性值},${属性值}
1.#号取值采用占位符的方式 更加安全 防止sql注入攻击!!!
2.$符一般的使用场景 以字段为参数时使用.
3.使用#号时,默认会添加一对""号
4.能使用#号 绝不用$
-->
<update id="updateUserById">
update demo_user set name=#{name}
where id = ${id}
</update>
6.3Mybatis查询案例
6.3.1查询测试案例
/**
* 根据Id查询数据 id=7
* 总结: 如果结果唯一,使用POJO对象接收
* 如果结果不唯一,使用List<POJO>集合接收
*/
@Test
public void testFindUserById(){
int id = 7;
User user = userMapper.findUserById(id);
System.out.println(user);
}
6.3.2编写Mapper接口文件
User findUserById(int id);
6.3.3编写Mapper映射文件
<select id="findUserById" resultType="com.jt.pojo.User">
select * from demo_user where id=#{id}
</select>
6.4Mybatis删除案例
6.4.1删除测试案例
@Test
public void testFindUserById(){
int id = 7;
User user = userMapper.findDeteleById(id);
System.out.println(user);
}
6.4.2编写Mapper接口文件
User findUserById(int id);
6.4.3编写Mapper映射文件
<delete id="findUserById">
delete * from demo_user where id=#{id}
</delete>
七.关于Mybatis的特殊用法
7.1Map用法
7.1.1编辑测试类
/**
* Mybatis Map查询
* 需求: 查询age>18 and age < 100的用户
* Sql: select * from demo_user where age>18 and age<100
* 难点: POJO对象无法传递多个同名属性!
* 解决方案: 如果遇到同名属性则可以封装为Map集合
*/
@Test
public void testFindByMap(){
Map map = new HashMap();
map.put("minAge",18);
map.put("maxAge",100);
List<User> list = userMapper.findUserByMap(map);
System.out.println(list);
}
7.1.2编写Mapper接口文件
List<User> findUserByMap(Map map);
7.1.3编写Mapper映射文件
<!--
取值用法: #{对象中的属性/Map中的key}
转义字符:
大于 > >
小于 < <
与号 & &
万能转义标签: <![CDATA[ 内容 ]]>
xml流文件 报文 更加安全 解析复杂
字节流信息: 直播!!!
-->
<select id="findUserByMap" resultType="com.jt.pojo.User">
<!--select * from demo_user where age>#{minAge} and age < #{maxAge}-->
<![CDATA[
select * from demo_user where age>#{minAge} and age < #{maxAge}
]]>
</select>
7.2关于#号与$符号区别
7.2.1测试案例
/**
* 指定字段查询数据
*/
@Test
public void testFindByColumn(){
String column = "age";
int value = 18;
Map map = new HashMap();
map.put("column",column);
map.put("value",value);
List<User> list = userMapper.findByColumn(map);
System.out.println(list);
}
7.2.2编写Mapper接口文件
List<User> findByColumn(Map map);
7.2.3编写Mapper映射文件
<!--使用$符 获取字段信息 -->
<select id="findByColumn" resultType="com.jt.pojo.User">
select * from demo_user where ${column}=#{value}
</select>
7.3@Param注解用法
7.3.1测试代码
/**
* 说明: 简化Map集合操作
* Mybatis中不允许直接传递多个数据,如果是多值需要转化为单值.\
1.将多值数据转化为POJO对象.\
2.将多值数据转化为Map集合. Mybatis为转化Map集合提供了注解@Param
*/
@Test
public void testFindByParam(){
int minId = 10;
int maxId = 100;
List<User> list = userMapper.findUserByMId(minId,maxId);
System.out.println(list);
}
7.3.2编写Mapper接口文件
List<User> findUserByMId(@Param("minId") int minId,
@Param("maxId") int maxId);
7.3.3编写Mapper映射文件
<select id="findUserByMId" resultType="com.jt.pojo.User">
select * from demo_user where id > #{minId} and id < #{maxId}
</select>
7.4模糊查询
7.4.1编辑测试类
/**
* 业务需求: 查询name中包含"君"字的数据
* Sql: select * from demo_user where name like "%君%"
*/
@Test
public void findUserByLike(){
String name = "君";
List<User> list = userMapper.findUserByLike(name);
System.out.println(list);
}
7.4.2编写Mapper接口文件
List<User> findUserByLike(String name);
7.4.3编写Mapper映射文件
<!--别名包: com.jt.pojo 只要定义成功之后,以后写类名即可-->
<select id="findUserByLike" resultType="User">
select * from demo_user where name like "%"#{name}"%"
</select>
7.5Sql简化标签
<!--
别名包: com.jt.pojo 只要定义成功之后,以后写类名即可
-->
<select id="findUserByLike" resultType="User">
<include refid="selectDemoUser"/> where name like "%"#{name}"%"
</select>
<!--Sql标签介绍:
可以将重复的/复杂的/特殊的Sql封装到Sql标签中
-->
<sql id="selectDemoUser">
select id,name,age,sex from demo_user
</sql>
7.6Mybatis的"集合"操作list/array/map
7.6.1业务需求
说明: Mybatis如果遇到批量操作,则可以使用集合的类型
案例: 查询id=1,3,4,5,6的数据
Sql: select * from demo_user where id in (1,3,4,5,6)
in的限定条件: 如果海量数据(500万)查询时不要使用in.尽可能使用主键查询.
//List ids = Arrays.asList(array);
@Test
public void findUserByIn(){
Integer[] array = {1,3,4,5,6};
List<User> list = userMapper.findUserByIn(array);
System.out.println(list);
}
7.6.2编辑Mapper接口文件
List<User> findUserByIn(Integer[] array);
7.6.3编辑Mapper映射文件
<!--
Mybatis集合操作
1."集合"的类型: array/list/Map集合
2. 目的:从集合中获取其中的数据. 一个一个取值
3. 方案: Mybatis提供了循环遍历的方式
4. 语法:
4.1collection需要遍历的数据
数组: collection="array"
List集合: collection="list"
Map<key,array/list>集合: collection="map中的key"
4.2 open/close 开始和接收标签
4.3 item: 定义取值的变量 通过#{xx}获取数据
4.4 separator: 分割符
-->
<select id="findUserByIn" resultType="User">
select * from demo_user where id in
<foreach collection="array" open="(" close=")"
item="id" separator=",">
#{id}
</foreach>
</select>
8.1主键自增
8.1.1方法一
<insert id="insertBook" useGeneratedKeys="true" keyProperty="id">
insert into t_book (b_name,author) values (#{name},#{author});
</insert>
这种方式比较简单,就是在插入节点上添加 useGeneratedKeys 属性,同时设置接收回传主键的属性。配置完成后,我们执行一个插入操作,插入时传入一个对象,插入完成后,这个对象的 id 就会被自动赋值,值就是刚刚插入成功的id。
8.1.2方法二
第二种方式则是利用MySQL自带的 last_insert_id() 函数查询刚刚插入的id
<insert id="insertBook">
<selectKey keyProperty="id" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_book (b_name,author) values (#{name},#{author});
</insert>
这种方式是在 insert 节点中添加 selectKey 来实现主键回填,实际上这种方式的功能更加丰富,因为 selectKey 节点中的 SQL 我们既可以在插入之前执行,也可以在插入之后执行(通过设置节点的 Order 属性为 AFTER 或者 BEFORE 可以实现),具体什么时候执行,还是要看具体的需求,如果是做主键回填,我们当然需要在插入 SQL 执行之后执行 selectKey 节点中的 SQL。
注意第二种方式一样也要通过设置 keyProperty 来指定将查询到的数据绑定到哪个属性上。
八.Mybatis-动态SQL
8.1 if-where标签
8.1.1 编写测试类
/**
* 需求: 根据对象中不为null的属性,查询数据
* 业务说明: 由于数据来源于前端服务器.参数可以是任意的数据,
* 但是要求后端能实现所有数据的查询. 一个方法通用!!!
*/
@Test
public void testFindUser(){
User user = new User();
user.setAge(3000).setSex("男");
List<User> list = userMapper.findUser(user);
System.out.println(list);
}
8.1.2编写Mapper接口文件
@Mapper //为接口创建代理对象,交给Spring容器管理
public interface UserMapper2 {
List<User> findUser(User user);
}
8.1.3编写Mapper映射文件
<?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.jt.mapper.UserMapper2">
<!--
Mybatis:动态sql语法 根据业务条件,动态拼接Sql
语法:
1. if标签: 如果判断为真 则拼接sql
2. where标签: 去除where后边多余1个and/or
-->
<select id="findUser" resultType="User">
select * from demo_user
<where>
<if test="id !=null">id = #{id}</if>
<if test="name !=null">and name = #{name}</if>
<if test="age !=null">and age = #{age}</if>
<if test="sex !=null">and sex = #{sex}</if>
</where>
</select>
</mapper>
8.2 if-set标签
编写测试类
/**
* 业务说明:
* 根据对象中不为null的属性进行更新操作,id当做唯一条件.
* 需求:
* 将id=5的用户的 name改为 御弟哥哥 年龄 18
*/
@Test
public void testUpdate(){
User user = new User();
user.setId(5).setName("御弟哥哥").setAge(18); //sex=null
userMapper.updateUser(user);
System.out.println("修改操作成功!!!");
}
编写Mapper接口
void updateUser(User user);
编写Mapper映射文件
<!--
思考: 如何做到通用
使用动态sql:根据对象中不为null的属性当做set条件
标签说明: set标签在修改操作中去除1个多余的,号
-->
<update id="updateUser">
update demo_user
<set>
<if test="name !=null">name=#{name},</if>
<if test="age !=null">age=#{age},</if>
<if test="sex !=null">sex=#{sex}</if>
</set>
where id=#{id}
</update>
8.3动态Sql-choose、when、otherwise
8.3.1编写测试类
说明: 如果不想使用所有的条件可以使用choose 类似于java中的switch 语法\
如果name有值,则按照name查询, if\
如果age有值,则按照age查询, else-if\
否则按照sex查询数据. else
@Test
public void testFindChoose(){
User user = new User();
user.setName("御弟哥哥").setAge(18).setSex("男");
List<User> list = userMapper.findUserChoose(user);
System.out.println(list);
}
8.3.2编写Mapper接口文件
List<User> findUserChoose(User user);
8.3.3编写Mapper映射文件
<!--分支结构的语法-->
<select id="findUserChoose" resultType="User">
select * from demo_user where
<choose>
<when test="name !=null">name=#{name}</when>
<when test="age !=null">age=#{age}</when>
<otherwise>sex = #{sex}</otherwise>
</choose>
</select>
| 标签属性 | 解释 |
|---|---|
| resultType | Sql语句执行的返回值 |
| parameterType | 参数类型 |
| id | 自定义 |
collerction|表示需要遍历的类型基本上只有:list,array,Map这三中写法。
index|表示循环的下标。
separator|表示每个对象的分隔符(也是进行下一次循环的标识符)。
item|表示当前循环对象。
open|以什么开头。
close|以什么结尾。
columnPrefix|"指定字段映射的前缀"
九.解决属性名和字段名不一致的问题
resultMap标签
<?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.jt.mapper.UserMapper3">
<!--
1.Sql 最好都小写 ctrl + shift + y
ctrl + shift + u
2.结果集映射必须与属性名称一致.
3.resultType适用于 单表查询&结果集字段与属性一致
4.如果resultType不满足要求,就是用resultMap完成数据的映射
-->
<select id="findAll" resultMap="resultUser">
select id as user_id,
name as user_name,
age user_age,
sex user_sex
from demo_user
</select>
<resultMap id="resultUser" type="User">
<!--id表示主键 必须添加-->
<id column="user_id" property="id"/>
<!--其它属性-->
<result column="user_name" property="name"/>
<result column="user_age" property="age"/>
<result column="user_sex" property="sex"/>
</resultMap>
</mapper>
1.可以通过sql语句 加别名的方式 与column保持一致
2.在#{id}中的字段要与property中的 保存一致 所以就是与实体类的属性一致
十.表关联查询
常见的表关联查询的关系
核心: 从一头出发,看向另一头
- 一对一 一个用户/一个ID 老公/老婆 一个员工对应一个部门
- 一对多 一个老师对应多个学生, 一个部门对应多个员工
- 多对一 多对一本质还是一对一
- 多对多 一个老师对应多个学生 一对多
一个学生对应多个老师 一对多 双向一对多
10.1一对一
10.1.1编写实体类
@SpringBootTest
public class TestMybatis4 {
@Autowired
private EmpMapper empMapper;
@Autowired
private DeptMapper deptMapper;
//主对象 员工和部门一对一
@Test
public void testOneToOne(){
List<Emp> list = empMapper.findEmp();
System.out.println(list);
}
}
10.1.2编写Mapper接口文件
@Mapper
public interface EmpMapper {
List<Emp> findEmp();
}
10.1.3编写Mapper映射文件
<?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.jt.mapper.EmpMapper">
<!--
规则:
1.使用关联查询时,不能出现同名字段,否则映射报错
-->
<select id="findEmp" resultMap="empRM">
select emp.*,dept.dept_name
from emp,dept
where emp.dept_id = dept.dept_id
</select>
<!--
知识点:
1.autoMapping="true"
如果字段名称和属性名称一致,则自动映射
2.association 一对一对象
3.javaType 固定搭配 封装对象的类型
总结:Mybatis可以实现关联查询的数据封装.
可以为主对象封装数据/同时可以为引用封装数据
-->
<resultMap id="empRM" type="Emp" autoMapping="true">
<!--1.标识主键-->
<id column="id" property="id"/>
<!--2.一对一封装 Dept对象-->
<association property="dept" javaType="Dept" autoMapping="true">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"/>
</association>
</resultMap>
</mapper>
10.2 一对多
10.2.1编写测试类
//部门和员工一对多
@Test
public void testOneToMore(){
List<Dept> list = deptMapper.findAll();
System.out.println(list);
}
10.2.2编写Mapper接口文件
@Mapper
public interface DeptMapper {
List<Dept> findAll();
}
10.2.3编写Mapper映射文件
<?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.jt.mapper.DeptMapper">
<select id="findAll" resultMap="deptRM">
select dept.dept_name,emp.* from dept,emp
where emp.dept_id = dept.dept_id
</select>
<!--
固定搭配: collection + ofType
-->
<resultMap id="deptRM" type="Dept" autoMapping="true">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
<!-- 一对多封装 -->
<collection property="emps" ofType="Emp" autoMapping="true">
<id column="id" property="id"></id>
</collection>
</resultMap>
</mapper>
10.3多对多
11.使用注解开发
面向接口编程的根本原因:解耦,可拓展,提高复用,分层开发中、上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性好
11.1Mybatis CRUD注解说明
/**
* 规则:
* 1.注解和映射文件标签二选一
* 2.一个接口方法只能添加一个注解
* 3.注解只适用于单表的简单操作,复杂操作使用xml映射文件写法
* @return
*/
@Select("select * from emp")
/* @Insert("sql")
@Update("sql")
@Delete("sql")*/
List<Emp> findAll();
11.2@MapperScan注解说明
指定扫描包注解路径
12. Mybatis 缓存概念
12.1 原生Mybatis操作步骤
12.1.1 Mybatis官网介绍
5.1.2 Mybatis入门案例
/*
* Mysql入门实现步骤:
* 1.编辑mybatis-config.xml核心配置文件
* 1.1指定数据源配置
* 2.编辑POJO实体对象.要求与数据库表中的字段一一对应
* 3.编辑Mapper接口. 添加接口方法
* 4.编辑接口的实现类(配置文件方式) 要求namespace id resultType
* 5.mybatis加载指定的mapper映射文件
* 6.创建SqlSessionFactory工厂对象
* 7.获取SqlSession,开启数据库链接
* 8.获取接口对象(代理对象)
* 9.调用接口方法,获取返回值结果
* 10.关闭sqlSession链接.
* */
@Test
public void testDemo1() throws IOException {
/*创建SqlSessionFactory*/
String resource = "mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/*从SqlSessionFactory中获取sqlSession*/
SqlSession sqlSession = sqlSessionFactory.openSession();
/*获取mapper接口,执行接口方法*/
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
/*Mybatis为接口创建了一个代理对象
知识点: 框架中通过接口调用方法时,如果没有实现类,则为其创建代理对象
代理对象~实现类
*/
System.out.println(userMapper.getClass());
List<User> userList = userMapper.findAll();
System.out.println(userList);
/*执行之后关闭SqlSession*/
sqlSession.close();
}
12.1.3 重要概念说明
SqlSessionFactory
说明: 作用在内部已经关联了数据库,该设计是工厂模式的一种, 目的为了生产SqlSession
类比: factory(面粉/肉/菜…)加工------面条
SqlSession
说明: 用户利用SqlSession 实现数据库CURD操作
类比: 吃面条\
12.2 Mybatis中的缓存
12.2.1 缓存机制
说明: 如果遇到大量的重复请求,如果每次查询 都查询数据库,则性能较低. 如果第一次查询查询数据库,之后的查询执行缓存的操作.则可以提高查询的效率. 储存: 缓存中的数据一般都在内存中
12.2.2 Mybatis缓存机制-一级缓存
说明: 由同一个SqlSession执行的重复的查询操作.,则可以自动的实现数据的共享.
级别: SqlSession对象
/**
* 1.Mybatis 默认条件下一级缓存默认开启的.
* 2.执行重复操作时,Mybatis一级缓存生效,查询一次数据库.
* 3.如果查询期间执行更新操作,则一级缓存清空.保证数据都是新的
*/
@Test
public void testCache1(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.findAll();
//userMapper.insert(xxx);
userMapper.findAll();
userMapper.findAll();
}
12.2.3 Mybatis缓存机制-二级缓存
说明: 在同一个SqlSessionFactory中生产的SqlSession内实现数据共享.
级别: SqlSessionFactory
/**
* 规则:
* 1. 二级缓存默认是开启的.
* 2. 二级缓存需要标记. cache标签
* 3. 如果需要使用二级缓存,则应该关闭SqlSession
* 4. 多线程条件下如果需要实现数据共享,则要求数据必须序列化! 考点!!!
*/
@Test
public void testCache2(){
//对象1
SqlSession sqlSession1 = sqlSessionFactory.openSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
//线程A
List<User> list1 = userMapper1.findAll();
sqlSession1.close(); //只有关闭sqlSession 数据才会保存到缓存中
//对象2
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
//线程B
List<User> list2 = userMapper2.findAll();
sqlSession2.close();
}
12.2.4标识二级缓存
12.2.5关于对象序列化问题
说明: 在多线程条件下.数据如果需要共享,必须序列化
<!-- property:实体类对象名称-->
<!-- column:数据库字段名称-->
<!-- javaType:指定属性的类型-->
<!-- type:实体类对象类型-->
<!-- autoMapping:自动映射-->
<!-- ofType:指定集合内部(泛型)的对象类型-->
<!-- collection: 封装集合类型-->
<!-- association:表示一对一封装-->
<!-- resultType:如果单表查询首选-->
<!-- resultMap:如果进行关联查询-->
<!-- autoMapping:开启自动映射-->
<!--columnPrefix:"指定字段映射的前缀"-->