MyBatis学习笔记
介绍篇
认识框架
什么是框架?
- 可以说,一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程,表现为一组抽象类以及其实例协作的方法,它为构件复用提供了上下文(Context)关系。因此构件库的大规模重用也需要框架。
为什么使用框架?
- 因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识、内容,问题太多。
- 在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。
- 而且框架一般是成熟、稳健的,它可以处理系统很多细节问题,比如:事务处理、安全性、数据流控制等问题。
- 还有框架一般都经过很多人使用,所以结构很好,扩展性也很好,而且它是不断升级,你可以直接享用别人升级代码带来的好处。
软件开发的三层结构
- 我们用三层结构主要是使项目结构更清楚,分工更明确,有利于后期的维护和升级。
- 三层结构包含:表现层、业务层、持久层
认识设计模式
设计模式概述
- 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。
- 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案,这些方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
- 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
- 设计模式不是一种方法和技术,而是一种思想。
- 设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用。
- 学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成。
设计模式的类型
总体来说,设计模式分为三类23种:
- 创建型(5种):工厂模式、抽象工厂模式、单例模式、原型模式、构建者模式
- 结构型(7种):适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式
- 行为型(11种):模板方法模式、策略模式、观察者模式、中介者模式、状态模式、责任链模式、命令模式、迭代器模式、访问者模式、解释器模式、备忘录模式
JavaEE设计模式:MVC、委托模式
回顾JDBC代码
public class JdbcTest {
private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
private static final String DB_URL = "jdbc:mysql://192.168.254.128:3306/ssm?characterEncoding=utf-8";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "123456";
private static final String TEST_SQL = "select * from user where id = ?";
public static void main(String[] args) {
findUserById(1);
}
private static void findUserById(int id) {
try {
// 1、加载驱动
Class.forName(JDBC_DRIVER);
// 2、得到连接
try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
// 3、获取预处理statement
PreparedStatement ps = conn.prepareStatement(TEST_SQL)) {
// 4、设置参数
ps.setObject(1, id);
// 5、执行SQL
try (ResultSet rs = ps.executeQuery()) {
// 6、遍历结果集
while (rs.next()) {
String result = String.format("{id = %d, username = %s, sex = %s}",
rs.getInt("id"),
rs.getString("username"),
rs.getString("sex"));
System.out.println(result);
}
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
认识Mybatis
- mybatis参考网址:http://www.mybatis.org/mybatis-3/zh/index.html
- github源码地址:https://github.com/mybatis/mybatis-3
什么是Mybatis?
- 持久层框架
- 封装了JDBC代码,但是完全屏蔽了JDBC代码的相关操作
- 用XML或者注解方式,去使用mybatis框架完成持久化操作
- mybatis会使用高级映射来完成参数处理和返回值映射
- mybatis是直接操作原生的SQL语句
Mybatis的由来
- 是apache的一个开源项目iBatis
- 2010年这个项目由apache software foundation迁移到google code,并改名为Mybatis
- 2013年11月迁移到Github
ORM框架
- Object Relation Mapping,例如:Hibernate
mybatis和ORM框架hibernate的区别
- mybatis是一个不完全的ORM框架,而hibernate是一个完全的ORM框架
- mybatis学习成本低,hibernate学习成本高
- mybatis数据库无关性不好,hibernate数据库无关性好
- mybatis是直接操作SQL语句,它更加灵活,而hibernate是操作的HQL语句
基础篇
MyBatis入门
开发流程
- 编写全局配置文件:SqlMapConfig.xml
- properties标签:读取Java配置文件(properties文件)
- typeAliases标签:对PO类的全路径(全限定名)做别名处理,方便xml配置
- mappers标签:加载映射文件
- 编写PO类
- 只有私有属性和getter、setter方法的javabean
- 只是在不同场景下,有了不同的定义
- 编写映射文件
- 编写原生SQL语句(符合SQL92标准和MySQL标签的语句)
- 数据参数映射
- 结果集映射
- 编写持久层代码
- 如何读取全局配置文件、还有映射文件
- SqlSessionFactoryBuilder(全局配置文件对应的流对象)
- SqlSessionFactory(获取SqlSession)
- SqlSession
- 如何调用映射文件中的SQL语句,完成对数据库的增删改查
- 调用SqlSession中的api完成增删改查功能
- 如何读取全局配置文件、还有映射文件
需求
- 根据用户id查询一个用户信息
- 根据用户名称模糊查询用户信息列表
- 添加用户
- 更新用户
- 删除用户
项目搭建
- 创建一个普通的 maven工程,添加依赖:
<!-- mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- junit单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
- 编写 SqlMapConfig.xml 全局文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 读取properties配置文件 -->
<properties resource="properties/db.properties"></properties>
<!-- 配置数据源 -->
<environments default="development">
<environment id="development">
<!-- 事务管理:采用的是JDBC的事务管理 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源连接池:POOLED使用的是Mybatis自己的连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<!-- 读取mapper映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
- 编写 UserMapper.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">
<!-- namespace:作用是为了分类管理映射文件中的MappedStatement对象 -->
<mapper namespace="test">
<!--
select\insert\update\delete标签,最终会封装到MappedStatement对象中
id:指定MappedStatement对象的唯一标识
对象参数绑定:使用OGNL
parameterType:指定输入参数映射的java类型
resultType:指定结果集映射的java类型
-->
<select id="findUserById" parameterType="int" resultType="com.yw.mybatis.example.po.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
- 编写 User.java PO类
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
}
实现需求
根据id查询用户信息
- 映射文件
<!-- 根据id获取用户信息 -->
<select id="findUserById" parameterType="int" resultType="com.yw.mybatis.example.po.User">
SELECT * FROM user WHERE id = #{id}
</select>
- 测试代码
public class MybatisDemo {
// sql会话工厂,抽取代码,方便重用
private SqlSessionFactory sqlSessionFactory;
/**
* @Before注解的方法会在@Test注解的方法之前执行
* @throws Exception
*/
@Before
public void init() throws Exception{
// 指定全局配置文件路径
String resource = "SqlMapConfig.xml";
// 加载资源文件(全局配置文件和映射文件)
// 最终全局配置文件的数据,都会封装到一个对象中:Configuration对象
InputStream inputStream = Resources.getResourceAsStream(resource);
// 用构建者模式,去创建SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception{
SqlSession sqlSession = null;
try {
// 构造UserMapper对象(sqlSession),该步操作会牵扯到事务
// 设置手动提交才能开启事务,默认是手动提交
sqlSession = sqlSessionFactory.openSession();
/*
参数1:和映射文件中的select标签建立联系:namespace+"."+statementID
参数2:就是要传递的参数
*/
User user = sqlSession.selectOne("test.findUserById", 1);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null){
sqlSession.close();
}
}
}
}
根据用户名模糊查询用户信息
- 映射文件
<!-- 自定义条件查询用户列表 -->
<select id="findUserByUsername" parameterType="java.lang.String"
resultType="com.yw.mybatis.example.po.User">
select * from user where username like '%${value}%'
</select>
- 测试代码
@Test
public void testFindUserByUsername() throws Exception{
SqlSession sqlSession = null;
try {
// 构造UserMapper对象(sqlSession),该步操作会牵扯到事务
// 设置手动提交才能开启事务,默认是手动提交
sqlSession = sqlSessionFactory.openSession();
/*
参数1:和映射文件中的select标签建立联系:namespace+"."+statementID
参数2:就是要传递的参数
*/
List<User> users = sqlSession.selectList("test.findUserByUsername", "张");
System.out.println(users.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null){
sqlSession.close();
}
}
}
#{} 和${}的区别
- 区别1:#{} 相当于JDBC SQL语句中的占位符 ? (PreparedStatement);${} 相当于JDBC SQL语句中的连接符号+(Statement)
- 区别2:#{} 进行输入映射的时候,会对参数进行类型解析(如果是String类型,会自动加上’');${} 进行输入映射的时候,将参数原样输出到SQL语句中。
- 区别3:#{} 如果进行简单类型(8大基本数据类型)的输入映射,#{}中参数名称可以任意;${} 如果进行简单类型(8大基本数据类型)的输入映射,${}中参数名称必须是value。
- 区别4:${} 存在SQL注入问题,例如使用OR 1=1 关键字将查询条件忽略。
添加用户
- 映射文件
<!-- 添加用户 -->
<insert id="insertUser" parameterType="com.yw.mybatis.example.po.User">
insert into user(username, birthday, sex, address)
values(#{username}, #{birthday}, #{sex}, #{address})
</insert>
- 测试代码
@Test
public void testInsertUser() throws Exception{
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 添加用户信息
User user = new User();
user.setUsername("Alice");
user.setAddress("US");
user.setSex("女");
user.setBirthday(new Date());
sqlSession.insert("test.insertUser", user);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null){
sqlSession.close();
}
}
}
- 主键返回
<!-- 添加用户 -->
<insert id="insertUser" parameterType="com.yw.mybatis.example.po.User">
<!-- selectKey将主键返回,需要再返回 -->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username, birthday, sex, address)
values(#{username}, #{birthday}, #{sex}, #{address})
</insert>
- 添加selectKey标签实现主键返回
- keyProperty:指定返回的主键,存储在pojo中的那个属性。
- order:selectKey标签中的sql的执行顺序,是相对于insert语句来说的。由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after。
- resultType:返回的主键对应的Java类型。
- LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新纪录id值。
删除用户
- 映射文件
<!-- 删除用户 -->
<delete id="deleteUserById" parameterType="int">
delete from user where id = #{id}
</delete>
- 测试代码
@Test
public void testDeleteUserById() throws Exception{
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 删除用户
sqlSession.delete("test.deleteUserById", 4);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null){
sqlSession.close();
}
}
}
修改用户
- 映射文件
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.yw.mybatis.example.po.User">
update user set
username = #{username},
birthday = #{birthday},
sex = #{sex},
address = #{address}
where id = #{id}
</update>
- 测试代码
@Test
public void testUpdateUser() throws Exception{
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 修改用户信息
User user = new User();
user.setId(3);
user.setUsername("Alice");
user.setAddress("BALABALA");
user.setSex("男");
user.setBirthday(new Date());
sqlSession.insert("test.updateUser", user);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null){
sqlSession.close();
}
}
}
开发dao方式
原始dao方式
说明:该种方式一般来说只会出现在那些从 ibatis 项目迁移过来的项目
- SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession的生命周期
- SqlSessionFactoryBuilder:method方法内的局部变量。
- SqlSessionFactory:应用范围内唯一。
- SqlSession:method方法范围。牵涉到线程安全问题,原因在于sqlsession实现类对象中会包含全局数据(参数和返回值)
- dao 接口和实现类
public interface UserDao {
User findUserById(int id) throws Exception;
}
public class UserDaoImpl implements UserDao {
// 依赖注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id){
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = null;
try{
user = sqlSession.selectOne("dao.test.findUserById", 1);
}finally{
sqlSession.close();
}
return user;
}
}
- 映射文件
<mapper namespace="dao.test">
<!-- 根据id获取用户信息 -->
<select id="findUserById" parameterType="int" resultType="com.yw.mybatis.example.po.User">
select * from user where id = #{id}
</select>
</mapper>
- 测试代码
public class UserDaoTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init(){
try {
// 指定全局配置文件路径
String resource = "dao/SqlMapConfig.xml";
// 加载资源文件(全局配置文件和映射文件)
InputStream inputStream = Resources.getResourceAsStream(resource);
// 用构建者模式,去创建SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testFindUserById(){
UserDao dao = new UserDaoImpl(sqlSessionFactory);
User user = dao.findUserById(1);
System.out.println(user);
}
}
mapper代理方式(推荐)
- 使用mapper代理方式开发dao,是只需要定义dao接口(mapper接口),不需要dao实现类。Mybatis底层使用的是动态代理方式帮助我们产生dao实现类:
- 基于JDK的动态代理(Mybatis的mapper代理方式,是基于JDK的动态代理):基于接口。
- 基于CGLib的动态代理:基于继承。
- 使用mapper代理方法开发dao,除了PO类和全局配置文件以外,只需要编写映射文件和Mapper接口(dao接口)
基于 XML 方式
- 使用:只需要开发Mapper接口(dao接口)和Mapper约束文件,不需要编写实现类
- 开发规范:
- 映射文件的namespace和mapper接口的类路径要一致;
- 映射文件的statement的id和和mapper接口的方法名要一致;
- 映射文件的statement的parameterType和mapper接口的方法参数类型要一致;
- 映射文件的statement的resultType和mappper接口的方法返回值类型要一致
- 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.yw.mybatis.example.mapper.xml.UserMapper">
<!-- 根据id获取用户信息 -->
<select id="findUserById" parameterType="int" resultType="com.yw.mybatis.example.po.User">
select * from user where id = #{id}
</select>
</mapper>
- mapper接口
public interface UserMapper {
User findUserById(int id);
}
- 加载映射文件
<mappers>
<!-- 批量加载 -->
<package name="com.yw.mybatis.example.mapper.xml"/>
</mappers>
- 测试代码
public class XmlUserMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init(){
try {
// 指定全局配置文件路径
String resource = "XmlSqlMapConfig.xml";
// 加载资源文件(全局配置文件和映射文件)
InputStream inputStream = Resources.getResourceAsStream(resource);
// 用构建者模式,去创建SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testFindUserById() throws Exception {
// 构造UserMapper对象(sqlSession)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 需要传的参数就是被代理的Mapper接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用UserMapper对象的findUserById
User user = userMapper.findUserById(1);
System.out.println(user);
}
}
基于注解
- 定义 mapper 接口
public interface AnnotationUserMapper {
@Select("select * from user where id = #{id}")
User findUserById(int id);
}
- 修改全局配置文件
<mappers>
<!-- 批量加载 -->
<package name="com.yw.mybatis.example.mapper.annotation"/>
</mappers>
- 测试代码
public class AnnotationUserMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init(){
try {
// 指定全局配置文件路径
String resource = "AnnotationSqlMapConfig.xml";
// 加载资源文件(全局配置文件和映射文件)
InputStream inputStream = Resources.getResourceAsStream(resource);
// 用构建者模式,去创建SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testFindUserById() {
SqlSession sqlSession = sqlSessionFactory.openSession();
AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class);
User user = userMapper.findUserById(1);
System.out.println(user);
}
}
全局配置文件
- 配置内容:SqlMapConfig.xml 中配置的内容和顺序如下
- properties:属性
- settings:全局配置参数
- typeAliases:类型别名
- typeHandlers:类型处理器——Java类型——JDBC类型——>数据库类型转换
- objectFactory:对象工厂
- plugins:插件——可以在Mybatis执行SQL语句的流程中,横叉一脚去实现一些功能增强,比如PageHelper分页插件
- environments:环境集合属性对象
- environment:环境子属性对象
- transactionManager:事务管理
- dataSource:数据源
- environment:环境子属性对象
- mappers:映射器
- mapper:映射
properties 标签
- 可以引用java属性文件中的配置信息,例如在 classpath 下定义的db.properties文件
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
db.username=root
db.password=root
- 要在 SqlMapConfig.xml 中引用db.properties中的属性时,如下:
<!-- 读取properties配置文件 -->
<properties resource="properties/db.properties"></properties>
<!-- 配置数据源 -->
<environments default="development">
<environment id="development">
<!-- 事务管理:采用的是JDBC的事务管理 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源连接池:POOLED使用的是Mybatis自己的连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
- properties标签除了可以使用resource属性引用properties文件中的属性,还可以在properties标签内定义property子标签来定义属性和属性值
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"></property>
</properties>
- 注意:Mybatis将按照下面的顺序来加载属性
1)读取properties元素内定义的属性
2)读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性
typeAlias 标签
- 别名的作用是简化映射文件中parameterType和resultType中的POJO类型名称编写,下面是默认支持的别名
别名 | 映射类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
map | Map |
- 自定义别名:在SqlMapConfig.xml中进行如下配置
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.yw.mybatis.example.po.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大小写都可以) -->
<package name="com.yw.mybatis.example.po"/>
</typeAliases>
mappers 标签
- <mapper resource=“”/>:使用相对于类路径的资源
- <mapper url=“”/>:使用绝对路径加载资源
- <mapper class=“”/>:使用mapper接口类路径,加载映射文件。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
- <package name=“”/>:注册指定包下的所有mapper接口,来加载映射文件。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
输入映射和输出映射
parameterType(输入类型)
- parameterType属性可以映射的输入类型有:简单类型、POJO类型、Map类型、List类型(数组),其中 Map类型和POJO类型用法类似
- 应用场景:传递简单类型、传递pojo对象、传递pojo包装对象
- 包装对象:pojo类中包含pojo
- #{}:是通过反射获取数据的——StaticSqlSource
- ${}:是通过OGNL表达式会随着对象的嵌套而相应的发生层级变化——DynamicSqlSource
- 包装对象:pojo类中包含pojo
resultType(输出类型)
- resultType 属性可以映射的java类型有:简单类型、POJO类型、Map类型,不过Map类型和POJO类型的使用情况类似。
- 使用要求:使用resultType进行输出映射时,要求sql语句中查询的列名要和映射的pojo属性名一致
- 应用场景:映射简单类型、映射pojo对象
- 注意:不管是单个的POJO还是POJO集合,在使用resultType完成映射时,用法一样
resultMap
- 使用要求:如果sql查询列名和pojo的属性名不一致,可以通过resultMap将列名和属性名做一个对应关系,最终将查询结果映射到指定的pojo对象中。
- 注意:resultType底层也是通过resultMap完成映射的
- 需求:将以下查询结果进行映射:
select id id_,username username_,birthday birthday_ from user
- Mapper 映射文件:由于sql查询列名和User类属性名不一致,所以不能使用resultType进行结构映射,需要定义一个resultMap将sql查询列名和User类的属性名对应起来,完成结果映射
<!--
定义resultMap:将查询的列名和pojo的属性名一一对应起来
type:指定查询结果要映射的pojo的类型
id:指定resultMap的唯一标识
-->
<resultMap type="user" id="userListResultMap">
<!--
id标签:映射结果的唯一列(主键列)
column:查询sql的列名
property:映射结果的属性名
result:普通结果,即pojo的属性
-->
<id column="id_" property="id"/>
<result column="username_" property="username"/>
<result column="birthday_" property="birthday"/>
</resultMap>
<!-- resultMap入门 -->
<select id="findUserListResultMap" resultMap="userListResultMap">
select id id_,username username_,birthday birthday_ from user
</select>