Mybatis【一篇足矣】

在这里插入图片描述

Mybatis学习笔记

一、Mybatis框架

1.概述

  1. mybatis是什么?有什么特点?

    它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它和数据库无关性较低。

  1. 什么是ORM?

Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指得是数据库中的关系模型,对象关系映射,指的就是Java对象和数据库的关系模型之间建立一种对应关系。比如:用一个Java的Student类,去对应数据库中的一张student表,一个Student对象就对应student表中的一行数据,类中的属性和表中的列一一对应。

  1. 为什么Mybatis是半自动的ORM框架?

用Mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射,就可以直接进行CRUD操作了。由于Mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialet),所以Mybatis的数据库无关性比较低。虽然Mybatis需要手写SQL,但相比JDBC,他提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发效率。

2.原理示意图

img

  1. Mybatis配置

    SQLMapConfig.xml,此文件作为Mybatis的全局配置文件,配置了Mybatis的运行环境等信息,此后会有详细介绍。mapper.xml文件即SQL映射文件,文件中配置了操作数据库的SQL语句。此文件需要在SQLMapConfig.xml中加载。

  2. 通过Mybatis环境等配置信息构造SqlSessionFactory,即会话工厂

  3. 有会话工厂(SqlSessionFactory)创建sqlSession即会话,操作数据库需要通过sqlSession进行。

  4. Mybatis底层自定义了Executor执行器接口来操作数据库,Executor接口有两个实现,一个是基本执行器,一个是缓存执行器

  5. Mybatis底层自定义了Executor执行器接口来操作数据库,Executor接口有两个实现,一个是基本执行器,一个是缓存执行器

  6. Mapped Statement也是Mybatis一个底层封装对象,它包含了Mybatis配置信息以及SQL映射信息等。mapper.xml文件中一个SQL对应一个Maped Statement对象,SQL的id即是Mapped Statement的id。

  7. Mapped Statement对SQL输入参数进行定义,包含HashMap、基本数据类型、POJO等,Executor通过Mapped Statement在执行SQL前,将输入的java对象映射到SQL中,输入参数映射就是在JDBC编程中对PreparedStatement设置参数。

  8. Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo等,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果集的解析处理过程

二、入门程序

1.原生开发

1.在jdbc数据库中,创建一张tbl_employee表(d_id字段暂时用不到)和tbl_dept表(本阶段暂时用不到此表)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.打开IDEA,创建一个maven项目
3.导入依赖jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.wangsuhang</groupId>
    <artifactId>MyBatis3</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.9</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
    </dependencies>
    <!--静态资源导出问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
4.创建一个pojo类(一个映射类)
package com.wangsuhang.mybatis_01_helloworld.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author suahng
 * @date 2021-07-06 9:56
 * @dec
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private String gender;
}
5.编写mapper.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: 名称空间;指定为接口的全类名(第二种方式这样写)
        id:唯一标识,推荐使用mapper中接口的 具体 方法名
        resultType:返回值类型
        #{id}:从传递过来的参数中取出id值
        -->
