【Mybatis】 入门

一、概述

1.1 JDBC

  • MyBatis是一个Java持久层框架,Java中操作关系型 数据库用的是JDBC,MyBatis是对JDBC的一个封装。

1.2 JDBC编程中问题

  • 企业开发中,根据项目大小、特点进行技术选型 ,JDBC操作数据库时效率是很高的,jdbc也是技术选型的参考。

  • 1、数据库连接频繁的创建和关闭,缺点浪费数据库的资源,影响操作效率。设想:使用数据库连接池

  • 2、sql语句是硬编码,如果需求变更需要修改sql,就需要修改java代码,需要重新编译,系统不易维护。设想:将sql语句 统一配置在文件中,修改sql不需要修改java代码。

  • 3、通过preparedStatement向占位符设置参数,存在硬编码( 参数位置,参数)问题。系统不易维护。设想:将sql中的占位符及对应的参数类型配置在配置文件中,能够自动输入映射。

  • 4、遍历查询结果集存在硬编码(列名)。设想:自动进行sql查询结果向java对象的映射(输出映射)。

1.3 MyBatis介绍

  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatisibatis进行一些改进。 目前mybatisgithub上托管。git(分布式版本控制,当前比较流程)
  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

1.4 Mybatis架构

【Mybatis】 入门

二、MyBatis入门程序

2.1 需求

  • 实现用户查询:
    • 根据用户id(主键)查询用户信息(单条记录)
    • 根据用户名称模糊查询用户信息(多条记录)
  • 用户添加
  • 用户删除
  • 用户修改

2.2 引入MyBatis依赖

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis  继承了日志等依赖,默认为log4j-->
        <dependency>  
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>

2.3 配置 log4j.properties

# Global logging configuration,建议开发环境中要用debug
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

2.4 配置 SqlMapConfig.xml(公用文件)

  • 通过SqlMapConfig.xml加载mybatis运行环境。
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 属性定义
    加载一个properties文件
    在 properties标签 中配置属性值
     -->
    <properties resource="db.properties">
        <!-- <property name="" value=""/> -->
    </properties>
    
    <!-- 定义 别名 -->
    <typeAliases>
       <typeAlias type="com.hao.mybatis.po.User" alias="user"/>     
    </typeAliases>
    
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment >
        <!-- 使用jdbc事务管理-->
            <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>
    
    <!--加载mapper映射
    如果将和spring整合后,可以使用整合包中提供的mapper扫描器,此处的mappers不用配置了。
     -->
    <mappers>
        <!-- 通过resource引用mapper的映射文件 -->
        <mapper resource="sqlmap/User.xml" />
    
    </mappers>
</configuration>

2.5 根据id查询用户

pojo(User.java)

public class User {
    private int id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址
    
    //getter & setter 省略
}

配置映射文件

  • 建议命名规则:表名+mapper.xml
  • 早期ibatis命名规则:表名.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命名空间,为了对sql语句进行隔离,方便管理 ,mapper开发dao方式,使用namespace有特殊作用
mapper代理开发时将namespace指定为mapper接口的全限定名
 -->
<mapper namespace="test">
<!-- 在mapper.xml文件中配置很多的sql语句,执行每个sql语句时,封装为MappedStatement对象
mapper.xml以statement为单位管理sql语句
 -->

    <!-- 根据id查询用户信息 -->
    <!-- 
        id:唯一标识 一个statement
        #{}:表示 一个占位符,如果#{}中传入简单类型的参数,#{}中的名称随意
        parameterType:输入 参数的类型,通过#{}接收parameterType输入 的参数
        resultType:输出结果 类型,不管返回是多条还是单条,指定单条记录映射的pojo类型
     -->
    <select >
        SELECT * FROM USER WHERE id= #{id}
    
    </select>
    
</mapper>

编写Dao层

public interface UserDao {
    
    //根据id查询用户信息
    public User findUserById(int id) throws Exception;
    //根据用户名称模糊查询用户列表
    public List<User> findUserByUsername(String username) throws Exception;
    //插入用户
    public void insertUser(User user) throws Exception;

}

public class UserDaoImpl implements UserDao {

