Mybatis源码解读 (基础应用篇)

本文深入探讨了Mybatis的基础应用,包括mapper代理的JDK和CGLIB实现,XML与注解方式的开发细节,如接口与namespace匹配、参数与返回类型的一致性。同时,讲解了全局配置文件的properties标签、typeAlias以及mappers标签的使用,并详细阐述了输入映射(parameterType)和输出映射(resultType、resultMap)的概念与配置方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mapper代理开发方式

此处使用的是 JDK 的动态代理方式,延迟加载使用的 cglib 动态代理方式

代理理解

代理分为静态代理和动态代理。此处先不说静态代理,因为 Mybatis 中使用的代理方式是动态代理。
动态代理分为两种方式:
  • 基于JDK的动态代理--针对有接口的类进行动态代理
  • 基于CGLIB的动态代理--通过子类继承父类的方式去进行代理。

XML方式

  • 开发方式 

只需要开发Mapper接口(dao接口)和Mapper映射文件,不需要编写实现类。

  • 开发规范

      Mapper接口开发方式需要遵循以下规范:

           1、Mapper接口的类路径与Mapper.xml文件中的namespace相同。

           2、Mapper接口方法名称和Mapper.xml中定义的每个statementid相同。

           3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql parameterType的类型相 同。

           4、Mapper接口方法的返回值类型和mapper.xml中定义的每个sqlresultType的类型相同。

  • 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.gly.mybatis.mapper.UserMapper"> 

    <!-- 根据id获取用户信息 --> 
    <select id="findUserById" parameterType="int" resultType="com.gly.mybatis.po.User"> 
        select * from user where id = #{id}
    </select> 

</mapper>
  • mapper 接口
/*** 用户管理mapper */ 
public interface UserMapper { 

    //根据用户id查询用户信息 
    public User findUserById(int id) throws Exception; 

} 
  • 全局配置文件中加载映射文件
<!-- 加载映射文件 --> 
<mappers> 
    <mapper resource="mapper/UserMapper.xml"/> 
</mappers>
  • 测试代码
public class UserMapperTest{ 

    private SqlSessionFactory sqlSessionFactory; 

    @Before 
    public void setUp() throws Exception { 

        //mybatis配置文件 
        String resource = "SqlMapConfig.xml"; 
        InputStream inputStream = Resources.getResourceAsStream(resource); 
        //使用SqlSessionFactoryBuilder创建sessionFactory 
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 

    }

    @Test 
    public void testFindUserById() throws Exception { 

        //获取session 
        SqlSession session = sqlSessionFactory.openSession(); 
        //获取mapper接口的代理对象 
        UserMapper userMapper = session.getMapper(UserMapper.class); 
        //调用代理对象方法 
        User user = userMapper.findUserById(1); 
        System.out.println(user); 
        //关闭session 
        session.close(); 

    } 

}

注解方式

 

  • 开发方式

只需要编写mapper接口文件接口。

  • mapper接口
public interface AnnotationUserMapper { 
// 查询
@Select("SELECT * FROM user WHERE id = #{id}") 
public User findUserById(int id); 

// 模糊查询用户列表 
@Select("SELECT * FROM user WHERE username LIKE '%${value}%'") 
public List<User> findUserList(String username); 

// 添加并实现主键返回 12345678910
@Insert("INSERT INTO user (username,birthday,sex,address) VALUES (# {username},#{birthday},#{sex},#{address})") 
@SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", resultType = int.class, before = false) 
public void insertUser(User user); 

}
  • 测试代码
public class AnnotationUserMapperTest { 

private SqlSessionFactory sqlSessionFactory; 

    /**
      * @Before注解的方法会在@Test注解的方法之前执行 
      *
      * @throws Exception 
      */ 
    @Before 
    public void init() throws Exception { 

        // 指定全局配置文件路径 
        String resource = "SqlMapConfig.xml"; 
        // 加载资源文件(全局配置文件和映射文件) 
        InputStream inputStream = Resources.getResourceAsStream(resource); 
        // 还有构建者模式,去创建SqlSessionFactory对象 
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 

    }