<mapper namespace="com.wangsuhang.mybatis_01_helloworld">
<select id="getEmpById" resultType="com.wangsuhang.mybatis_01_helloworld.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>
</mapper>
6.编写全局配置文件SQLMapConfig.xml( mybatis-config.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>
    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--设置驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbc"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--sql mapper(SQL映射文件)的位置-->
    <mappers>
    	<!--就是上一步的mappe.xml文件-->
        <mapper resource="EmployeeMapper.xml" />
    </mappers>
</configuration>
7.测试代码和运行结果
package com.wangsuhang.mybatis_01_helloworld.test;
import com.wangsuhang.mybatis_01_helloworld.mapper.EmployeeMapper;
import com.wangsuhang.mybatis_01_helloworld.pojo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisTest {
    /**
     * 1.根据xml配置文件(全局配置文件 mybatis-config.xml )创建一个 SqlSessionFactory 对象
     *      有数据源的一些信息
     * 2.sql映射文件(EmployeeMapper2.xml):配置了每一个sql,以及 sql 的封装规则
     * 3.将 sql 映射文件注册在全局配置文件中
     * 4.在测试类中写具体的代码:
     *       1)根据全局配置文件得到 SQLSessionFactory
     *       2)使用 SQLSession工厂,获取 sqlSession 对象,使用他来执行增删改查
     *           一个 sqlSession 就是代表和数据库的一个会话,用完关闭
     *       3)使用 sql 的唯一标识来告诉 MyBatis执行哪个SQL。 sql都是保存在sql映射文件中
     */
    @Test
    public void testMyBatis() throws IOException {
        //1.获取sqlSessionFactory对象
        String config = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        System.out.println(sqlSessionFactory);
        //2.获取 sqlSession 实例,能直接执行已经映射的 sql 语句
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //sql的唯一标识:statement- Unique identifier matching the statement to use.
        //即mapper.xml文件中的namespace + SQL语句的id
        //执行SQL要用的参数:parameter- A parameter object to pass to the statement.
        Employee employee = sqlSession.selectOne("com.wangsuhang.mybatis_01_helloworld.getEmpById", 1);
        System.out.println(employee);
        //关闭资源
        sqlSession.close();
    }
}

运行结果

com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.wangsuhang.mybatis_01_helloworld.test.MyBatisTest,testMyBatis
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@f6c48ac
Opening JDBC Connection
Created connection 81009902.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4d41cee]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4d41cee]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4d41cee]
Returned connection 81009902 to pool.
Process finished with exit code 0

2.Mapper动态代理方式开发DAO

1.实现原理

Mapper接口开发放肆只需要程序员编写Mapper接口(相当于DAO接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同DAO接口的实现类方法。

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

  • mapper.xml文件中namespace与mapper的全类名相同。
  • Mapper接口方法名和mapper.xml中定义的每个statement(即具体的SQL语句)的id相同。
  • Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同。
  • Mapper接口方法的输出类型参数类型和mapper.xml中定义的每个resultType的类型相同。
2.改写mapper.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: 名称空间;指定为接口的全类名
        id:唯一标识,推荐使用mapper中接口的 具体 方法名
        resultType:返回值类型
        #{id}:从传递过来的参数中取出id值
        -->
<mapper namespace="com.wangsuhang.mybatis_01_helloworld.mapper.EmployeeMapper">
	<select id="getEmpById" resultType="com.wangsuhang.mybatis_01_helloworld.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>
</mapper>
3.编写XxxMapper.java(接口文件)
package com.wangsuhang.mybatis_01_helloworld.mapper;
import com.wangsuhang.mybatis_01_helloworld.pojo.Employee;
/**
 * @author suahng
 * @date 2021-07-06 14:18
 * @dec
 */
public interface EmployeeMapper {
    public Employee getEmpById(Integer id);
}
4.测试代码和运行结果
package com.wangsuhang.mybatis_01_helloworld.test;
import com.wangsuhang.mybatis_01_helloworld.mapper.EmployeeMapper;
import com.wangsuhang.mybatis_01_helloworld.pojo.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
 * @author suahng
 * @date 2021-07-06 10:49
 * @dec
 *
 * 1.接口式编程
 *   原生:       Dao     ====>    DaoImpl
 *   mybatis:   Mapper  ====>    xxMapper.xml
 * 2.SqlSession:代表和数据库的一次会话,用完必须关闭
 * 3.SqlSession和Connection 一样它都是非线程安全。每次使用都应该获取新的对象
 * 4.mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象
 *      (将接口和xml进行绑定)
 *   EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
 * 5.两个重要的配置文件:
 *      mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息的那个...系统运行环境信息
 *      sql映射文件:保存了每一个sql语句的映射信息,将sql抽取了出来了
 */
public class MyBatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String config = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(config);
        return new SqlSessionFactoryBuilder().build(is);
    }
    /**
     * 1.获取sqlSessionFactory对象
     *      解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSessionFactory
     *      注意:MappedStatement:代表一个增删改查的详细信息
     * 2.获取SQLSession对象
     *      返回一个DefaultSqlSession对象,包含Executor和Configuration
     *      这一步会创建Executor对象;
     * 3.获取接口的代理对象(MapperProxy)
     *      getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象
     *      代理对象里面包含了,DefaultSqlSession(Executor)
     *
     * 4.执行增删改操作
     *
     *
     * 总结:
     * 1.根据配置文件(全局,sql映射)初试化出Configuration对象
     * 2.创建一个DefaultSqlSession对象,
     *      他里面包含Configuration以及
     *      Executor(根据全局配置文件的defaultExecutorType创建出对应的Executor)
     * 3.DefaultSqlSession.getMapper(),拿到Mapper接口对应的MapperProxy
     * 4.MapperProxy里面有(DefaultSqlSession);
     * 5.执行增删改查方法:
     *      1)调用DefaultSession的增删改查(Executor);
     *      2)会创建一个StatementHandler对象;(同时也会创建出ParameterHandler和ResultSetHandler)
     *      3)调用StatementHandler预编译参数以及设置参数值;
     *          使用ParameterHandler来给sql设置参数
     *      4)调用StatementHandler的增删改查方法;
     *      5)ResultSetHandler封装结果
     * 注意:
     *  四大对象(Executor,ParameterHandler,ResultSetHandler,StatementHandler)
     *  每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler)
     *
     * @throws IOException
     */
    @Test
    public void test01() throws IOException {
        //1.获取sqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //2.获取SQLSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            //3.获取接口的实现类对象
            //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            System.out.println(mapper.getClass());
            Employee emp = mapper.getEmpById(1);
            System.out.println(mapper.getClass());
            System.out.println(emp);
        }finally {
            //4.关闭资源
            sqlSession.close();
        }
    }
}