    private SqlSessionFactory sqlSessionFactory;

    // 将SqlSessionFactory注入
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User findUserById(int id) throws Exception {

        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 根据id查询用户信息
        User user = sqlSession.selectOne("test.findUserById", id);

        sqlSession.close();

        return user;

    }

    @Override
    public List<User> findUserByUsername(String username) throws Exception {
        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("test.findUserByName", username);
        sqlSession.close();
        return list;
    }

    @Override
    public void insertUser(User user) throws Exception {
        // 创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.insert("test.insertUser", user);
        sqlSession.commit();
        sqlSession.close();
        
    }

}

测试

public class UserDaoImplTest {

    // 会话工厂
    private SqlSessionFactory sqlSessionFactory;

    // 创建工厂
    @Before
    public void init() throws IOException {

        // 配置文件(SqlMapConfig.xml)
        String resource = "SqlMapConfig.xml";

        // 加载配置文件到输入 流
        InputStream inputStream = Resources.getResourceAsStream(resource);

        // 创建会话工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    }

    @Test
    public void testFindUserById() throws Exception {

        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        
        User user = userDao.findUserById(1);
        System.out.println(user);
        
    }

}

2.6 根据用户名称模糊查询用户信息

  • 根据用户名称模糊查询用户信息可能返回多条记录。

修改映射文件

<!-- 根据用户名称查询用户信息,可能返回多条
    ${}:表示sql的拼接,通过${}接收参数,将参数的内容不加任何修饰拼接在sql中。
    
     -->
    <select >
        select * from user where username like '%${value}%'
    </select>
  • 使用${}接收参数,此种方式相当于拼接 ,不能防止SQL注入

测试


    @Test
    public void testFindUserByName() {

        // 通过sqlSessionFactory创建sqlSession

        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 通过sqlSession操作数据库
        // 第一个参数:statement的位置,等于namespace+statement的id
        // 第二个参数:传入的参数
        List<User> list = null;
        try {
            list = sqlSession.selectList("test.findUserByName", "%小明%");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭sqlSession
            sqlSession.close();
        }

        System.out.println(list.get(0).getUsername());

    }

2.7 MyBatis开发过程小结

  • 1、编写SqlMapConfig.xml
  • 2、编写mapper.xml,定义了statement
  • 3、编程通过配置文件创建SqlSessionFactory
  • 4、通过SqlSessionFactory获取SqlSession
  • 5、通过。操作数据库,如果执行添加、更新、删除需要调用SqlSession.commit()
  • 6、SqlSesion使用完成要关闭

2.8 用户添加

  • 向用户表插入一条记录。

修改映射文件

<!-- 添加用户
    parameterType:输入 参数的类型,User对象 包括 username,birthday,sex,address
    #{}接收pojo数据,可以使用OGNL解析出pojo的属性值
    #{username}表示从parameterType中获取pojo的属性值
     -->
    <insert >
        INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
    </insert>

测试

@Test
    public void testInsertUser() {

        // 通过sqlSessionFactory创建sqlSession

        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 通过sqlSession操作数据库
        // 创建插入数据对象
        User user = new User();
        user.setUsername("浪子燕青");
        user.setAddress("河南郑州");
        user.setBirthday(new Date());
        user.setSex("1");

        try {
            sqlSession.insert("test.insertUser", user);
            // 需要提交事务
            sqlSession.commit();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭sqlSession
            sqlSession.close();
        }
        System.out.println("用户的id=" + user.getId());

    }

    // 测试根据id删除用户(得到单条记录)
    @Test
    public void testDeleteUser() {

        // 通过sqlSessionFactory创建sqlSession

        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 通过sqlSession操作数据库
        try {
            sqlSession.delete("test.deleteUser", 35);
            // 需要提交事务
            sqlSession.commit();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭sqlSession
            sqlSession.close();
        }

    }

主键返回