    @Test 
    public void testFindUserById() { 

        SqlSession sqlSession = sqlSessionFactory.openSession(); 
        AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class); 
        User user = userMapper.findUserById(1); 
        System.out.println(user); 

    }

    @Test 
    public void testFindUserList() { 

        SqlSession sqlSession = sqlSessionFactory.openSession(); 
        AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class); 
        List<User> list = userMapper.findUserList("老郭"); 
        System.out.println(list); 

    }

    @Test 
    public void testInsertUser() { 

        SqlSession sqlSession = sqlSessionFactory.openSession(); 
        AnnotationUserMapper userMapper = sqlSession.getMapper(AnnotationUserMapper.class); 

        User user = new User(); 
        user.setUsername("Test2"); 
        user.setSex("1"); 
        user.setAddress("TestBase"); 
        userMapper.insertUser(user); 
        System.out.println(user.getId()); 

    } 

}

全局配置文件

配置内容

SqlMapConfifig.xml 中配置的内容和顺序如下:
properties(属性) 

settings(全局配置参数) 

typeAliases(类型别名) 

typeHandlers(类型处理器)--Java类型--JDBC类型--->数据库类型转换 

objectFactory(对象工厂) 

plugins(插件)--可以在Mybatis执行SQL语句的流程中,横叉一脚去实现一些功能增强,比如 PageHelper分页插件,就是第三方实现的一个插件 

environments(环境集合属性对象) 

environment(环境子属性对象) 

    transactionManager(事务管理) 

    dataSource(数据源) 

mappers(映射器)

properties标签

SqlMapConfifig.xml 可以引用 java 属性文件中的配置信息。
  1. classpath下定义db.properties文件
    jdbc.driver=com.mysql.jdbc.Driver 
    jdbc.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8 
    jdbc.username=root 
    jdbc.password=root
  2. 在SqlMapConfifig.xml文件中,引用db.properties中的属性,具体如下:
<properties resource="db.properties"/> 
    <environments default="development"> 
        <environment id="development"> <transactionManager type="JDBC"/> 
            <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> 
                <property name="url" value="${jdbc.url}"/> 
                <property name="username" value="${jdbc.username}"/> 
                <property name="password" value="${jdbc.password}"/> 
            </dataSource> 
        </environment> 
    </environments>

properties标签除了可以使用resource属性,引用properties文件中的属性。还可以在properties标签内定义property子标签来定义属性和属性值,具体如下:

<properties> 
    <property name="driver" value="com.mysql.jdbc.Driver"/> 
</properties>

注意: MyBatis 将按照下面的顺序来加载属性

  • 读取properties 元素体内定义的属性。
  • 读取properties 元素中resource url 加载的属性,它会覆盖已读取的同名属性。

typeAlias标签

 
别名的作用 :就是为了简化映射文件中 parameterType ResultType 中的 POJO 类型名称编写。
 
默认支持别名
别名
映射的类型
_byte
byte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
mapMap
自定义别名
SqlMapConfifig.xml 中进行如下配置:
<typeAliases> 

    <!-- 单个别名定义 --> 
    <typeAlias alias="user" type="com.gly.mybatis.entity.User"/> 

    <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> 
    <package name="com.gly.mybatis.entity"/> 
</typeAliases>

mappers标签

<mapper resource=""/>

使用相对于类路径的资源
如:
<mapper resource="sqlmap/User.xml" />
<mapper url="">
使用绝对路径加载资源
如:
<mapper url="file://d:/sqlmap/User.xml" />
<mapper class=""/>
使用 mapper 接口类路径,加载映射文件。
如:
 <mapper class="com.gly.mybatis.mapper.UserMapper"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
 
<package name=""/>
注册指定包下的所有 mapper 接口,来加载映射文件。
如:
<package name="com.gly.mybatis.mapper"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
 
​​​​​​

输入映射和输出映射

parameterType(输入类型)

parameterType 属性可以映射的输入参数 Java 类型有: 简单类型、 POJO 类型、 Map 类型、 List 类型( 数组)
  • Map类型和POJO类型的用法类似,本课程只讲POJO类型的相关配置。
  • List类型在动态SQL部分进行讲解。
传递简单类型
参考入门案例中用户查询的案例。
 
传递 pojo 对象
参考入门案例中的添加用户的案例。
 
传递 pojo 包装对象
包装对象: pojo 类中嵌套 pojo
 