运行结果

com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.wangsuhang.mybatis_01_helloworld.test.MyBatisTest,test01
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
class com.sun.proxy.$Proxy4
Opening JDBC Connection
Created connection 1039949752.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3dfc5fb8]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
class com.sun.proxy.$Proxy4
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3dfc5fb8]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3dfc5fb8]
Returned connection 1039949752 to pool.

Process finished with exit code 0

三、全局配置文件

1.配置文件内容

全局配置文件中,各个标签要按照如下的顺序进行配置,因为Mybatis加载配置文件的原码中是按照这个顺序进行解析的。

<configuration>
	<!-- 配置顺序如下
     properties  
     settings
     typeAliases
     typeHandlers
     objectFactory
     plugins
     environments
        environment
            transactionManager
            dataSource
     mappers
     -->
</configuration>

各个标签说明如下:

  • properties(属性)

  • settings(全局配置参数)

  • typeAliases(类型别名)

  • typeHandlers(类型处理器)

  • objectFactory(对象工厂)

  • plugins(插件)

  • environments(环境集合属性对象)

    • environment(环境子属性对象)
      • transactionManager(事务管理器)
      • dataSource(数据源)
  • databaseIdProvider(数据库厂商标识)

  • mappers(映射器)

1.1properties(属性)

这些属性可以在外部进行配置,并可以进行动态替换。

classpath下定义dbconfig.properties文件

jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/jdbc?rewriteBatchedStatements=true
jdbc.driver=com.mysql.jdbc.Driver

全局配置文件中引用如下:

	<properties resource="dbconfig.properties"/>
    <!--
        1.mybatis可以使用 properties 来引入外部properties 配置文件的内容
          resource:引入类路径下的资源
          url:引入网络路径或者磁盘路径下的资源
    -->
    <environments default="mysql">
        <environment id="mysql">
            <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)==传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

1.2settings(全局配置参数)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

