1. Mybatis的开发方式

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

1.1 代理理解

代理分为静态代理和动态代理。此处先不说静态代理,因为Mybatis中使用的代理方式是动态代理。

动态代理分为两种方式:

  • 基于JDK的动态代理--针对有接口的类进行动态代理
  • 基于CGLIB的动态代理--通过子类继承父类的方式去进行代理。

1.2 XML方式

  • 开发方式

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

  • 开发规范

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

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

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

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

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

  • 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.kkb.mybatis.mapper.UserMapper">
<!-- 根据id获取用户信息 -->
    <select id="findUserById" parameterType="int" resultType="com.kkb.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();
        
    }
}

1.3 注解方式

  • 开发方式

    只需要编写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);

    // 添加并实现主键返回
    @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("开课吧-2");
        user.setSex("1");
        user.setAddress("致真大厦");
        userMapper.insertUser(user);
        System.out.println(user.getId());
    }

}

2. 全局配置文件

2.1 配置内容

SqlMapConfig.xml中配置的内容和顺序如下:

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

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

objectFactory(对象工厂)

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

environments(环境集合属性对象)

environment(环境子属性对象)
       transactionManager(事务管理)
       dataSource(数据源)
mappers(映射器)

2.2 properties标签

SqlMapConfig.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、在SqlMapConfig.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 加载的属性,它会覆盖已读取的同名属性。

2.3 typeAlias标签

别名的作用:就是为了简化映射文件中parameterType和ResultType中的POJO类型名称编写。

2.3.1 默认支持别名

别名 映射的类型
_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

2.3.2 自定义别名

在SqlMapConfig.xml中进行如下配置:

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

2.4 mappers标签

<mapper resource=""/>

使用相对于类路径的资源

如:

<mapper resource="sqlmap/User.xml" />

<mapper url="">

使用绝对路径加载资源

如:

<mapper url="file://d:/sqlmap/User.xml" />

<mapper class=""/>

使用mapper接口类路径,加载映射文件。

如:

<mapper class="com.kkb.mybatis.mapper.UserMapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

<package name=""/>

注册指定包下的所有mapper接口,来加载映射文件。

如:

<package name="com.kkb.mybatis.mapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

3. 输入映射和输出映射

3.1 parameterType(输入类型)

parameterType属性可以映射的输入参数Java类型有:简单类型、POJO类型、Map类型、List类型(数组)

  • Map类型和POJO类型的用法类似,这里只讲POJO类型的相关配置。
  • List类型在动态SQL部分进行讲解。

传递简单类型

参考《Mybatis基础》(在我的主页内查找)中用户查询的案例。

传递pojo对象

参考《Mybatis基础》(在我的主页内查找)中的添加用户的案例。

传递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();
    }

3.2 resultType(输出类型)

resultType属性可以映射的java类型有:简单类型、POJO类型、Map类型

不过Map类型和POJO类型的使用情况类似,所以只需讲解POJO类型即可。

3.2.1 使用要求

使用resultType进行输出映射时,要求sql语句中查询的列名和要映射的pojo的属性名一致。

3.2.2 映射简单类型

案例需求

查询用户记录总数。

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(queryVo);
         System.out.println(count);

        sqlSession.close();
    }

注意:输出简单类型必须查询出来的结果集只有一列。

3.2.3 映射pojo对象

注意:不管是单个POJO还是POJO集合,在使用resultType完成映射时,用法一样。

参考《Mybatis基础》(在我的主页内查找)中根据用户ID查询用户信息和根据名称模糊查询用户列表的案例

4. resultMap

4.1 使用要求

如果sql查询列名和pojo的属性名可以不一致,通过resultMap将列名和属性名作一个对应关系,最终将查询结果映射到指定的pojo对象中。

注意:resultType底层也是通过resultMap完成映射的。

4.2 需求

将以下sql的查询结果进行映射:

SELECT id id_,username username_,birthday birthday_ FROM user

4.3 Mapper接口

// resultMap入门
public List<User> findUserListResultMap() throws Exception; 

4.4 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/>:表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个<id />

    • Property:表示User类的属性。
    • Column:表示sql查询出来的字段名。
    • Column和property放在一块儿表示将sql查询出来的字段映射到指定的pojo类属性上。
  • <result/>:普通结果,即pojo的属性。

晓双
76 声望15 粉丝

🏅Alibaba Nacos & Apache EventMesh Committer