  • 需求:user对象插入到数据库后,新记录的主键要通过user对象返回,通过user获取主键值。
  • 解决思路:
  • 通过LAST_INSERT_ID()获取刚插入记录的自增主键值,在insert语句执行后,执行select LAST_INSERT_ID()就可以获取自增主键。
<!--

order:设置selectKey中sql执行的顺序,相对于insert语句来说
keyProperty:将主键值设置到哪个属性
resultType:select LAST_INSERT_ID()的结果 类型
-->
<insert >
        <selectKey keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID()
        </selectKey>
        
        INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
    </insert>
  • 使用mysql的uuid机制生成主键
  • 使用uuid生成主键的好处是不考虑数据库移植后主键冲突问题。
    • 实现思路:先查询uuid得到主键,将主键设置到user对象中,将user对象插入数据库。
<insert >
    <selectKey keyProperty="id" order="BEFORE" resultType="string">
        select uuid()
    </selectKey>
    
    INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
  • 实现 oracle数据库主键返回,如何做??
  • oracle没有自增主键机制,使用序列完成主键生成。
  • 实现思路:
  • 先查询序列得到主键,将主键设置到user对象中,将user对象插入数据库。
<insert >
        <selectKey keyProperty="id" order="BEFORE" resultType="int">
            select 序列.nextval() from dual
        </selectKey>
        
        INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address})
    </insert>

2.9 用户删除和更新

修改映射文件

<!-- 用户删除  -->
    <delete >
     delete from user where id=#{id}
    </delete>
    <!-- 用户更新 
    要求:传入的user对象中包括 id属性值
    -->
    <update >
        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
    </update>

测试

// 测试根据id删除用户(得到单条记录)
@Test
public void testDeleteUser() {
    
    // 通过sqlSessionFactory创建sqlSession
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    // 通过sqlSession操作数据库
    try {
        sqlSession.delete("test.deleteUser", 35);
        // 需要提交事务
        sqlSession.commit();
    
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 关闭sqlSession
        sqlSession.close();
    }
    
    
}
    
// 测试根据id更新用户(得到单条记录)
@Test
public void testUpdateUser() {
    
    // 通过sqlSessionFactory创建sqlSession
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    // 通过sqlSession操作数据库
    // 创建更新数据对象,要求必须包括 id
    User user = new User();
    user.setId(35);
    user.setUsername("燕青");
    user.setAddress("河南郑州");
//      user.setBirthday(new Date());
    user.setSex("1");
    
    try {
        sqlSession.update("test.updateUser", user);
        // 需要提交事务
        sqlSession.commit();
    
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 关闭sqlSession
        sqlSession.close();
    }
    
        System.out.println("用户的id=" + user.getId());
    
    }

三、Mybatis 与JDBC

  • 1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
    • 解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
  • 2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
    • 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
  • 3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
    • 解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
  • 4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
    • 解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

四、Mybatis与Hibernate

  • 企业开发进行技术选型 ,考虑mybatis与hibernate适用场景。
  • mybatis:入门简单,程序容易上手开发,节省开发成本 。mybatis需要程序员自己编写sql语句,是一个不完全 的ORM框架,对sql修改和优化非常容易实现 。
  • mybatis适合开发需求变更频繁的系统,比如:互联网项目。
  • hibernate:入门门槛高,如果用hibernate写出高性能的程序不容易实现。hibernate不用写sql语句,是一个 ORM框架。
  • hibernate适合需求固定,对象数据模型稳定,中小型项目,比如:企业OA系统。
  • 总之,企业在技术选型时根据项目实际情况,以降低成本和提高系统 可维护性为出发点进行技术选型。

五、配置文件

5.1 SqlMapConfig.xml

  • 是Mybatis全局配置文件,只有一个,名称不固定的

5.2 Mapper.xml

  • mapper.xml是以statement为单位进行配置。(把一个sql称为一个statement),satatement中配置 sql语句、parameterType输入参数类型(完成输入映射)、resultType输出结果类型(完成输出映射)。
  • 还提供了parameterMap配置输入参数类型(过期了,不推荐使用了)
  • 还提供resultMap配置输出结果类型(完成输出映射)

5.3 #{}

  • 表示一个占位符,向占位符输入参数,mybatis自动进行java类型和jdbc类型的转换。
  • 程序员不需要考虑参数的类型,比如:传入字符串,mybatis最终拼接好的sql就是参数两边加单引号。
  • #{}接收pojo数据,可以使用OGNL解析出pojo的属性值