设置名描述有效值默认值
cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
aggressiveLazyLoading开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。true | falsefalse (在 3.4.1 及之前的版本中默认为 true)
multipleResultSetsEnabled是否允许单个语句返回多结果集(需要数据库驱动支持)。true | falsetrue
useColumnLabel使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。true | falsetrue
useGeneratedKeys允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。true | falseFalse
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL
autoMappingUnknownColumnBehavior指定发现自动映射目标未知列(或未知属性类型)的行为。NONE: 不做任何反应WARNING: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARNFAILING: 映射失败 (抛出 SqlSessionException)NONE, WARNING, FAILINGNONE
defaultExecutorType配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。SIMPLE REUSE BATCHSIMPLE
defaultStatementTimeout设置超时时间,它决定数据库驱动等待数据库响应的秒数。任意正整数未设置 (null)
defaultFetchSize为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。任意正整数未设置 (null)
defaultResultSetType指定语句默认的滚动策略。(新增于 3.5.2)FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置)未设置 (null)
safeRowBoundsEnabled是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。true | falseFalse
safeResultHandlerEnabled是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。true | falseTrue
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falseFalse
localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。SESSION | STATEMENTSESSION
jdbcTypeForNull当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。OTHER
lazyLoadTriggerMethods指定对象的哪些方法触发一次延迟加载。用逗号分隔的方法列表。equals,clone,hashCode,toString
defaultScriptingLanguage指定动态 SQL 生成使用的默认脚本语言。一个类型别名或全限定类名。org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
defaultEnumTypeHandler指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5)一个类型别名或全限定类名。org.apache.ibatis.type.EnumTypeHandler
callSettersOnNulls指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。true | falsefalse
returnInstanceForEmptyRow当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2)true | falsefalse
logPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串未设置
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
proxyFactory指定 Mybatis 创建可延迟加载对象所用到的代理工具。CGLIB | JAVASSISTJAVASSIST (MyBatis 3.3 以上)
vfsImpl指定 VFS 的实现自定义 VFS 的实现的类全限定名,以逗号分隔。未设置
useActualParamName允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)true | falsetrue
configurationFactory指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3)一个类型别名或完全限定类名。未设置
shrinkWhitespacesInSql从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5)true | falsefalse
defaultSqlProviderTypeSpecifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), when these attribute was omitted.A type alias or fully qualified class nameNot set

一个配置完整的 settings 元素的示例如下:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

本例中使用的settings元素有:

    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--设置驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
1.3 typeAliases(类型别名)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:

@Alias("author")
public class Author {
    ...
}

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

所以,我们在别名的时候,不要占用上面已有的别名,它们都是大小写不敏感的。

1.4typeHandlers(类型处理器)

MyBatis 在设置预处理语句(PreparedStatement)中的参数,或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。

理解:用于处理Java类型和Jdbc类型之间的转换,mybatis有许多内置的TypeHandler

    <select id="getEmpById" parameterType="int" resultType="com.wangsuhang.mybatis_01_helloworld.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>
1.5objectFactory(对象工厂)

mybatis会根据resultTyperesultMap的属性来将查询得到的结果封装成对应的Java类,它有一个默认的DefaultObjectFactory,用于创建对象实例,这个标签用的也不多

1.6plugins(插件)

可以用来配置mybatis的插件,比如在开发中经常需要对查询结果进行分页,就需要用到pageHelper分页插件,这些插件就是通过这个标签进行配置的。

<!-- PageHelper 分页插件 -->
<plugins>
  <plugin interceptor="com.github.pagehelper.PageInterceptor">
     <property name="helperDialect" value="mysql"/>
  </plugin>
</plugins>
1.7environments(环境配置)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置。

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境

所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:

  • 每个数据库对应一个 SqlSessionFactory 实例

为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

如果忽略了环境参数,那么将会加载默认环境,如下所示:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);

environments 元素定义了如何配置环境。

environment:指定据具环境

  • id:指定当前环境的唯一标识
  • transactionManager:事务管理器
  • dataSource:数据源
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>
  </environment>
</environments>

注意一些关键点:

  • 默认使用的环境 ID(比如:default=“development”)。
  • 每个 environment 元素定义的环境 ID(比如:id=“development”)。
  • 事务管理器的配置(比如:type=“JDBC”)。
  • 数据源的配置(比如:type=“POOLED”)。

默认环境和环境 ID 顾名思义, 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。

本例中使用如下:

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/jdbc"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
1.8databaseIdProvider(数据库厂商标识)

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:

    <databaseIdProvider type="DB_VENDOR">
        <!-- 为不同的数据库厂商起别名 -->
        <property name="MySQL" value="mysql1"/>
        <property name="Oracle" value="oracle"/>
    </databaseIdProvider>

在mapper.xml中使用:

    <select id="getEmpById" resultType="com.wangsuhang.mybatis_02_config.pojo.Employee"
        databaseId="mysql1">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>