需求
通过包装 POJO 传递参数,完成用户查询。
 
QueryVO
定义包装对象 QueryVO
public class QueryVO { 
    private User user; 
}
SQL 语句
SELECT * FROM user where username like '%小明%'
Mapper 文件
<!-- 使用包装类型查询用户 使用ognl从对象中取属性值,如果是包装对象可以使用.操作符来取内容部的属性 --> 
<select id="findUserList" parameterType="queryVo" resultType="user"> 
    SELECT * FROM user where username like '%${user.username}%' 
</select>
Mapper 接口
/**
  * 用户管理mapper 
  */ 
public interface UserMapper { 

    //综合查询用户列表 
    public List<User> findUserList(QueryVo queryVo) throws Exception; 

}
测试方法
 
UserMapperTest 测试类中,添加以下测试代码:
@Test
public void testFindUserList() throws Exception { 

    SqlSession sqlSession = sqlSessionFactory.openSession(); 
    //获得mapper的代理对象 
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
    //创建QueryVo对象 
    QueryVo queryVo = new QueryVo(); 
    //创建user对象 
    User user = new User(); 
    user.setUsername("小明"); 
    queryVo.setUser(user); 
   
    //根据queryvo查询用户 
    List<User> list = userMapper.findUserList(queryVo);         
    System.out.println(list); 
    sqlSession.close(); 

}

resultType(输出类型)

resultType 属性可以映射的 java 类型有: 简单类型、 POJO 类型、 Map 类型
不过 Map 类型和 POJO 类型的使用情况类似,所以只需讲解 POJO 类型即可。
 
使用要求
使用 resultType 进行输出映射时,要求 sql 语句中 查询的列名 和要映射的 pojo 的属性名 一致。
 
映射简单类型
 
案例需求
查询用户记录总数。
 
Mapper 映射文件
<!-- 获取用户列表总数 --> 
<select id="findUserCount" resultType="int"> 
    select count(1) from user 
</select>
Mapper 接口
//查询用户总数 
public int findUserCount() throws Exception;
测试代码
 
UserMapperTest 测试类中,添加以下测试代码:
@Test
public void testFindUserCount() throws Exception {

    SqlSession sqlSession = sessionFactory.openSession();
    //获得mapper的代理对象
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int count = userMapper.findUserCount();
    System.out.println(count);
    sqlSession.close(); 
}
注意:输出简单类型必须查询出来的结果集只有一列。
 
映射 pojo 对象
 
注意:不管是单个 POJO 还是 POJO 集合,在使用 resultType 完成映射时,用法一样。
 
参考入门程序之根据用户 ID 查询用户信息和根据名称模糊查询用户列表的案例

 

resultMap

使用要求
 
如果 sql 查询列名和 pojo 的属性名可以不一致,通过 resultMap 将列名和属性名作一个对应关系,最终将
查询结果映射到指定的 pojo 对象中。
 
注意: resultType 底层也是通过 resultMap 完成映射的。
 
需求
 
将以下 sql 的查询结果进行映射:
 
SELECT id id_,username username_,birthday birthday_ FROM user
Mapper 接口
// resultMap入门 
public List<User> findUserListResultMap() throws Exception;
Mapper 映射文件
 
由于 sql 查询列名和 User 类属性名不一致,所以不能使用 resultType 进行结构映射。
 
需要定义一个 resultMap sql 查询列名和 User 类的属性名对应起来,完成结果映射。
<!-- 定义resultMap:将查询的列名和映射的pojo的属性名做一个对应关系 --> 
<!--type:指定查询结果要映射的pojo的类型 id:指定resultMap的唯一标示 --> 

<resultMap type="user" id="userListResultMap"> 
    <!-- id标签:映射查询结果的唯一列(主键列) column:查询sql的列名 property:映射结果的属性名 --> 
    <id column="id_" property="id"/> 
    <!-- result标签:映射查询结果的普通列 --> 
    <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>
  • <id/>:表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个
    • Property :表示 User类的属性。
    • Column :表示 sql查询出来的字段名。
    • Column property 放在一块儿表示将 sql 查询出来的字段映射到指定的 pojo 类属性上。
  • <result/>:普通结果,即pojo的属性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值