5.4 ${}

  • 表示sql的拼接,通过${}接收参数,将参数的内容不加任何修饰拼接在sql中。
  • ${}也可以接收pojo数据,可以使用OGNL解析出pojo的属性值
  • 缺点:不能防止sql注入。

六、Mybatis 重要 API

6.1 SqlSession

6.2 SqlSessionFactoryBuilder

  • SqlSessionFactoryBuilder是以工具类方式来使用,需要创建sqlSessionFactory就new一个SqlSessionFactoryBuilder。

6.3 sqlSessionFactory

  • 正常开发时,以单例方式管理sqlSessionFactory,整个系统运行过程中sqlSessionFactory只有一个实例,将来和spring整合后由spring以单例方式管理sqlSessionFactory。

6.4 SqlSession

  • sqlSession是一个面向用户(程序员)的接口,程序员调用sqlSession的接口方法进行操作数据库。
  • sqlSession能否以单例 方式使用??
    • 由于sqlSession是线程不安全,所以sqlSession最佳应用范围在方法体内,在方法体内定义局部变量使用sqlSession。

七、Mapper代理的方式

7.1 简介

  • 原始dao开发方式,程序员需要写dao接口和dao 的实现类
    • dao的实现类中存在重复代码,整个mybatis操作的过程代码模板重复(先创建sqlsession、调用sqlsession的方法、关闭sqlsession)
    • dao的实现 类中存在硬编码,调用sqlsession方法时将statement的id硬编码。
  • mapper代理的方式,程序员只需要写dao接口,dao接口实现对象由mybatis自动生成代理对象。本身dao在三层架构中就是一个通用的接口。

7.2 mapper开发规范

  • 要想让mybatis自动创建dao接口实现类的代理对象,必须遵循一些规则:

  • 1、mapper.xml中namespace指定为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">
<!-- namespace命名空间,为了对sql语句进行隔离,方便管理 ,mapper开发dao方式,使用namespace有特殊作用
mapper代理开发时将namespace指定为mapper接口的全限定名
 -->
<mapper namespace="com.hao.mybatis.mapper.UserMapper">
<!-- 在mapper.xml文件中配置很多的sql语句,执行每个sql语句时,封装为MappedStatement对象
mapper.xml以statement为单位管理sql语句
 -->
  • 此步骤目的:通过mapper.xml和mapper.java进行关联。

  • 2、mapper.xml中statement的id就是mapper.java中方法名

  • 3、mapper.xml中statement的parameterType和mapper.java中方法输入参数类型一致

  • 4、mapper.xml中statement的resultType和mapper.java中方法返回值类型一致.

  • 5、mapper映射文件的命名方式建议:表名Mapper.xml

<!-- 根据id查询用户信息 -->
    <!-- 
        id:唯一标识 一个statement
        #{}:表示 一个占位符,如果#{}中传入简单类型的参数,#{}中的名称随意
        parameterType:输入 参数的类型,通过#{}接收parameterType输入 的参数
        resultType:输出结果 类型,不管返回是多条还是单条,指定单条记录映射的pojo类型
     -->
    <select >
        SELECT * FROM USER WHERE id= #{id}
    
    </select>

7.3 mapper接口

  • mybatis提出了mapper接口,相当 于dao 接口。
  • mapper接口的命名方式建议:表名Mapper
public interface UserMapper {
    //根据用户id查询用户信息
    public User findUserById(int id) throws Exception;
}

7.4 在SqlMapConfig.xml中加载

<mappers>
         <mapper resource="mapper/UserMapper.xml" /> 
</mappers>

7.5 返回单个对象和集合对象

  • 不管查询记录是单条还是多条,在statement中resultType定义一致,都是单条记录映射的pojo类型。
  • mapper接口方法返回值,如果是返回的单个对象,返回值类型是pojo类型,生成的代理对象内部通过selectOne获取记录,如果返回值类型是集合对象,生成的代理对象内部通过selectList获取记录。