Mybatis匹配规则如下:

  • 如果没有配置databaseIdProvider标签,那么databaseId=null;
  • 如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上,则设置databaseId=配置指定的值,否则,依旧为null;
  • Mybatis会加载不带databaseId属性和带有匹配当前数据库databaseId属性的所有语句。如果同时找到带有databaseId和不带databaseId的相同语句,则后者会被舍弃。
1.9mappers(映射器)

mapper配置的几种方法:

  • <mapper resource=" " />

    使用相对于类路径的资源引用

        <mappers>
            <mapper resource="EmployeeMapper3.xml" />
            <mapper resource="EmployeeMapperPlus.xml" />
            <mapper resource="DepartmentMapper.xml"/>
        </mappers> 
  • <mapper url=" " />

    使用完全限定资源定位符(UEL)

    <mapper url="file:///F:\code\MyBatis3\src\main\resources\EmployeeMapper2.xml" /> 
  • <mapper class=" " />

    使用映射器接口实现类的完全限定类名

    注意:

    1.有sql映射文件,映射文件名必须和接口同名,并且与接口统一目录下;

    2.没有sql映射 文件,所有的sql都是利用注解写在接口上

        <mappers>
            <mapper resource="EmployeeMapper2.xml" />
            <mapper class="com.wangsuhang.mybatis_02_config.mapper.EmployeeMapperAnnotation"/>
        </mappers>
    

本例中使用的是第二种方式:

package com.wangsuhang.mybatis_02_config.mapper;
import com.wangsuhang.mybatis_01_helloworld.pojo.Employee;
import org.apache.ibatis.annotations.Select;
/**
 * @author suahng
 * @date 2021-07-06 20:23
 * @dec
 */
public interface EmployeeMapperAnnotation {
    @Select("select * from tbl_employee where id = #{id}")
    public Employee getEmpById(Integer id);
}
 
  • <package name=" " />

    将包内的映射器接口实现全部注册为映射器

    注意:

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

    <mappers>
      <package name="org.mybatis.builder"/>
    </mappers> 
  • 四、参数传递

    1.输入参数

    1.1单个参数

    可以接收基本类型,对象类型,集合类型的值。这种情况下Mybatis可以直接使用这个参数,不需要经过任何处理。

    dao接口:

    package com.wangsuhang.mybatis_03_mapper.mapper;
    import com.wangsuhang.mybatis_03_mapper.pojo.Employee;
    /**
     * @author suahng
     * @date 2021-07-06 14:18
     * @dec
     */
    public interface EmployeeMapper {
        public Employee getEmpById(Integer id);
    }
    

mapper.xml文件中对应的sql语句:

	<select id="getEmpById" resultType="com.wangsuhang.mybatis_03_mapper.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>

测试程序及结果

    @Test
    public void test() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //1.获取到的SQLSession不会自动提交数据
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee emp = mapper.getEmpById(1);
            System.out.println(emp);
            sqlSession.commit();
        }finally {
            sqlSession.close();
        }
    }
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

1.2.多个参数
1.2.1多个参数-按位置

任意多个参数,都会被Mybatis重新包装成一个Map传入。Map的key是param1,param2… 或arg0,arg1…;value就是参数的值;

dao接口:

List<Employee> getEmpByIdOrLastName(Integer id,String lastName);

mapper.xml文件中对应的sql语句:

    <!--  Employee getEmpByIdOrLastName(Integer id,String lastName); -->
    <select id="getEmpByIdOrLastName" resultType="com.wangsuhang.mybatis_03_mapper.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{param1} or last_name = #{arg1}
    </select>

测试程序及结果:

	EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
    List<Employee> emps = mapper.getEmpByIdOrLastName(1, "admin");
    emps.forEach(System.out::println);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 36333492.
Returned connection 36333492 to pool.
Opening JDBC Connection
Checked out connection 36333492 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@22a67b4]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? or last_name = ? 
==> Parameters: 1(Integer), admin(String)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@22a67b4]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@22a67b4]
Returned connection 36333492 to pool.

1.2.2多个参数-使用@Param

为参数使用@param起一个名字,Mybatis就会将这些参数封装进map中,key就是我们自己指定的名字。