//根据用户id查询用户信息
    public User findUserById(int id) throws Exception;
    
    //根据用户名称  查询用户信息
    public List<User> findUserByName(String username) throws Exception;

7.6 问题

返回值的问题

  • 如果方法调用的statement,返回是多条记录,而mapper.java方法的返回值为pojo,此时代理对象通过selectOne调用,由于返回多条记录,所以报错: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

输入参数的问题

  • 使用mapper代理的方式开发,mapper接口方法输入参数只有一个,可扩展性是否很差
  • 可扩展性没有问题,因为dao层就是通用的,可以通过扩展pojo(定义pojo包装类型)将不同的参数(可以是pojo也可以简单类型)传入进去。

八、sqlMapConfig.xml 配置文件

  • SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)

8.1 properties属性定义

  • 可以把一些通用的属性值配置在属性文件中,加载到mybatis运行环境内。
  • 比如:创建db.properties配置数据库连接参数。

<!-- 属性定义
    加载一个properties文件
    在 properties标签 中配置属性值
     -->
<properties resource="db.properties">
    <!-- <property name="" value=""/> -->
</properties>
<!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment >
        <!-- 使用jdbc事务管理-->
            <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>

  • 注意 MyBatis 将按照下面的顺序来加载属性:
  • 在 properties 元素体内定义的属性首先被读取。
  • 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
  • 最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
  • 建议使用properties,不要在properties中定义属性,只引用定义的properties文件中属性,并且properties文件中定义的key要有一些特殊的规则。

8.2 settings全局参数配置

  • mybatis运行时可以调整一些全局参数(相当于软件的运行参数)
  • 根据使用需求进行参数配置。
  • 注意:小心配置,配置参数会影响mybatis的执行。
  • ibatis的全局配置参数中包括很多的性能参数(最大线程数,最大待时间。。。),通过调整这些性能参数使ibatis达到高性能的运行,mybatis没有这些性能参数,由mybatis自动调节。

8.3 typeAliases(常用)

  • 可以将parameterType、resultType中指定的类型 通过别名引用。

8.4 mybaits提供了很多别名

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

8.5 自定义别名

  • 可以单个定义也可以批量定义
<!-- 定义 别名 -->
    <typeAliases>
        <!--
        单个别名的定义
        alias:别名,type:别名映射的类型  -->
        <!-- <typeAlias type="com.hao.mybatis.po.User" alias="user"/> -->
        <!-- 批量别名定义
        指定包路径,自动扫描包下边的pojo,定义别名,别名默认为类名(首字母小写或大写)
         -->
        <package name="com.hao.mybatis.po"/>
        
    </typeAliases>

8.6 使用别名

  • 在parameterType、resultType中使用别名:
<select >
        SELECT * FROM USER WHERE id= #{id}
</select>

8.7 typeHandlers

  • 类型处理器将java类型和jdbc类型进行映射。
  • mybatis默认提供很多类型处理器,一般情况下够用了。

8.8 mappers

<!--加载mapper映射
    如果将和spring整合后,可以使用整合包中提供的mapper扫描器,此处的mappers不用配置了。
     -->
    <mappers>
        <!-- 通过resource引用mapper的映射文件 -->
        <mapper resource="sqlmap/User.xml" />
        <!-- <mapper resource="mapper/UserMapper.xml" />  此处代码中已经删除掉了,移到了mapper.java 同目录下-->
        <!-- 通过class引用mapper接口 
        class:配置mapper接口全限定名
        要求:需要mapper.xml和mapper.java同名并且在一个目录 中
        -->
        <!-- <mapper class="com.hao.mybatis.mapper.UserMapper"/> -->
        <!-- 批量mapper配置 
        通过package进行自动扫描包下边的mapper接口,
        要求:需要mapper.xml和mapper.java同名并且在一个目录 中
        
        -->
        <package name="com.hao.mybatis.mapper"/>
        
    </mappers>

8.9 输入和输出映射

  • 通过parameterType完成输入映射,通过resultType和resultMap完成输出映射。

九、resultMap