即在方法中形参前面加入@param(“自定义参数”),mapper.xml文件中使用#{自定义参数名}

dao接口:

	public Employee getEmpByIdAndLastName(@Param("id") Integer id, @Param("lastName") String lastName);

mapper.xml文件中对应的sql语句:

    <select id="getEmpByIdAndLastName" resultType="com.wangsuhang.mybatis_03_mapper.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id} and last_name = #{lastName}
    </select>

测试程序及结果:

     EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
     Employee emp = mapper.getEmpByIdAndLastName(1, "admin");
     System.out.println(emp);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? and last_name = ? 
==> Parameters: 1(Integer), admin(String)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

Process finished with exit code 0

1.2.3多个参数-使用对象(POJO)

当这些参数属于我们业务在中的POJO时,我们直接传递POJO。

使用java对象传递参数,java的属性值就是SQL语句需要的参数值。每个属性就是一个参数。

语法格式:#{property,javaType=java中数据类型名,jdbcType=数据库中数据类型名};javaType,jdbcType的类型Mybatis可以检测出来,一般不需要设置,常用格式为#{property};

dao接口:

	public Employee getEmpbyPojo(Employee employee);

mapper.xml文件中对应的sql语句:

    <select id="getEmpbyPojo" parameterType="com.wangsuhang.mybatis_03_mapper.pojo.Employee"
            resultType="com.wangsuhang.mybatis_03_mapper.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id} or last_name = #{lastName}
    </select>

测试程序及结果:

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = new Employee();
            employee.setId(1);
            employee.setLastName("admin");
            Employee emp = mapper.getEmpbyPojo(employee);
            System.out.println(emp);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? or last_name = ? 
==> Parameters: 1(Integer), admin(String)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

Process finished with exit code 0

异常测试:

SQL语句中字段名输入错误后测试,将lastName改为lastname:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'lastname' in 'class com.wangsuhang.mybatis_03_mapper.pojo.Employee'
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'lastname' in 'class com.wangsuhang.mybatis_03_mapper.pojo.Employee'
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'lastname' in 'class com.wangsuhang.mybatis_03_mapper.pojo.Employee'
Process finished with exit code -1

1.2.4多个参数-使用map

也可将多个参数封装为map,直接传递,mapper.xml文件使用#{key}引用参数值。

dao接口:

	public Employee getEmpByMap(Map<String,Object> map);

mapper.xml文件中对应的sql语句:

    <select id="getEmpByMap" resultType="com.wangsuhang.mybatis_03_mapper.pojo.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id} and last_name = #{lastName}
    </select>

测试程序及结果:

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            HashMap<String, Object> map = new HashMap<>();
            map.put("id",1);
            map.put("lastName","admin");
            Employee emp = mapper.getEmpByMap(map);
            System.out.println(emp);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? and last_name = ? 
==> Parameters: 1(Integer), admin(String)
<==    Columns: id, lastName, email, gender
<==        Row: 1, admin, jerry@qq.com, 女
<==      Total: 1
Employee(id=1, lastName=admin, email=jerry@qq.com, gender=女)
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

Process finished with exit code 0

2.输出参数

2.1使用resultType

resultType:执行SQL得到ResultSet转换的类型,使用类型的完全限定名或别名。注意,如果返回的是集合,那应该设置为集合包含的类型,而不是结合本身。

resultType和resultMap,不能同时使用。

2.1.1简单类型

简单类型:8种java原始类型+String

dao接口:

public int getEmpCount();

mapper.xml文件中对应的sql语句:

    <select id="getEmpCount" resultType="int">
        select count(*) from tbl_employee
    </select>

测试程序及结果:

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            int count = mapper.getEmpCount();
            System.out.println(count);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: select count(*) from tbl_employee 
==> Parameters: 
<==    Columns: count(*)
<==        Row: 30013
<==      Total: 1
30013
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

Process finished with exit code 0

2.1.2对象类型(POJO)

前面几个例子,一直在用这个,就不再另外举例了。

2.1.3map

SQL的查询结果作为Map 中的key和value;

dao接口:

    // 返回一条记录的map:key是列名,值就是对于的值
    public Map<String,Object> getEmpByIdReturnMap(Integer id);