9.1 简介

  • resultType:指定输出结果的类型(pojo、简单类型、hashmap..),将sql查询结果映射为java对象,使用resultType注意:sql查询的列名要和resultType指定pojo的属性名相同,指定相同 属性方可映射成功,如果sql查询的列名要和resultType指定pojo的属性名全部不相同,list中无法创建pojo对象的。
  • resultMap:将sql查询结果映射为java对象。如果sql查询列名和最终要映射的pojo的属性名不一致,使用resultMap将列名和pojo的属性名做一个对应关系 (列名和属性名映射配置)

9.2 resultMap配置

<!-- 定义resultMap,列名和属性名映射配置
    id:mapper.xml中的唯一标识 
    type:最终要映射的pojo类型
     -->
    <resultMap  >
        <!-- 列名
        id_,username_,birthday_
        id:要映射结果集的唯 一标识 ,称为主键
        column:结果集的列名
        property:type指定的哪个属性中
         -->
         <id column="id_" property="id"/>
         <!-- result就是普通列的映射配置 -->
         <result column="username_" property="username"/>
         <result column="birthday_" property="birthday"/>
    </resultMap>

9.3 resultMap

<!-- 使用resultMap作结果映射
    resultMap:如果引用resultMap的位置和resultMap的定义在同一个mapper.xml,
    直接使用resultMap的id,如果不在同一个mapper.xml要在resultMap的id前边加namespace
    
     -->
    <select >
    
        select id id_,username username_,birthday birthday_ from user where username like '%${userCustom.username}%'
    </select>

9.4 mapper.java

//查询用户,使用resultMap进行映射
    public List<User> findUserListResultMap(UserQueryVo userQueryVo)throws Exception;

十、动态sql

  • mybatis重点是对sql的灵活解析和处理。

10.1 需求

  • 将自定义查询条件查询用户列表和查询用户列表总记录数改为动态sql

10.2 if和where

    <!-- where标签相当 于where关键字,可以自动去除第一个and -->
        <where>
            <if test="userCustom!=null">
              ....
            </if>
            
        </where>

10.3 sql片段

  • 通过sql片段可以将通用的sql语句抽取出来,单独定义,在其它的statement中可以引用sql片段。
  • 通用的sql语句,常用:where条件、查询列

10.4 sql片段的定义

<!-- 将用户查询条件定义为sql片段
    建议对单表的查询条件单独抽取sql片段,提高公用性
    注意:不要将where标签放在sql片段
      -->
    <sql >
            <!-- 如果 userQueryVo中传入查询条件,再进行sql拼接-->
            <!-- test中userCustom.username表示从userQueryVo读取属性值-->
            <if test="userCustom!=null">
                <if test="userCustom.username!=null and userCustom.username!=''">
                    and username like '%${userCustom.username}%'
                </if>
                <if test="userCustom.sex!=null and userCustom.sex!=''">
                    and sex = #{userCustom.sex}
                </if>
                <!-- 根据id集合查询用户信息 -->
                <!-- 最终拼接的效果:
                SELECT id ,username ,birthday  FROM USER WHERE username LIKE '%小明%' AND id IN (16,22,25)
                collection:集合的属性
                open:开始循环拼接的串
                close:结束循环拼接的串
                item:每次循环取到的对象
                separator:每两次循环中间拼接的串
                 -->
                 <foreach collection="ids" open=" AND id IN ( " close=")" item="id" separator=",">
                    #{id}
                 </foreach>
                 <!-- 
                 SELECT id ,username ,birthday  FROM USER WHERE username LIKE '%小明%' AND (id = 16 OR id = 22 OR id = 25) 
                  <foreach collection="ids" open=" AND ( " close=")" item="id" separator="OR">
                    id = #{id}
                 </foreach>
                  -->
                <!-- 还有很的查询条件 -->
            </if>
    </sql>

10.5 引用sql片段

<!-- where标签相当 于where关键字,可以自动去除第一个and -->
        <where>
            <!-- 引用sql片段,如果sql片段和引用处不在同一个mapper必须前边加namespace -->
            <include ref></include>
            <!-- 下边还有很其它的条件 -->
            <!-- <include ref></include> -->
        </where>
 

10.6 foreach

  • 在statement通过foreach遍历parameterType中的集合类型。