mapper.xml文件中对应的sql语句:

    <select id="getEmpByIdReturnMap" resultType="java.util.Map">
        select * from tbl_employee where id = #{id}
    </select>

测试程序及结果:

            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Map<String, Object> emp = mapper.getEmpByIdReturnMap(1);
            System.out.println(emp);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: select * from tbl_employee where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, last_name, email, gender, d_id
<==        Row: 1, admin, jerry@qq.com, 女, 1
<==      Total: 1
{gender=女, d_id=1, last_name=admin, id=1, email=jerry@qq.com}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

Process finished with exit code 0

2.2使用resultMap

resultMap可以自定义SQL的结果和java对象属性的映射关系。更灵活的把列值赋值给指定的属性。

使用方式:

  1. 先定义resultMap,指定列名和属性的对应关系
  2. <select>中吧resultType替换成resultMap
1.2.1准备工作

每个员工有与之对应的部门,建立部门表(上面已建立),和改造员工表(加一个字段d_id,表示该员工对应的部门id)

改后的Employee.java,–>EmployeePlus.java

package com.wangsuhang.mybatis_03_mapper.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author suahng
 * @date 2021-07-06 9:56
 * @dec
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmployeePlus {
    private Integer id;
    private String lastName;
    private String email;
    private String gender;
    private Department dept;
}

部门表对应的POJO,Department.java

package com.wangsuhang.mybatis_03_mapper.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * @author suahng
 * @date 2021-07-09 19:50
 * @dec
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
    //该部门下的所有员工信息
    private List<EmployeePlus> emps;
}


1.2.2一对一查询

场景:
查询Employee的同时查询员工对应的部门
Employee====>Department
一个员工有与之对应的部门信息

dao接口:

public EmployeePlus getEmpAndDeptById(Integer id);

方式一:级联属性封装结果集

mapper.xml文件中对应的sql语句:

    <!-- 方法1:级联属性封装结果集-->
    <resultMap id="MyDifEmp" type="com.wangsuhang.mybatis_03_mapper.pojo.EmployeePlus">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender" />
        <result column="did" property="dept.id"/>
        <result column="dept_name" property="dept.departmentName"/>
    </resultMap>
    <!-- public Employee getEmpAndDeptById(Integer id); -->
    <select id="getEmpAndDeptById" resultMap="MyDifEmp2">
        SELECT e.id id,e.last_name last_name,e.email email,e.gender gender,e.d_id d_id,d.id did,d.dept_name dept_name
        FROM tbl_employee e JOIN tbl_dept d ON e.d_id = d.id
        WHERE e.id = #{id}
    </select>


测试程序及结果:

            EmployeeMapperPlus mapper = sqlSession.getMapper(EmployeeMapperPlus.class);
            EmployeePlus emp = mapper.getEmpAndDeptById(1);
            System.out.println(emp);

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: SELECT e.id id,e.last_name last_name,e.email email,e.gender gender,e.d_id d_id,d.id did,d.dept_name dept_name FROM tbl_employee e JOIN tbl_dept d ON e.d_id = d.id WHERE e.id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, last_name, email, gender, d_id, did, dept_name
<==        Row: 1, admin, jerry@qq.com, 女, 1, 1, 开发部
<==      Total: 1
EmployeePlus(id=1, lastName=admin, email=jerry@qq.com, gender=女, dept=Department(id=1, departmentName=开发部, emps=null))
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.

Process finished with exit code 0

方法2:使用association定义关联单个对象的规则

mapper.xml文件中对应的sql语句:

    <!-- 方法2:使用association定义关联单个对象的规则 -->
    <resultMap id="MyDifEmp2" type="com.wangsuhang.mybatis_03_mapper.pojo.EmployeePlus">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender" />
        <!-- association可以指定联合的javaBean对象
             property="dept":指定哪个属性是联合的对象
             JavaType:指定哪个属性对象的类型 [不能省略]
         -->
        <association property="dept" javaType="com.wangsuhang.mybatis_03_mapper.pojo.Department">
            <id column="did" property="id"/>
            <result column="dept_name" property="departmentName"/>
        </association>
    </resultMap>
    <!-- public Employee getEmpAndDeptById(Integer id); -->
    <select id="getEmpAndDeptById" resultMap="MyDifEmp2">
        SELECT e.id id,e.last_name last_name,e.email email,e.gender gender,e.d_id d_id,d.id did,d.dept_name dept_name
        FROM tbl_employee e JOIN tbl_dept d ON e.d_id = d.id
        WHERE e.id = #{id}
    </select>

测试程序及结果同上,就不在写了。

association:表示进行关联查询单条记录
property:表示关联查询的结果存储在com.wangsuhang.mybatis_03_mapper.pojo.EmployeePlus的dep属性中
javaType:表示关联查询的结果类型
<id property="did" column="id"/>:查询结果的did列对应关联对象的id属性;
<result property="。departmentName" column="dept_name"/>:查询结果的dept_name列对应关联对象的departmentName属性

1.2.2多对一查询

场景二:
查询部门的时候将部门对应的所有员工信息也查询出来:详细信息在DepartmentMapper.xml中

dao接口:

public Department getDeptByIdPlus(Integer id);

mapper.xml文件中对应的sql语句:

    <!--
        collection:嵌套结果集的方式,定义关联的集合类型元素的封装规则
    -->
    <!-- public Department getDeptByIdPlus(Integer id); -->
    <resultMap id="MyDept" type="com.wangsuhang.mybatis_03_mapper.pojo.Department">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>
        <!--
            collection:定义关联集合类型的封装规则
            property:将要关联的信息映射到哪个属性中
            ofType:指定集合里面元素的类型
         -->
        <collection property="emps" ofType="com.wangsuhang.mybatis_03_mapper.pojo.EmployeePlus">
            <!-- 定义这个集合中元素的封装规则 -->
            <id column="eid" property="id"/>
            <result column="last_name" property="lastName" />
            <result column="email" property="email"/>
            <result column="gender" property="gender"/>
        </collection>
    </resultMap>
    <select id="getDeptByIdPlus" resultMap="MyDept">
        SELECT d.id did,d.dept_name dept_name,
         e.id eid,e.last_name last_name,e.email email,e.gender gender
        FROM tbl_dept d
        LEFT JOIN tbl_employee e
        ON d.id=e.d_id
        WHERE d.id=#{did}
    </select>

测试程序及结果:

            DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
            Department dept = mapper.getDeptByIdPlus(1);
            System.out.println(dept);

Created connection 1333592072.
Returned connection 1333592072 to pool.
Opening JDBC Connection
Checked out connection 1333592072 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
==>  Preparing: SELECT d.id did,d.dept_name dept_name, e.id eid,e.last_name last_name,e.email email,e.gender gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=? 
==> Parameters: 1(Integer)
<==    Columns: did, dept_name, eid, last_name, email, gender
<==        Row: 1, 开发部, 1, admin, jerry@qq.com, 女
<==        Row: 1, 开发部, 4, wsh, wsh@qq.com, 男
<==        Row: 1, 开发部, 7, smith, smith@qq.com, 男
<==        Row: 1, 开发部, 8, allen, allen@qq.com, 男
<==        Row: 1, 开发部, 11, smith, smith@qq.com, 男
<==        Row: 1, 开发部, 12, allen, allen@qq.com, 男
<==      Total: 6
Department(id=1, departmentName=开发部, emps=[EmployeePlus(id=1, lastName=admin, email=jerry@qq.com, gender=女, dept=null), EmployeePlus(id=4, lastName=wsh, email=wsh@qq.com, gender=男, dept=null), EmployeePlus(id=7, lastName=smith, email=smith@qq.com, gender=男, dept=null), EmployeePlus(id=8, lastName=allen, email=allen@qq.com, gender=男, dept=null), EmployeePlus(id=11, lastName=smith, email=smith@qq.com, gender=男, dept=null), EmployeePlus(id=12, lastName=allen, email=allen@qq.com, gender=男, dept=null)])
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f7d0008]
Returned connection 1333592072 to pool.
Process finished with exit code 0


                                     
                                     
![在这里插入图片描述](https://img-blog.csdnimg.cn/b7bc8802456640919905d7c88da44be3.gif#pic_center)
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kai-爱记录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值