MyBatis_00000

目录

MyBatis 简介

MyBatis 的 GitHub 地址:https://github.com/mybatis

具体链接地址:
MyBatis 下载:https://github.com/mybatis/mybatis-3
MyBatis 文档:https://mybatis.org/mybatis-3

其他链接地址:
MyBatis 中文文档:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
MyBatis-Spring 官方中文文档:https://mybatis.org/spring/zh/index.html

MyBatis 是一个开源的数据持久层框架。它内部封装了 JDBC(Java database connectivity)访问数据库的操作,支持普通的 SQL(structured query language,结构化查询语言) 查询、存储过程和高级映射,几乎消除了所有的 JDBC 代码和参数的手工设置以及结果集的检索。
MyBatis 作为持久层框架,其主要思想是将程序中的大量 SQL 语句剥离出来,配置在配置文件中,实现 SQL 的灵活配置。这样做能将 SQL 与程序代码分离,可以在不修改程序代码的情况下,直接在配置文件中修改 SQL。

MyBatis 历史

MyBatis 的前身是 iBatis,是 Apache 的一个开源项目。2010 年 6 月这个项目由 Apache Software Foundation 迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x 正式更名为 MyBatis。代码于2013年11月迁移到 Github。

iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和DAO(data access objects)。

MyBatis 特性

1、MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
2、MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
3、MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJO(Plain Ordinary Java Object,普通的Java对象)映射成数据库中的记录。
4、MyBatis 是一个半自动的 ORM(Object Relational Mapping)框架。

MyBatis 优点

JDBC
1、SQL 夹杂在Java代码中耦合度高,导致硬编码内伤。
2、维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见。
3、代码冗长,开发效率低。

MyBatis
1、轻量级,性能出色。
2、SQL 和 Java 编码分开,功能边界清晰。Java 代码专注业务、SQL 语句专注数据。
MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 文件中,从程序代码中彻底分离,即降低耦合度,又便于统一管理和优化,还可重用。
3、提供 XML 标签,支持编写动态 SQL 语句。
4、提供映射标签,支持对象与数据库的 ORM 字段关系映射。

什么是数据持久化?

数据持久化是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。例如,文件的存储、数据的读取等都是数据持久化操作。数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等。

什么是 ORM?

对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。

ORM是一种数据持久化技术。它在对象模型和关系型数据库之间建立起对应关系,并且提供了一种机制,通过 JavaBean 对象去操作数据库表中的数据。

在实际开发中,程序员使用面向对象的技术操作数据,而当存储数据时,使用的却是关系型数据库。ORM在对象模型和关系数据库的表之间建立了一座桥梁,有了它,程序员就不需要在使用 SQL 语句操作数据库中的表,使用 API 直接操作 JavaBean 对象就可以实现数据的存储、查询、更改和删除等操作。MyBatis 通过 XML 文件或注解进行配置和原始映射,在实体类和 SQL 语句之间建立映射关系,是一种半自动化的 ORM 实现。

MyBatis 是 ORM 解决方案

基于 ORM, MyBatis 在对象模型和关系数据库的表之间建立了一座桥梁。通过 MyBatis,可以建立 SQL 关系映射,便捷地实现数据存储、查询、更改和删除等操作。

持久化类(POJO)和 SQL 映射文件

持久化类是指其实例状态需要被 MyBatis 持久化到数据库中的类。在应用的设计中,持久化类通常对应需求中的业务实体。MyBatis 一般采用 POJO(Plain Ordinary Java Object)编程模型来实现持久化类,与 POJO 类配合完成持久化工作是 MyBatis 最常见的工作模式。

POJO 从字面上来讲就是普通 Java 对象。POJO 类可以理解为符合 JavaBean 规范的实体类,它不需要继承和实现任何特殊的 Java 基类或者接口。JavaBean 对象的状态保存在属性中,访问属性必须通过对应的 getter 和 setter 方法。

MyBatis 下载

在这里插入图片描述
点击“See the docs”查看MyBatis的文档(英文文档)。
点击“Download Latest”下载最新版本的MyBatis。
在这里插入图片描述
点击“Download Latest”。

在这里插入图片描述
点击“Download”。
在这里插入图片描述

Eclipse 搭建 MyBatis

创建maven工程

New -> Project
在这里插入图片描述
选择“Maven Project”,点击“Next”。
在这里插入图片描述
将 “Create a simple project (skip archetype selection)” 前面的钩选中,点击 “Next”。
在这里插入图片描述
点击“Next”。
在这里插入图片描述
填写“Group Id”、“Artifact Id”、“Package”,点击“Finish”在这里插入图片描述
maven工程目录结构如下:
在这里插入图片描述
打包方式:jar

<packaging>jar</packaging>

引入依赖

<dependencies>

	<!-- MySQL -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.3</version>
	</dependency>

	<!-- MyBatis -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.4.6</version>
	</dependency>
	
	<!-- junit 测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
  </dependencies>

创建 MyBatis 的核心配置文件

MyBatis 核心配置文件主要用于配置数据库连接和 MyBatis 运行时所需的各种特性,包含了设置和影响 MyBatis 行为的属性。

为了方便管理以后各框架集成所需的配置文件,需在项目工程下新建 Source Folder 类型的 resources 目录。为了在框架集成时更好地区分各个配置文件,我们一般将此文件命名为 “mybatis-config.xml”。该文件需要配置数据库连接信息和 MyBatis 的参数。

将来整合 Spring 之后,这个配置文件可以省略。

核心配置文件主要用于配置连接数据库的环境和 MyBatis 的全局配置信息。

核心配置文件存放的位置是 src/main/resources 目录下

MyBatis 核心配置文件配置了 MyBatis 的一些全局信息,包含数据库连接信息和 MyBatis 运行时所需的各种特性,以及设置和影响 MyBatis 行为的一些属性。

<?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>

  <!-- 设置连接数据库的环境 -->
  <environments default="development">
    <environment id="development">
      <!-- 事务 -->
      <transactionManager type="JDBC"/>
      
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test_jack"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
      
    </environment>
  </environments>
  
  <!-- 引入映射文件 -->
  <mappers>
    <mapper resource="mappers/UserMapper.xml"/>
  </mappers>
  
</configuration>

核心配置文件详细说明

<?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>

  <!--引入database.properties文件,此时就可以${属性名}的方式访问属性值-->
  <properties resource="jdbc.properties"/>

  <settings>
	    
	<!--将表中字段的下划线自动转换为驼峰-->
	<setting name="mapUnderscoreToCamelCase" value="true"/>
	
	<!--开启延迟加载-->
	<setting name="lazyLoadingEnabled" value="true"/>
	
	<!-- 配置 MyBatis 的 log 实现为 LOG4J -->
	<setting name="logImpl" value="LOG4J"/>
	
  </settings>
  
  <typeAliases>
    <!--
	    typeAlias:设置某个具体的类型的别名
	    
	    属性:
        type:需要设置别名的类型的全类名
	    alias:设置此类型的别名,若不设置此属性,该类型拥有默认的别名,即类名且不区分大小写
	           若设置此属性,此时该类型的别名只能使用alias所设置的值
	    -->
	    <!--<typeAlias type="com.jack.mybatis.bean.User"></typeAlias>-->
	    <!--<typeAlias type="com.jack.mybatis.bean.User" alias="abc">
	</typeAlias>-->
	
	    <!--以包为单位,设置该包下所有的类型都拥有默认的别名,即类名且不区分大小写-->
	    <package name="com.jack.mybatis.bean"/>
	
  </typeAliases>
  
  <!--
    environments:设置多个连接数据库的环境
    
    属性:
    default:设置默认使用的环境的id
  -->
  <environments default="mysql_test">
    
    <!--
      environment:设置具体的连接数据库的环境信息
      
      属性:
      id:设置环境的唯一标识,可通过environments标签中的default设置某一个环境的id,表示默认使用的环境
    -->
    <environment id="mysql_test">
      
      <!--
        transactionManager:设置事务管理方式
        
        属性:
        type:设置事务管理方式,type="JDBC|MANAGED"
        type="JDBC":设置当前环境的事务管理都必须手动处理
        type="MANAGED":设置事务被管理,例如spring中的AOP
      -->
      <transactionManager type="JDBC"/>
      
      <!--
        dataSource:设置数据源
        
        属性:
            type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI"
            type="POOLED":使用数据库连接池,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建
            type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建
            type="JNDI":调用上下文中的数据源
      -->
      <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>

  <!--引入映射文件-->
  <mappers>
  
    <mapper resource="UserMapper.xml"/>
    
    <!--
      以包为单位,将包下所有的映射文件引入核心配置文件。
      注意:此方式必须保证mapper接口和mapper映射文件必须在相同的包下
    -->
    <package name="com.green.sea.mapper"/>

  </mappers>

</configuration>

MyBatis核心配置文件中几个常用元素的作用如下:

configuration:配置文件的根元素节点。
properties:通过 resource 属性从外部指定 properties 属性文件(database.properties),该属性文件描述数据库连接的相关配置(数据库驱动driver、连接数据库的url、数据库用户名username、数据库密码password),其位置也是在 /resources 目录下。
settings:设置 MyBatis 运行中的一些行为,比如此处设置 MyBatis 的 log 日志实现为 LOG4J,即使用log4j 实现日志功能。
environments:表示配置 MyBatis 的多套运行环境,将 SQL 映射到多个不同的数据库上,该元素节点下可以配置多个 environment 子元素节点,但是必须指定其中一个为默认运行环境(通过 default属性指定)。
environment:配置 MyBatis 的一套运行环境,需指定运行环境 ID、事务管理、数据源配置等相关信息。
mappers:作用是 MyBatis 去哪里找到 SQL 映射文件(该文件内容是开发者定义的映射 SQL 语句),整个项目中可以有一个或多个 SQL 映射文件。
mapper:mappers 的子元素节点,具体指定 SQL 映射文件的路径,其中 resource 属性值表述了 SQL 映射文件的路径(类资源路径)。

核心配置文件中的标签必须按照固定的顺序:

properties
settings
typeAliases
typeHandlers
objectFactory
objectWrapperFactory
reflectorFactory
plugins
environments
databaseIdProvider
mappers

settings 元素

settings 元素的作用是设置一些非常重要的选项,用于设置和改变 MyBatis 运行中的行为。

settings 元素支持的属性:

设置项描述运行值默认值
cacheEnabled对在此配置文件下的所有 cache 进行全局性开/关设置true|falsetrue
lazyLoadingEnabled全局性设置懒加载。如果设为 false,则所有相关联的设置都会被初始化加载。true|falsetrue
autoMappingBehaviorMyBatis 对于 resultMap 自动映射的匹配级别。NONE|PARTIAL|FULLPARTIAL

typeAliases 元素

typeAliases 元素的作用是配置类型别名,通过与 MyBatis 的 SQL 映射文件相关联,减少输入多余的完整类名,以简化操作。

<typeAliases>
	<!--这里给实体类取别名,方便在 mapper 配置文件中使用-->
    <typeAlias alias="user" type="com.greensea.manage.pojo.User"/>
    <typeAlias alias="provider" type="com.greensea.manage.pojo.Provider"/>	
</typeAliases>

<typeAliases>
	<package name="com.greensea.manage.pojo"/>
</typeAliases>

environments 元素

MyBatis 可以配置多套运行环境,如开发环境、测试环境、生产环境等,我们可以灵活选择不同的配置,从而将SQL映射到不同的数据库环境上。不同的运行环境可以通过environments元素来配置,但是不管增加几套运行环境,都必须要明确选择出当前唯一的一个运行环境。这是因为每个数据库都对应一个SqlSessionFactory实例,需要指明哪个运行环境将被创建,并把运行环境中设置的参数传递给SqlSessionFactory。
具体配置代码如下:

<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>

1、默认的运行环境ID:通过default属性来指定当前的运行环境ID为development,对于环境ID的命名要确保唯一。
2、transactionManager事务管理器:设置其类型为JDBC(MyBatis有两种事务管理类型,即JDBC和MANAGED),直接使用JDBC的提交和回滚功能,依赖于从数据源获得连接来管理事务的生命周期。
3、dataSource元素:使用标准的JDBC数据源接口来配置JDBC连接对象的资源。MyBatis提供了三种数据源类型(UNPOOLED、POOLED、JNDI),这里使用POOLED数据源类型。该类型利用“池”的概念将JDBC连接对象组织起来,减少了创建新的连接实例时所必需的初始化和认证时间,是MyBatis实现的简单的数据库连接池类型,它使数据库连接可被复用,不必在每次请求时都去创建一个物理连接。对于高并发的Web应用,这是一种流行的处理方式,有利于快速响应请求。

mappers元素

mappers映射器用来定义SQL的映射语句,我们只需要告诉MyBatis去哪里找到这些SQL语句,即去哪里找相应的SQL映射文件,可以使用类资源路径或者URL等。

使用类资源路径获取资源

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

使用URL获取资源

<mappers>
	<mapper url="file:///E:/sqlmappers/UserMapper.xml"/>
	<mapper url="file:///E:/sqlmappers/ProviderMapper.xml"/>
</mappers>

创建表和 POJO

在 MyBatis 中,不需要 POJO 类名与数据库表名一致,因为 MyBatis 是 POJO 与 SQL 语句之间的映射机制,一般情况下,保证 POJO 对象的属性与数据库表的字段名一致即可。

表名:t_user

字段名字段说明数据类型说明
id主键IDbigint主键;自动递增;不允许为空
username用户名varchar(20)
password密码varchar(20)
age年龄tinyint
email电子邮箱varchar(20)

在这里插入图片描述
创建包:com.greensea.manage.entity
在该包下创建User.java

package com.greensea.manage.entity;

import java.io.Serializable;

public class User implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer id;
	private String username;
	private String password;
	private Integer age;
	private String email;
	
	public User() {
		
	}

	public User(String username, String password, Integer age, String email) {
		
		this.username = username;
		this.password = password;
		this.age = age;
		this.email = email;
		
	}

	public User(Integer id, String username, String password, Integer age, String email) {
		
		this.id = id;
		this.username = username;
		this.password = password;
		this.age = age;
		this.email = email;
		
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password="
				+ password + ", age=" + age + ", email=" + email + "]";
	}
	
}

创建 mapper 接口

MyBatis 中的 mapper 接口相当于以前的dao。但是区别在于 mapper 仅仅是接口,不需要提供实现类。

package com.greensea.manage.mapper;

public interface UserMapper {
	
	/**
	 * 插入一条User数据
	 * @return 1,插入成功
	 */
	int insertUser();
		
}

创建 MyBatis 的 SQL 映射文件

SQL 映射文件的几个顶级元素配置:

  • mapper:映射文件的根元素节点,只有一个属性namespace(命名空间),其作用如下:

1、用于区分不同的mapper,全局唯一。
2、绑定DAO接口,即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实现类,MyBatis会通过接口的完整限定名查找到对应的mapper配置来执行SQL语句。因此namesp的命名必须跟接口同名。

MyBatis的SQL映射文件中mapper元素的namespace属性有如下要求:
1、namespace的命名必须跟某个DAO接口同名。
2、在不同的mapper文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id联合区分。接口中的方法与映射文件中SQL语句id应一一对应。

  • cache:配置给定命名空间的缓存。
  • cache-ref:从其他命名空间引用缓存配置。
  • resultMap:用来描述数据库结果集和对象的对应关系。
  • sql:可以重用的SQL块,也可以被其他语句引用。
  • insert:映射插入语句。
  • update:映射更新语句。
  • delete:映射删除语句。
  • select:映射查询语句。

SQL 映射文件一般都对应于相应的 POJO,所以一般都是以 POJO 的名称 +Mapper 的规则来命名。当然该 mapper 文件属于 DAO 层的操作,应该放置在 dao 包下(也可以放置在resources资源文件目录下),并根据业务功能进行分包放置。

ORM(Object Relational Mapping):对象关系映射。

  • 对象:Java的实体类对象
  • 关系:关系型数据库
  • 映射:二者之间的对应关系
Java概念数据库概念
属性字段/列
对象记录/行

1、表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml,因此一个映射文件对应一个实体类,对应一张表的操作。
2、MyBatis映射文件用于编写SQL,访问以及操作表中的数据。
3、MyBatis映射文件存放的位置是src/main/resources/mappers目录下。

MyBatis中可以面向接口操作数据,要保证两个一致:

1、mapper接口的全类名和映射文件的命名空间(namespace)保持一致。
2、mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致。

<?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.green.sea.mapper.UserMapper"> <!-- 映射文件的namespace要和mapper接口的全类名保持一致。 -->
  
  <insert id="insertUser"> <!-- 映射文件中SQL语句的id要和mapper接口中的方法名一致。 -->
  	insert into t_user values (null, "宋江", "songjiang", 50, "982902178@qq.com");
  </insert>
  
</mapper>

各元素的含义如下:

mapper:映射文件的根元素节点,只有一个属性 namespace。
namespace:用于区分不同的 mapper,全局唯一。

测试

MyBatis 的三个基本要素:
1、核心接口和类。
2、MyBatis 核心配置文件(mybatis-config.xml)。
3、SQL 映射文件(mapper.xml)

MyBatis 的核心接口和类
1、每个 MyBatis 的应用程序都以一个 SqlSessionFactory 对象的实例为核心。
2、首先获取 SqlSessionFactoryBuilder 对象,可以根据 XML 或 Configuration 类的实例构建该对象。
3、然后获取SqlSessionFactory 对象,该对象实例可以通过 SqlSessionFactoryBuilder 对象获得。
4、有了 SqlSessionFactory 对象之后,进而可以获取 SqlSession 实例,SqlSession 对象中完全包含以数据库为背景的所有执行 SQL 操作的方法。可以用该实例来直接执行已映射的 SQL 语句。

package com.company.project.module.first.test;

import java.io.IOException;
import java.io.InputStream;

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 com.company.project.module.first.mapper.UserMapper;
import com.company.project.module.first.util.MyBatisUtil;

public class TestUser {

	public static void main(String[] args) {
		
		InputStream inputStream = null;
		SqlSessionFactory sqlSessionFactory = null;
		
		try {

			//读取MyBatis的核心配置文件
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
			//创建SqlSessionFactoryBuilder对象
			SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
			
			//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
			sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			
			if(inputStream != null) {
				
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
			
		}
			
		//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务
		//SqlSession sqlSession = sqlSessionFactory.openSession();
		
		//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交
		SqlSession sqlSession = sqlSessionFactory.openSession(true); //传入ture,则自动提交事务,默认为不提交。
		
		
		//通过代理模式创建UserMapper接口的代理实现类对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		//调用UserMapper接口中的方法,就可以根据UserMapper的全接口名匹配元素文件,通过调用的方法名匹配映射文件中的SQL。
		int result = userMapper.insertUser();
		
		//sqlSession.commit(); //提交事务
		
		sqlSession.close();
		
		System.out.println("返回结果:" + result);
			
	}
	
}
  • SqlSession:代表 Java 程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
  • SqlSessionFactory:是“生产” SqlSession 的“工厂”。
  • 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 的作用

SqlSessionFactoryBuilder 负责构建 SqlSessionFactory,并且提供了多个 build() 方法的重载。
在这里插入图片描述

SqlSessionFactory build(Reader reader)
SqlSessionFactory build(Reader reader, String environment)
SqlSessionFactory build(Reader reader, Properties properties)
SqlSessionFactory build(Reader reader, String environment, Properties properties)
SqlSessionFactory build(InputStream inputStream)
SqlSessionFactory build(InputStream inputStream, String environment)
SqlSessionFactory build(InputStream inputStream, Properties properties)
SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
SqlSessionFactory build(Configuration config)

配置信息以三种形式提供给 SqlSessionFactoryBuilder 的 build() 方法,分别是 InputStream(字节流)、Reader(字符流)、Configuration(类),由于字节流与字符流都属于读取配置文件的方式,所以从配置信息的来源去构建一个 SqlSessionFactory 有两种方式:读取 XML 配置文件构造方式和编程构造方式。

SqlSessionFactoryBuild 的生命周期和作用域

SqlSessionFactoryBuild 最大特点就是用过即丢。一旦创建了SqlSessionFactory 对象,这个类就不需要存在了,因此 SqlSessionFactoryBuilder 的最佳使用范围就是存在于方法体内,也就是局部变量。

SqlSessionFactory

SqlSessionFactory 的作用

SqlSessionFactory 就是创建 SqlSession 实例的工厂。所有的 MyBatis 应用都是以 SqlSessionFactory 实例为中心。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 对象来获得。有了 SqlSessionFactory 的实例,就可以通过 SqlSessionFactory 提供的openSession() 方法来获取 SqlSession 实例。
在这里插入图片描述

SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();

SqlSessionFactory 的生命周期和作用域

SqlSessionFactory 对象一旦创建,就会在这个应用运行过程中始终存在。没有理由去销毁或再创建它,并且在应用运行中也不建议多次创建 SqlSessionFactory。因此 SqlSessionFactory 的最佳作用域是 Application,即随着应用的生命周期一同存在。那么这种“存在于整个应用运行期间有且仅有一个实例”的模式就是所谓的单例模式(指在应用运行期间有且仅有一个实例)。

SqlSession

SqlSession 的作用

SqlSession 用于执行持久化操作的对象,类似于 JDBC 中的 Connection。它提供了面向数据库执行 SQL 命令所需的所有方法,可以通过 SqlSession 实例直接运行已映射的 SQL 语句。
在这里插入图片描述

SqlSession 的生命周期和作用域

SqlSession 对应着一次数据库会话,由于数据库会话不是永久的,因此 SqlSession 的生命周期也不是永久的。相反,在每次访问数据库时都需要创建它(注意:并不是说在 SqlSession 里只能执行一次 SQL,它是完全可以执行多次的,但是若关闭了 SqlSession,那么就需要重新创建它)。创建 SqlSession 的方式只有一个,那就是使用 SqlSessionFactory 对象的 openSession() 方法。

每个线程都有自己的 SqlSession 实例,SqlSession 实例不能被共享,也不是线程安全的。因此最佳的作用域范围是 request 作用域或者方法体作用域。

创建MyBatis工具类

package com.company.project.module.first.util;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil {

	private static SqlSessionFactory sqlSessionFactory = null;
	
	static {
		
		InputStream inputStream = null;
		
		try {
			
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
			SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
			sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
			
		} catch (IOException e) {		
			e.printStackTrace();
		}finally {
			
			if(inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
			
	}
	
	public static SqlSession createSqlSession() {
		
		return sqlSessionFactory.openSession(true);
		
	}
	
	public static void closeSqlSession(SqlSession sqlSession) {
		
		if(null != sqlSession) {
			
			sqlSession.close();
			
		}
		
	}
	
}

使用MyBatis工具类写测试类

package com.company.project.module.first.test;

import java.io.IOException;
import java.io.InputStream;

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 com.company.project.module.first.mapper.UserMapper;
import com.company.project.module.first.util.MyBatisUtil;

public class TestUser {

	public static void main(String[] args) {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		int result = userMapper.insertUser();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println("result=" + result);
			
	}

}

加入 log4j 日志功能

添加依赖

	<dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

添加 log4j 的配置文件

log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 
	
	<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">   
		
		<param name= "Encoding" value="UTF-8"/>
		
		<layout class="org.apache.log4j.PatternLayout">	      
			
			<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
		
		</layout>
		
	</appender>
	
	<logger name="java.sql">
		<level value="debug"/>
	</logger>
	  
	<logger name="org.apache.ibatis">
		<level value="info"/>
	</logger>
	  
	<root>
		<level value="debug"/>
		<appender-ref ref="STDOUT" />
	</root>
	
</log4j:configuration>

日志的级别:
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细。

MyBatis 对数据库的操作

修改

UserMapper.java文件中添加:

	/**
	 * 根据id修改一条User数据
	 * @return 1,修改成功
	 */
	int updateUserById();

UserMapper.xml文件中添加:

	<!-- int updateUserById(); -->
	<update id="updateUserById">
		update t_user set username="卢俊义" where id=1;
	</update>

测试方法:

	@Test
	public void testUpdateUserById() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		int result = userMapper.updateUserById();
		MyBatisUtil.closeSqlSession(sqlSession);
		System.out.println("结果:" + result);
		
	}

删除

UserMapper.java 文件中添加:

	/**
	 * 根据id删除一条User数据
	 * @return 1,删除成功
	 */
	int deleteUserById();

UserMapper.xml 文件中添加:

	<!-- int deleteUserById(); -->
	<delete id="deleteUserById">
		delete from t_user where id=1;
	</delete>

测试方法:

	@Test
	public void testDeleteUserById() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		int result = userMapper.deleteUserById();
		MyBatisUtil.closeSqlSession(sqlSession);
		System.out.println("结果:" + result);
		
	}	

查询

UserMapper.java添加:

	/**
	 * 根据id查询一条User数据
	 * @return 一条User数据
	 */
	User selectUserById();
	
	
	/**
	 * 查询所有User信息
	 * @return 所有User
	 */
	List<User> selectUserAll();

UserMapper.xml添加:

	<!-- User selectUserById(); -->
	<select id="selectUserById" resultType="com.greensea.manage.entity.User">
		select * from t_user where id=2;
	</select>

	<!-- List<User> selectUserAll(); -->
	<select id="selectUserAll" resultType="com.greensea.manage.entity.User">
		select * from t_user;
	</select>

查询功能的标签必须设置resultType或resultMap
resultType:设置默认的映射关系。字段名和属性名相同时。
resultMap:设置自定义的映射关系。

select:表示查询语句,是 MyBatis 最常见的元素之一,常用属性如下:
id:该命名空间下唯一标识符。
resultType:表示 SQL 语句返回值类型,此处通过 SQL 语句返回的是 int 数据类型。

测试类:

	@Test
	public void testSelectUserById() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		User user = userMapper.selectUserById();
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(user);
		
	}
	
	@Test
	public void testSelectUserAll() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		List<User> users = userMapper.selectUserAll();
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}
  • 查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系。
    resultType:自动映射,用于属性名和表中字段名一致的情况。
    resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况。
  • 当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常:TooManyResultsException
    若查询的数据只有一条,可以使用实体类或集合作为返回值。

MyBatis 接口中带参操作

MyBatis 获取参数值的两种方式:${} 和 #{}
${} 的本质就是字符串拼接,#{} 的本质是占位符赋值。
${} 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是 #{} 使用占位符赋值的方式拼接 sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号。

单个字面量类型的参数

若mapper接口中的方法参数为单个的字面量类型。此时可以使用${}和#{}以任意的名称获取参数的值,注意${}需要手动加单引号。

UserMapper.java

/**
	 * 根据id查询一条User数据
	 * @return 一条User数据
	 */
	User selectUserById1(Integer id);

UserMapper.xml

<!-- User selectUserById1(Integer id); -->
	<select id="selectUserById1" resultType="com.greensea.manage.entity.User">
		select * from t_user where id=#{id};
	</select>

测试:

@Test
	public void testSelectUserById1() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		User user = userMapper.selectUserById1(2);
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(user);
		
	}

多个字面量类型的参数

若 mapper 接口中的方法参数为多个时,MyBatis 会自动将这些参数放在一个 map 集合中,以 arg0, arg1…为键,以参数为值;以 param1, param2…为键,以参数为值;因此只需要通过 ${} 和 #{} 访问 map 集合的键就可以获取相对应的值,注意${}需要手动加单引号。

UserMapper.java

/**
	 * 根据用户名和密码查询用户
	 * @param User对象
	 * @return 查询的用户集合
	 */
	List<User> selectUserByUsernameAndPassword(String username, String password);

UserMapper.xml

<!-- List<User> selectUserByUsernameAndPassword(User user); -->
	<select id="selectUserByUsernameAndPassword" resultType="com.greensea.manage.entity.User">
		select * from t_user where username=#{param1} and password=#{param2};
	</select>

测试

@Test
	public void testSelectUserByUsernameAndPassword() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		List<User> users = userMapper.selectUserByUsernameAndPassword("宋江", "songjiang");
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}

map 集合类型的参数

若mapper接口中的方法需要的参数为多个时,可以手动创建map集合,将这些数据放在map中,只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号。

UserMapper.java

/**
	 * 根据用户名和密码查询用户
	 * @param map集合
	 * @return 查询的用户集合
	 */
	List<User> selectUserByUsernameAndPassword1(Map<String, Object> map);

UserMapper.xml

<!-- List<User> selectUserByUsernameAndPassword1(Map<String, Object> map); -->
	<select id="selectUserByUsernameAndPassword1" resultType="com.greensea.manage.entity.User">
		select * from t_user where username=#{username} and password=#{password};
	</select>

测试

@Test
	public void testSelectUserByUsernameAndPassword1() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("username", "宋江");
		map.put("password", "songjiang");
		
		List<User> users = userMapper.selectUserByUsernameAndPassword1(map);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}

实体类类型的参数

若mapper接口中的方法参数为实体类对象时,可以使用${}和#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号

插入数据

UserMapper.java

/**
	 * 插入一条用户数据
	 * @param User用户
	 * @return 返回1,插入成功
	 */
	int insertUserParamUser(User user);

UserMapper.xml

<!-- int insertUserParamUser(User user); -->
	<insert id="insertUserParamUser">
 		insert into t_user values (null, #{username}, #{password}, #{age}, #{email});
 	</insert>

insert元素包括如下属性:
1、id:与select元素的id一样,是命名空间中唯一的标识符,可以被用来引用该条语句。
2、parameterType:与select元素的parameterType一样,是传入参数的类型的完全限定名或别名。

对于增删改(insert、delete、update)这类数据库更新操作,需要注意两点:
1、该类型的操作本身默认返回执行SQL语句影响的行数,所有DAO层的接口方法的返回值一般设置为int类型。最好不要返回boolean类型。
2、insert、delete、update元素中均没有resultType属性,只有查询操作需要对返回结果的类型(resultType/resultMap)进行相应的指定。

测试

@Test
	public void testInsertUserParamUser() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		/*User user = new User();
		user.setUsername("宋江");
		user.setPssword("songjiang");
		user.setAge(56);
		user.setEmail("982902178@qq.com");*/
		
		User user = new User("宋江", "songjiang", 56, "982902178@qq.com");
		
		int result = userMapper.insertUserParamUser(user);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(result);
		
	}

查询数据

UserMapper.java

/**
	 * 根据用户名和密码查询用户信息
	 * @param 用户名
	 * @param 密码
	 * @return 用户的集合
	 */
	List<User> selectUserByUsernameAndPasswordParamUser(User user);

UserMapper.xml

<!-- List<User> selectUserByUsernameAndPasswordParamUser(String username, String password); -->
 	<select id="selectUserByUsernameAndPasswordParamUser" resultType="com.greensea.manage.entity.User">
 		select * from t_user where username=#{username} and password=#{password};
 	</select>

测试

@Test
	public void selectUserByUsernameAndPasswordParamUser() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		User user = new User();
		user.setUsername("宋江");
		user.setPassword("songjiang");
		
		List<User> users = userMapper.selectUserByUsernameAndPasswordParamUser(user);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}

使用 @Param 标识参数

使用@Param标识参数,可以通过@Param注解标识mapper接口中的方法参数。此时,会将这些参数放在 map 集合中,以 @Param 注解的value 属性值为键,以参数为值;以 param1, param2…为键,以参数为值;只需要通过 ${} 和 #{} 访问 map 集合的键就可以获取相对应的值,注意 ${} 需要手动加单引号。

UserMapper.java

/**
	 * 根据用户名和密码查询用户
	 * @param User对象
	 * @return 查询的用户集合
	 */
	List<User> selectUserByUsernameAndPasswordParamUser1(@Param("username") String username, @Param("password") String password);

UserMapper.xml

<!-- List<User> selectUserByUsernameAndPasswordParamUser1(@Param("username") String username, @Param("password") String password); -->
	<select id="selectUserByUsernameAndPasswordParamUser1" resultType="com.greensea.manage.entity.User">
		select * from t_user where username=#{username} and password=#{password};
	</select>

测试

@Test
	public void selectUserByUsernameAndPasswordParamUser1() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		List<User> users = userMapper.selectUserByUsernameAndPasswordParamUser1("宋江", "songjiang");
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}

MyBatis 的各种查询

MyBatis 的各种查询功能:
1、若查询出的数据(对象)只有一条
(1)可以通过实体类对象接收。(User)
(2)可以通过list集合接收。(List、List<Map<String, Object>)
(3)可以通过map集合接收。(Map<String, Object>)
结果形式:{password=123456, sex=男, id=3, age=23, email=12345@qq.com, username=admin}

2、若查询出的数据有多条
(1)可以通过实体类类型的 list 集合接收。(List)
(2)可以通过 map 类型的 list 集合接收。(List<Map<String, Object>>)
(3)可以在 mapper 接口的方法上添加 @MapKey 注解,此时就可以将每条数据转换的 map 集合作为值,以某个字段(该字段的值唯一)的值作为键,放在同一个 map 集合中。

注意:一定不能通过实体类对象接收,此时会抛异常 TooManyResultsException

查询结果为一个实体类对象

只适用于返回一条数据

/**
	 * 根据用户id查询用户信息
	 * @param 用户id
	 * @return 一条用户信息
	 */
	User selectUserById(@Param("id") Integer id);
<!-- User selectUserById(@Param("id") Integer id); -->
 	<select id="selectUserById" resultType="User">
 		select * from t_user where id=#{id};
 	</select>
@Test
	public void testSelectUserById() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();	
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		User user = userMapper.selectUserById(2);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(user);
		
	}

查询结果为 List 集合

适用于返回一条或一条以上数据

/**
	 * 查询所有User信息
	 * @return 所有User;List集合,里面的元素是实体类对象
	 */
	List<User> selectUserAll();
<!-- List<User> selectUserAll(); -->
	<select id="selectUserAll" resultType="User">
		select * from t_user;
	</select>
@Test
	public void testSelectUserAll() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		List<User> users = userMapper.selectUserAll();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}

查询:返回单个数据

在 MyBatis 中,对于 Java 中常用的数据类型都设置了类型别名。
例如:
java.lang.Integer -> int | integer
int -> _int | _integer
String -> string
List -> list
Map -> map

/**
	 * 查询共有多少用户
	 * @return 用户总数
	 */
	int selectUserCount();
<!-- int selectUserCount(); -->
 	<select id="selectUserCount" resultType="Integer">
 		select count(*) from t_user;
 	</select>
@Test
	public void tsetSelectUserCount() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		int count = userMapper.selectUserCount();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(count);
		
	}

对于resultType值,即返回结果,MyBatis 提供的类型别名如下:

AliasMapped Type
_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

查询:返回一条数据;返回: Map

只适用于返回一条数据。

/**
	 * 根据用户id查询用户
	 * @param id
	 * @return 一条用户数据,将该用户数据以属性为key,属性值为value存放在map集合中
	 */
	Map<String, Object> selectUserByIdMap(@Param("id") Integer id);
<!-- Map<String, Object> selectUserByIdMap(@Param("id") Integer id); -->
 	<select id="selectUserByIdMap" resultType="map">
 		select * from t_user where id=#{id};
 	</select>
@Test
	public void selectUserByIdMap(){	
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		Map<String, Object> map = userMapper.selectUserByIdMap(1);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(map);
		
	}

以上代码输出结果为 map 类型,key为属性名称,值为属性值。
返回结果形式:{password=123456, sex=男, id=1, age=23, email=982902178@qq.com, username=admin}

查询:返回一条或一条以上数据

返回 List

/**
	 * 查询所有用户信息,放在List集合中,集合中的元素为map集合,该集合中存放的key为属性名称,value为属性值
	 * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取
	 * @return 用户数据,将该用户数据以属性为key,属性值为value存放在map集合中
	 */
	List<Map<String, Object>> selectAllUserListInMap();
<!-- List<Map<String, Object>> selectAllUserListInMap(); -->
 	<select id="selectAllUserListInMap" resultType="map">
 		select * from t_user;
 	</select>
@Test
	public void selectAllUserListInMap(){
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		List<Map<String, Object>> listInMap = userMapper.selectAllUserListInMap();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(listInMap);
		
		for (int i = 0; i < listInMap.size(); i++) {
			System.out.println(listInMap.get(i));
		}
		
	}

@MapKey 注解;返回:Map

查询出所有数据
/**
     * 查询所有用户信息为map集合
     * 将表中的数据以map集合的方式查询,一条数据对应一个map;
     * 若有多条数据,就会产生多个map集合,并且最终以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合
	 * @return map集合
	 */
	@MapKey(value = "id")
	Map<String, Object> selectAllUserMap();
<!-- Map<String, Object> selectAllUserMap(); -->
 	<select id="selectAllUserMap" resultType="map">
 		select * from t_user;
 	</select>
@Test
	public void selectAllUserMap(){
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		Map<String, Object> map = userMapper.selectAllUserMap();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(map);
		
	}

结果:
{
1={password=123456, sex=男, id=1, age=23, username=admin},
2={password=123456, sex=男, id=2, age=23, username=张三},
3={password=123456, sex=男, id=3, age=23, username=张三}
}

查询出特定条件的数据
@MapKey("id")
	Map<String, Object> selectUserByUsernameAnnotation(@Param("username") String username);
<!-- Map<String, Object> selectUserByUsernameAnnotation(@Param("username") String username); -->
	<select id="selectUserByUsernameAnnotation" resultType="map">
		select * from t_user where username=#{username};
	</select>
@Test
	public void selectUserByUsernameAnnotation() {
	
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	
		Map<String, Object> map = userMapper.selectUserByUsernameAnnotation("潘金莲");
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(map);
		
	}

特殊SQL的执行

模糊查询

UserMapper.java

/**
	 * 模糊查询
	 * @param 模糊查询的条件
	 * @return 用户数据集合
	 */
	List<User> selectUserLike(@Param("username") String username);

UserMapper.xml

<!-- List<User> selectUserLike(@Param("username") String username); -->
	<select id="selectUserLike" resultType="User" parameterType="String">
		select * from t_user where username like concat('%', #{username}, '%');
	</select>

test

@Test
	public void testSelectUserLike() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		List<User> users = userMapper.selectUserLike("卢");
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(users);
		
	}

parameterType表示查询语句传入参数的类型的完全限定名或别名。它支持基础数据类型和复杂数据类型。

批量删除

/**
	 * 批量删除
	 * @param id
	 * @return 删除个数
	 */
	int deleteBatch(@Param("ids") String ids);
<!-- int deleteBatch(@Param("ids") String id); -->
	<delete id="deleteBatch">
		delete from t_user where id in (${ids});
	</delete>
@Test
	public void deleteBatch() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();	
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		int number = userMapper.deleteBatch("1, 2, 3");

		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(number);
		
	}

动态设置表名进行查询

/**
	 * 查询所有用户信息
	 * @param 表名
	 * @return 表中所有数据
	 */
	List<User> selectAllUserTableName(@Param("tableName") String tableName);
<!-- List<User> selectAllUserTableName(@Param("tableName") String tableName); -->
	<select id="selectAllUserTableName" resultType="User">
		select * from ${tableName};
	</select>
@Test
	public void selectAllUserTableName(){
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		List<User> users = userMapper.selectAllUserTableName("t_user");
		
		MyBatisUtil.closeSqlSession(sqlSession);

		System.out.println(users);
		
		for (User user : users) {
			System.out.println(user);
		}
		
	}

添加功能获取自增的主键

useGeneratedKeys:设置使用自增的主键。
keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数 user 对象的某个属性中

int insertUserId(User user);
<!-- int insertUserId(User user); -->
	<insert id="insertUserId" useGeneratedKeys="true" keyProperty="id">
		insert into t_user values (null, #{username}, #{password}, #{age}, #{email});		
	</insert>
@Test
	public void insertUser(){
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		User user = new User(null, "宋江", "123", 55, "982902178@qq.com");
		
		int number = userMapper.insertUserId(user);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(number);
		System.out.println(user);
		
	}

自定义映射 resultMap

若字段名和实体类中的属性名不一致,则可以通过 resultMap 设置自定义映射。

若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
1、可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
2、可以在MyBatis的核心配置文件中设置一个全局配置信息 mapUnderscoreToCamelCase ,可以在查询表中数据时,自动将_类型的字段名转换为驼峰
例如:字段名user_name,设置了 mapUnderscoreToCamelCase ,此时字段名就会转换为 userName。

resultMap 处理字段和属性的映射关系

resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型

子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系

collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名

resultMap元素包括如下属性值和子节点:

  • id属性:唯一标识,此id值用于对select元素resultMap属性的引用
  • type属性:表示该resultMap的映射结果类型。
  • result子节点:用于标识一些简单属性,其中column属性表示从数据库中查询的字段名,property则表示查询出来的字段对应的值赋给实体对象的哪个属性。

resultType与resultMap的关联和区别

1、resultType
resultType表示返回类型,包括基础数据类型和复杂数据类型。
2、resultMap
resultMap是对外部resultMap定义的引用,对应外部resultMap的id ,表示返回结果映射到哪一个resultMap上。它的应用场景一般是:数据库字段信息与对象属性不一致或者需要做复杂的联合查询,以便自由控制映射结果。
3、resultType和resultMap的关联
在MyBatis进行查询映射的时候,查询出来的每个字段值都放在一个对应的Map里面,其中键是字段名,值则是其对应的值。当select元素提供的返回类型属性是resultType的时候,MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性(即调用对应的对象里的属性的setter方法进行填充)。正因为如此,当使用resultType的时候,直接在后台就能接收到其相应的对象属性值。由此可看出,其实MyBatis的每个查询映射的返回类型都是resultMap,只是当我们提供的返回类型属性是resultType的时候,MyBatis会自动把对应的值赋给resultType所指定对象的属性;而当我们提供的返回类型属性是resultMap的时候,因为Map不能很好地表示领域模型,就需要通过进一步的定义把它转化为对应的实体对象。

在MyBatis的select元素中,resultType和resultMap本质上是一样的,都是Map数据结构。但需要明确一点:resultType属性和resultMap属性绝对不能同时存在,只能二者选其一使用。

在MyBatis中,使用resultMap能够进行自动映射匹配的前提是字段名和属性名必须一致,在默认映射级别(PARTIAL)情况下,若字段名和属性名一致,即使没有做属性名的匹配,也可以在后台获取到未匹配过的属性值;若字段名和属性名不一致,且在resultMap里没有做映射,那么就无法在后台获取并输出。

<resultMap id="userMap" type="User">
    <id property="id" column="id"></id>
    <result property="userName" column="user_name"></result>
    <result property="password" column="password"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
</resultMap>

<!--List<User> testMohu(@Param("mohu") String mohu);-->
<select id="testMohu" resultMap="userMap">
    <!--select * from t_user where username like '%${mohu}%'-->
    select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')
</select>

建表

表名:t_employee

字段名字段类型长度说明
eidbigint20主键自增
emp_namevarchar255
gendertinyint4
ageint11
emailvarchar255
didbigint20

在这里插入图片描述
表名:t_department

字段名字段类型长度备注
didbigint20主键自增
dept_namevarchar255

在这里插入图片描述
SQL

select * from t_employee, t_department where t_employee.did=t_department.did;

select * from t_employee
	left join t_department
	on t_employee.did=t_department.did;
	
select * from t_employee e
	left join t_department d 
	on e.did=d.did;
	
select * from t_employee as e
	left join t_department as d 
	on e.did=d.did;

select e.*, d.* from t_employee as e
	left join t_department as d 
	on e.did=d.did;
	
select d.*, e.* from t_employee as e
	left join t_department as d 
	on e.did=d.did;
	
select * from t_employee as e
	left join t_department as d 
	on e.did=d.did
	where e.did='2';

实体类:

Employee.java

package com.greensea.manage.entity;

import java.io.Serializable;

public class Employee implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private Integer eid;
	private String empName;
	private Integer gender;
	private Integer age;	
	private String email;
	private Integer did;
	
	private Department department;

	public Employee() {
		
	}

	public Employee(String empName, Integer gender, Integer age, String email, Integer did, Department department) {
		
		this.empName = empName;
		this.gender = gender;
		this.age = age;
		this.email = email;
		this.did = did;
		this.department = department;
		
	}
	
	public Employee(Integer eid, String empName, Integer gender, Integer age, String email, Integer did, Department department) {
	
		this.eid = eid;
		this.empName = empName;
		this.gender = gender;
		this.age = age;
		this.email = email;
		this.did = did;
		this.department = department;
		
	}

	public Integer getEid() {
		return eid;
	}

	public void setEid(Integer eid) {
		this.eid = eid;
	}

	public String getEmpName() {
		return empName;
	}

	public void setEmpName(String empName) {
		this.empName = empName;
	}

	public Integer getGender() {
		return gender;
	}

	public void setGender(Integer gender) {
		this.gender = gender;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Integer getDid() {
		return did;
	}

	public void setDid(Integer did) {
		this.did = did;
	}

	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [eid=" + eid + ", empName=" + empName + ", gender="
				+ gender + ", age=" + age + ", email=" + email + ", did=" + did
				+ ", department=" + department + "]";
	}
	
}

department.java

package com.greensea.manage.entity;

import java.io.Serializable;
import java.util.List;

public class Department implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer did;
	private String deptName;
	
	private List<Employee> employees; 
	
	public Department() {
		
	}
	
	public Department(String deptName, List<Employee> employees) {
		
		this.deptName = deptName;
		this.employees = employees;
		
	}
	
	public Department(Integer did, String deptName, List<Employee> employees) {
	
		this.did = did;
		this.deptName = deptName;
		this.employees = employees;
		
	}

	public Integer getDid() {
		return did;
	}

	public void setDid(Integer did) {
		this.did = did;
	}

	public String getDeptName() {
		return deptName;
	}

	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}

	public List<Employee> getEmployees() {
		return employees;
	}

	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}

	@Override
	public String toString() {
		return "Department [did=" + did + ", deptName=" + deptName + ", employees=" + employees + "]";
	}

}

接口

EmployeeMapper.java

/**
	 * 查询所有雇员信息
	 * @return 所有员工信息
	 */
	List<Employee> selectEmployeeAll();

映射文件

EmployeeMapper.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">

<mapper namespace="com.greensea.manage.mapper.EmployeeMapper">
	
	<resultMap type="Employee" id="employeeMap">
		<id property="eid" column="eid"/>
		<result property="empName" column="emp_name"/>
		<result property="gender" column="gender"/>
		<result property="age" column="age"/>
		<result property="email" column="email"/>
		<result property="did" column="did"/>
	</resultMap>
	
    <!-- List<Employee> selectEmployeeAll(); -->
	<select id="selectEmployeeAll" resultMap="employeeMap">
		select * from t_employee;
	</select>
	
</mapper>

测试

test

@Test
	public void selectEmployeeAll() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		
		List<Employee> employees = employeeMapper.selectEmployeeAll();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(employees);
		
		for (Employee employee : employees) {
			System.out.println(employee);
		}
		
	}

resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型

子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系

collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名

多对一映射

方式一:级联属性赋值

EmployeeMapper.java

/**
	 * 根据员工id查询员工信息以及所在部门的信息。
	 * @param eid;员工id
	 * @return 查询到的员工
	 */
	Employee selectEmployeeAndDepartmentById(@Param("eid") Integer eid);

EmployeeMapper.xml

<resultMap id="employeeAndDepartmentMapOne" type="Employee">
		<id property="eid" column="eid"/>
		<result property="empName" column="emp_name"/>
		<result property="gender" column="gender"/>
		<result property="age" column="age"/>
		<result property="email" column="email"/>
		<result property="did" column="did"/>
		
		<result property="department.did" column="did"/>
		<result property="department.deptName" column="dept_name"/>
	</resultMap>
	<!-- Employee selectEmployeeAndDepartmentById(@Param("eid") Integer eid); -->
	<select id="selectEmployeeAndDepartmentById" resultMap="employeeAndDepartmentMapOne">
		select * from t_employee left join t_department on t_employee.did=t_department.did where t_employee.eid=#{eid};
	</select>

test

@Test
	public void selectEmployAndDepartmentById() {
		
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		
		Employee employee = employeeMapper.selectEmployeeAndDepartmentById(1);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(employee);
		
	}

方式二:使用association

<resultMap id="employeeAndDepartmentMapTwo" type="Employee">
		<id property="eid" column="eid"/>
		<result property="empName" column="emp_name"/>
		<result property="gender" column="gender"/>
		<result property="age" column="age"/>
		<result property="email" column="email"/>
		<result property="did" column="did"/>
		
		<association property="department" javaType="Department">
			<id property="did" column="did"/>
			<result property="deptName" column="dept_name"/>
		</association>
		
	</resultMap>
	<!-- Employee selectEmployeeAndDepartmentById(@Param("eid") Integer eid); -->
	<select id="selectEmployeeAndDepartmentById" resultMap="employeeAndDepartmentMapTwo">
		select * from t_employee left join t_department on t_employee.did=t_department.did where t_employee.eid=#{eid};
	</select>

方式三:分步查询

步骤一:根据员工eid查询员工信息

/**
	 * 处理多对一映射关系;分步查询;步骤一;根据员工eid查询一条员工信息
	 * @param 员工eid
	 * @return 员工信息
	 */
	Employee selectEmployeeByIdStepOne(@Param("id") Integer id);
<resultMap type="Employee" id="employeeResultMapStepOne">
		<id property="eid" column="eid"/>
		<result property="empName" column="emp_name"/>
		<result property="gender" column="gender"/>
		<result property="age" column="age"/>
		<result property="email" column="email"/>
		<result property="did" column="did"/>
		
		<association property="department" select="com.greensea.manage.mapper.DepartmentMapper.selectDepartmentByIdStepTwo" column="did"/>
			
	</resultMap>
	<!-- Employee selectEmployeeByIdStepOne(@Param("id") Integer id); -->
	<select id="selectEmployeeByIdStepOne" resultMap="employeeResultMapStepOne">
		select * from t_employee where eid=#{id};
	</select>

步骤二:根据部门did查询部门信息

/**
	 * 处理多对一映射关系;分步查询;步骤二;根据部门did查询一条部门信息
	 * @param 部门did
	 * @return 部门信息
	 */
	Department selectDepartmentByIdStepTwo(@Param("id") Integer id);
<resultMap type="Department" id="departmentResultMapStepTwo">
		<id property="did" column="did"/>
		<result property="deptName" column="dept_name"/>
	</resultMap>
	<!-- Department selectDepartmentByIdStepTwo(@Param("id") Integer id); -->	
	<select id="selectDepartmentByIdStepTwo" resultMap="departmentResultMapStepTwo">
		select * from t_department where did=#{id};
	</select>

test

@Test
	public void testSelectDepartmentByIdSteptwo() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
		
		Department department = departmentMapper.selectDepartmentByIdStepTwo(1);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(department);
		
	}
	
	@Test
	public void testSelectEmployeeByIdStepOne() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		
		Employee employee = employeeMapper.selectEmployeeByIdStepOne(1);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(employee);
		
	}

一对多映射

collection

DepartmentMapper.java

/**
	 * 根据部门did查询一条部门信息;一对多
	 * @param 部门id
	 * @return 部门信息
	 */
	Department selectDepartmentByidEmployee(@Param("id") Integer id);

DepartmentMapper.xml

<resultMap type="Department" id="departmentEmployeeResultMap">
		<id property="did" column="did"/>
		<result property="deptName" column="dept_name"/>
		<collection property="employees" ofType="Employee">
			<id property="eid" column="eid"/>
			<result property="empName" column="emp_name"/>
			<result property="gender" column="gender"/>
			<result property="age" column="age"/>
			<result property="email" column="email"/>
			<result property="did" column="did"/>
		</collection>
	</resultMap>
	<!-- Department selectDepartmentByidEmployee(@Param("id") Integer id); -->
	<select id="selectDepartmentByidEmployee" resultMap="departmentEmployeeResultMap">
		<!-- 
		select * from t_department d left join t_employee e on d.did=e.did where d.did=1;
		select d.*, e.* from t_department d left join t_employee e on d.did=e.did where d.did=1;
		-->
		select * from t_department left join t_employee on t_department.did=t_employee.did where t_department.did=#{id};		
	</select>

test

@Test
	public void selectDepartmentByidEmployee() {
		
		SqlSession sqlSession = null;
		
		try {
			sqlSession = MyBatisUtil.createSqlSession();
			DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
			
			Department department = departmentMapper.selectDepartmentByidEmployee(1);
			
			System.out.println(department);
			
		} catch (Exception e) {
			e.printStackTrace();
			//sqlSession.rollback();
		}finally {
			MyBatisUtil.closeSqlSession(sqlSession);
		}
		
	}

分步查询

步骤一:
DepartmentMapper.java

 /**
      * 处理一对多映射关系;分步查询;步骤一;根据部门编号查询出一条部门信息
     * @param 部门编号
     * @return 一条部门信息
     */
	Department selectDepartmentByIdEmployeeStepOne(@Param("id") Integer id);

DepartmentMapper.xml

<resultMap type="Department" id="selectDepartmentByIdEmployeeStepOneResultMap">
		<id property="did" column="did"/>
		<result property="deptName" column="dept_name"/>
		<collection property="employees" column="did" fetchType="eager" select="com.greensea.manage.mapper.EmployeeMapper.selectDepartmentByIdEmployeeStepTwo"/>
	</resultMap>
	<!-- Department selectDepartmentByIdEmployeeStepOne(@Param("id") Integer id); -->
	<select id="selectDepartmentByIdEmployeeStepOne" resultMap="selectDepartmentByIdEmployeeStepOneResultMap">
		select * from t_department where did = #{id}
	</select>

步骤二:
EmployeeMapper.java

/**
	 * 处理一对多映射关系;分步查询;步骤二;根据员工部门编号查询出一条员工信息
	 * @param 员工部门的编号
	 * @return 一条员工信息
	 */
	Employee selectDepartmentByIdEmployeeStepTwo(@Param("id") Integer id);

EmployeeMapper.xml

<resultMap type="Employee" id="selectDepartmentByIdEmployeeStepTwoResultMap">
		<id property="eid" column="eid"/>
		<result property="empName" column="emp_name"/>
		<result property="gender" column="gender"/>
		<result property="age" column="age"/>
		<result property="email" column="email"/>	
	</resultMap>
	<!-- Employee selectDepartmentByIdEmployeeStepTwo(@Param("id") Integer id); -->
	<select id="selectDepartmentByIdEmployeeStepTwo" resultMap="selectDepartmentByIdEmployeeStepTwoResultMap">
		select * from t_employee where did=#{id};
	</select>

test

@Test
	public void TestSelectDepartmentByIdEmployeeStepTwo() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		
		Employee employee = employeeMapper.selectDepartmentByIdEmployeeStepTwo(1);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(employee);
		
	}
	
	@Test
	public void testSelectDepartmentByIdEmployeeStepOne() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
		
		Department department = departmentMapper.selectDepartmentByIdEmployeeStepOne(1);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println(department);
		
	}

分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载,此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”。

动态(Dynamic)SQL

if

	/**
	 * 多条件查询
	 * @param 实体类对象
	 * @return 对象集合
	 */
	List<Employee> selectEmployeeByCondition(Employee employee);
	<!-- List<Employee> selectEmployeeByCondition(Employee employee); -->
	<select id="selectEmployeeByCondition" resultMap="employeeMap">
		
		select * from t_employee where 1=1
		
		<if test="empName != '' and empName != null">
			and emp_name=#{empName}
		</if>
		<if test="age != '' and age != null">
			and age=#{age}
		</if>
		<if test="sex != '' and sex != null">
			and sex=#{sex}
		</if>
		
	</select>
	@Test
	public void selectEmployeeByCondition() {
		
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		List<Employee> employees = employeeMapper.selectEmployeeByCondition(new Employee(null, "宋江", null, "男", "110@qq.com", 1));
		
		for (Employee employee : employees) {
			System.out.println(employee);
		}
		
	}

where

	/**
	 * 多条件查询;where的使用
	 * @param 实体类对象
	 * @return 对象集合
	 */
	List<Employee> selectEmployeeByConditionWhere(Employee employee);
	<!-- List<Employee> selectEmployeeByConditionWhere(Employee employee); -->
	<select id="selectEmployeeByConditionWhere" resultMap="employeeMap">
		
		select * from t_employee
		
		<where>
			
			<if test="empName != '' and empName != null">
				emp_name=#{empName}
			</if>
			<if test="age != '' and age != null">
				and age=#{age}
			</if>
			<if test="sex != '' and sex != null">
				and sex=#{sex}
			</if>
			
		</where>
		
	</select>
	@Test
	public void selectEmployeeByConditionWhere() {
		
		SqlSession sqlSession = SqlSessionUtil.getSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		List<Employee> employees = employeeMapper.selectEmployeeByConditionWhere(new Employee(null, "宋江", null, "男", "110@qq.com", 1));
		
		for (Employee employee : employees) {
			System.out.println(employee);
		}
		
	}

where 和 if 一般结合使用:
若 where 标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
若 where 标签中的if条件满足,则 where 标签会自动添加 where 关键字,并将条件最前方多余的 and 去掉
where 标签不能去掉条件最后多余的 and 。

trim

choose、when、otherwise

foreach

删除操作

EmployeeMapper.java

	/**
     * 批量删除
     * @param 数组
     * @return 删除影响行数
     */
	int deleteEmplyoeeBatchArray(@Param("ids") Integer[] ids);

EmployeeMapper.xml

	<!-- int deleteEmplyoeeBatchArray(Integer[] ids); -->
	<delete id="deleteEmplyoeeBatchArray">
		delete from t_employee where eid in
		<foreach collection="ids" item="id" separator="," open="(" close=")">
			#{id}
		</foreach>
	</delete>

日志输出信息:

DEBUG 04-08 16:56:02,476 ==> Preparing: delete from t_employee where eid in ( ? , ? , ? ) (BaseJdbcLogger.java:137)
DEBUG 04-08 16:56:02,508 > Parameters: 5(Integer), 6(Integer), 7(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-08 16:56:02,511 <
Updates: 3 (BaseJdbcLogger.java:137)
结果:3

	<!-- int deleteEmplyoeeBatchArray(Integer[] ids); -->
	<delete id="deleteEmplyoeeBatchArray">
		delete from t_employee where
		<foreach collection="ids" item="id" separator="or" open="where">
			eid=#{id}
		</foreach>
	</delete>

日志输出信息:

DEBUG 04-08 17:12:47,834 ==> Preparing: delete from t_employee where eid=? or eid=? or eid=? (BaseJdbcLogger.java:137)
DEBUG 04-08 17:12:47,856 > Parameters: 8(Integer), 9(Integer), 10(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-08 17:12:47,870 <
Updates: 3 (BaseJdbcLogger.java:137)
结果:3

test

	@Test
	public void testDeleteEmplyoeeBatchArray() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		
		Integer[] array = new Integer[] {8, 9, 10};
		int deleteResultCount = employeeMapper.deleteEmplyoeeBatchArray(array);
		
		System.out.println("结果:" + deleteResultCount);
		
	}

collection:设置要循环的数组或集合
item:表示集合或数组中的每一个数据
separator:设置循环体之间的分隔符
open:设置foreach标签中的内容的开始符
close:设置foreach标签中的内容的结束符

插入操作

EmployeeMapper.java

	/**
	 * 批量添加
	 * @param employees集合
	 * @return 插入成功的条数
	 */
	int insertEmployeeBatchList(@Param("employees") List<Employee> employees);

EmployeeMapper.xml

	<!-- int insertEmployeeBatchList(@Param("employees") List<Employee> employees); -->
	<insert id="insertEmployeeBatchList">
		insert into t_employee values
			<foreach collection="employees" item="employee" separator=",">
				(null, #{employee.empName}, #{employee.gender}, #{employee.age}, #{employee.email}, #{employee.did})	
			</foreach>	
	</insert>

test

	@Test
	public void testInsertEmployeeBatchList() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
		
		Employee employee = new Employee("宋江", 1, 55, "982902178@qq.com", 2, null);
		Employee employee1 = new Employee("卢俊义", 1, 56, "982902178@qq.com", 2, null);
		Employee employee2 = new Employee("吴用", 1, 57, "982902178@qq.com", 2, null);
		
		List<Employee> employees = Arrays.asList(employee, employee1, employee2);
		
		int insertResultCount = employeeMapper.insertEmployeeBatchList(employees);
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		System.out.println("结果:" + insertResultCount);
		
	}

日志输出结果:

DEBUG 04-08 18:19:24,298 ==>  Preparing: insert into t_employee values (null, ?, ?, ?, ?, ?) , (null, ?, ?, ?, ?, ?) , (null, ?, ?, ?, ?, ?) (BaseJdbcLogger.java:137) 
DEBUG 04-08 18:19:24,343 ==> Parameters: 宋江(String), 1(Integer), 55(Integer), 982902178@qq.com(String), 2(Integer), 卢俊义(String), 1(Integer), 56(Integer), 982902178@qq.com(String), 2(Integer), 吴用(String), 1(Integer), 57(Integer), 982902178@qq.com(String), 2(Integer) (BaseJdbcLogger.java:137) 
DEBUG 04-08 18:19:24,347 <==    Updates: 3 (BaseJdbcLogger.java:137) 
结果:3

SQL 片段

SQL片段,可以记录一段公共SQL片段,在使用的地方通过include标签进行引入。

<sql id="empColumns">
    eid, ename, age, sex, did
</sql>

select <include refid="empColumns"></include> from t_emp;

MyBatis 的缓存

MyBatis 的一级缓存

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
使一级缓存失效的四种情况:
1、不同的SqlSession对应不同的一级缓存。
2、同一个SqlSession但是查询条件不同。
3、同一个SqlSession两次查询期间执行了任何一次增删改操作。
4、同一个SqlSession两次查询期间手动清空了缓存。

下列案例使用了一级缓存,只执行了一次SQL

	@Test
	public void testSelectUserAll() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		
		List<User> users = userMapper.findAllUser();
		
		List<User> users1 = userMapper.findAllUser();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		
		users.forEach(System.out::println);
		System.out.println("****************");
		users1.forEach(System.out::println);
		
	}
DEBUG 04-09 08:49:34,212 ==>  Preparing: select * from t_user; (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:49:34,242 ==> Parameters:  (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:49:34,265 <==      Total: 11 (BaseJdbcLogger.java:137) 

不同的SqlSession对应不同的一级缓存。

	@Test
	public void testSelectUserAll() {
		
		SqlSession sqlSession = MyBatisUtil.createSqlSession();
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);		
		List<User> users = userMapper.findAllUser();
		
		SqlSession sqlSession1 = MyBatisUtil.createSqlSession();
		UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
		List<User> users1 = userMapper1.findAllUser();
		
		MyBatisUtil.closeSqlSession(sqlSession);
		MyBatisUtil.closeSqlSession(sqlSession1);
		
		users.forEach(System.out::println);
		System.out.println("****************");
		users1.forEach(System.out::println);
		
	}
DEBUG 04-09 08:52:22,531 ==>  Preparing: select * from t_user; (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:52:22,588 ==> Parameters:  (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:52:22,604 <==      Total: 11 (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:52:22,623 ==>  Preparing: select * from t_user; (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:52:22,624 ==> Parameters:  (BaseJdbcLogger.java:137) 
DEBUG 04-09 08:52:22,628 <==      Total: 11 (BaseJdbcLogger.java:137) 

MyBatis 的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取.
二级缓存开启的条件:
1、在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
2、在映射文件中设置标签
3、二级缓存必须在SqlSession关闭或提交之后有效
4、查询的数据所转换的实体类类型必须实现序列化的接口

使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。

二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:

eviction属性:缓存回收策略
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。

flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

MyBatis 缓存查询的顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存。
如果一级缓存也没有命中,则查询数据库。
SqlSession关闭之后,一级缓存中的数据会写入二级缓存。

整合第三方缓存 EHCache

添加依赖

		<!-- MyBatis EHCache整合包 -->
		<dependency>
			<groupId>org.mybatis.caches</groupId>
			<artifactId>mybatis-ehcache</artifactId>
			<version>1.2.1</version>
		</dependency>
		
		<!-- slf4j日志门面的一个具体实现 -->
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>

各jar包功能

jar包名称作用
mybatis-ehcacheMybatis和EHCache的整合包
ehcacheEHCache核心包
slf4j-apiSLF4J日志门面包
logback-classic支持SLF4J门面接口的一个具体实现

创建EHCache的配置文件:ehcache.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xml>

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  
<!-- 磁盘保存路径 -->
  <diskStore path="D:\data\mybatis\ehcache"/>
 
  <defaultCache>
      maxElementsInMemory="1000"
      maxElementsOnDisk="10000000"
      eternal="false"
      overflowToDisk="true"
      timeToIdleSeconds="120"
      timeToLiveSeconds="120"
      diskExpiryThreadIntervalSeconds="120"
      memoryStoreEvictionPolicy="LRU">
  </defaultCache>

</ehcache>

设置二级缓存的类型

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时需要SLF4J的具体实现logback来打印日志。
创建logback的配置文件logback.xml。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>

<configuration debug="true">
	  
	<!-- 指定日志输出的位置 -->  
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
			    
		<encoder>
		    <!-- 日志输出的格式 -->
		    <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->      
		    <pattern>
		    	[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n
		    </pattern>    
	    
	    </encoder>  
	    
	    </appender> 
			
			<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
		    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
		    <root level="DEBUG">
				<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->    
				<appender-ref ref="STDOUT" />		  
			</root>
			 
			<!-- 根据特殊需求指定局部日志级别 -->  
			<logger name="com.jack.crowd.mapper" level="DEBUG" />
			 
</configuration>

EHCache的配置文件说明

属性名是否必须作用
maxElementsInMemory在内存中缓存的element的最大数目
maxElementsOnDisk在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断
overflowToDisk设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
timeToIdleSeconds当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMBDiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskPersistent在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)

MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
1、Java实体类
2、Mapper接口
3、Mapper映射文件

创建逆向工程的步骤

添加依赖和插件

<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.seagreen</groupId>
	<artifactId>maven_mybatis_1</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<packaging>jar</packaging>

	<dependencies>

		<!-- MySQL -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.3</version>
		</dependency>

		<!-- MyBatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.9</version>
		</dependency>

		<!-- log4j -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>

		<!-- junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.9</version>
			<scope>test</scope>
		</dependency>

		<!-- Mybatis EHCache整合包 -->
		<dependency>
			<groupId>org.mybatis.caches</groupId>
			<artifactId>mybatis-ehcache</artifactId>
			<version>1.2.1</version>
		</dependency>

		<!-- slf4j日志门面的一个具体实现 -->
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>

	</dependencies>

	<!-- 控制Maven在构建过程中相关配置 -->
	<build>

		<!-- 构建过程中用到的插件 -->
		<plugins>

			<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
			<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>1.3.0</version>

				<!-- 插件的依赖 -->
				<dependencies>

					<!-- 逆向工程的核心依赖 -->
					<dependency>
						<groupId>org.mybatis.generator</groupId>
						<artifactId>mybatis-generator-core</artifactId>
						<version>1.3.2</version>
					</dependency>

					<!-- 数据库连接池 -->
					<dependency>
						<groupId>com.mchange</groupId>
						<artifactId>c3p0</artifactId>
						<version>0.9.2</version>
					</dependency>

					<!-- MySQL驱动 -->
					<dependency>
						<groupId>mysql</groupId>
						<artifactId>mysql-connector-java</artifactId>
						<version>5.1.8</version>
					</dependency>
					
				</dependencies>
				
			</plugin>

		</plugins>
		
	</build>

</project>

创建逆向工程的配置文件:generatorConfig.xml

文件名必须是:generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!--
    	targetRuntime: 执行生成的逆向工程的版本
        	MyBatis3Simple: 生成基本的CRUD
            MyBatis3: 生成带条件的CRUD
     -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
    
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/test_jack"
                        userId="root"
                        password="root">
        </jdbcConnection>
        
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.jack.generator.entity" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.jack.generator.mapper"  targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.jack.generator.mapper"  targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_employee" domainObjectName="Employee"/>
        <table tableName="t_department" domainObjectName="Department"/>
        
    </context>
    
</generatorConfiguration>

执行插件的generate目标

eclipse中,项目右键或pom.xml右键,Run As -> Maven build
在弹出的对话框中输入:mybatis-generator:generate

idea中: 双击即可。
在这里插入图片描述

QBC 查询

QBC(Quary By Criteria),Criteria是Criterion的复数,译为规则,准则。在SQL语句中相当于查询条件。
QBC查询是将查询条件通过Java对象进行模块化封装。

@Test
	public void testGenerator() {

		InputStream inputStream = null;
		SqlSession sqlSession = null;
		
		try {
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
			SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			sqlSession = sqlSessionFactory.openSession(true);
			
			EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
			
			// 查询所有数据
			List<Employee> list = employeeMapper.selectByExample(null);
			
			list.forEach(System.out::println);
			
			// 根据条件查询
			EmployeeExample employeeEexample = new EmployeeExample();
			employeeEexample.createCriteria().andEmpNameEqualTo("宋江").andAgeGreaterThanOrEqualTo(20);
			employeeEexample.or().andDidIsNotNull();
			
			List<Employee> employees = employeeMapper.selectByExample(employeeEexample);
			employees.forEach(System.out::println);
			
			Employee employee = new Employee();
			employee.setEid(22L);
			employee.setEmpName("林冲");
			employee.setGender((byte)1);
			employee.setAge(50);
			employee.setEmail("982902178@qq.com");
			employee.setDid(1L);
			
			employeeMapper.updateByPrimaryKeySelective(employee);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			sqlSession.close();
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}

PageHelper分页插件

官网地址:https://pagehelper.github.io/

添加依赖

<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.3.2</version>
</dependency>

配置分页插件

在MyBatis的核心配置文件中配置PageHelper插件。

<plugins>
 		<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>

分页插件的使用

1、在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数

	@Test
    public void testPageHelper(){
        
    	SqlSession sqlSession = MyBatisUtil.createSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
        //PageHelper.startPage(2, 2);
        
        Page<Object> page = PageHelper.startPage(2, 4); //print:Page{count=true, pageNum=2, pageSize=4, startRow=4, endRow=8, total=11, pages=3, reasonable=false, pageSizeZero=false}[User [id=6, username=卢俊义, password=1234, age=51, sex=null, email=111@qq.com], User [id=7, username=卢俊义, password=1234, age=51, sex=null, email=111@qq.com], User [id=8, username=宋江, password=songjiang, age=51, sex=null, email=982902178@qq.com], User [id=9, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com]]
        
        List<User> users = userMapper.selectAllUser();
        
        //PageInfo<User> page = new PageInfo<>(users, 5); //print:PageInfo{pageNum=1, pageSize=11, size=11, startRow=0, endRow=10, total=11, pages=1, list=[User [id=2, username=宋江, password=songjiang, age=50, sex=null, email=982902178@qq.com], User [id=3, username=宋江, password=songjiang, age=50, sex=null, email=982902178@qq.com], User [id=4, username=宋江, password=songjiang, age=51, sex=null, email=982902178@qq.com], User [id=5, username=卢俊义, password=1234, age=51, sex=null, email=111@qq.com], User [id=6, username=卢俊义, password=1234, age=51, sex=null, email=111@qq.com], User [id=7, username=卢俊义, password=1234, age=51, sex=null, email=111@qq.com], User [id=8, username=宋江, password=songjiang, age=51, sex=null, email=982902178@qq.com], User [id=9, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com], User [id=10, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com], User [id=11, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com], User [id=12, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com]], prePage=0, nextPage=0, isFirstPage=true, isLastPage=true, hasPreviousPage=false, hasNextPage=false, navigatePages=5, navigateFirstPage=1, navigateLastPage=1, navigatepageNums=[1]}
        
        users.forEach(System.out::println);
        
        System.out.println(page); 

    }

输出结果:

age
{
	count=true, 
	pageNum=2,    
	pageSize=4, 
	startRow=4,
	endRow=8, 
	total=10, 
	pages=3, 
	reasonable=false,
	pageSizeZero=false	
}
	
[
	User [id=5, username=宋江, password=songjiang, age=51, sex=null, email=982902178@qq.com], 
	User [id=6, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com],
	User [id=7, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com], 
	User [id=8, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com]
]

pageNum:当前页码;第几页
pageSize:每页条数
startRow:从第几条开始,不包括startRow
endRow:从第几条结束
total:总条数;共多少条数据
pages:总页数,共多少页

2、在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据
list:分页之后的数据
navigatePages:导航分页的页码数

@Test
    public void testPageHelper(){
        
    	SqlSession sqlSession = MyBatisUtil.createSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
        PageHelper.startPage(3, 3);
        
        //Page<Object> page = PageHelper.startPage(3, 3); 
        List<User> users = userMapper.selectAllUser();
        
        PageInfo<User> page = new PageInfo<User>(users, 5); 
        
        users.forEach(System.out::println);
        
        System.out.println(page); 

    }

一共10条数据测试

1 4  7  10 
2 5  8 
3 6  9 

PageInfo{

	pageNum=3, 
	pageSize=3, 
	size=3, 
	startRow=7, 
	endRow=9, 
	total=10,
	pages=4, 
	
	list=Page{
	
		count=true, 
		pageNum=3, 
		pageSize=3, 
		startRow=6, 
		endRow=9, 
		total=10, 
		pages=4, 
		reasonable=false, 
		pageSizeZero=false
	}
		
	[
		User [id=7, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com], 
		User [id=8, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com],
		User [id=9, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com]
	],
			
	prePage=2, 
	nextPage=4, 
	isFirstPage=false, 
	isLastPage=false, 
	hasPreviousPage=true, 
	hasNextPage=true, 
	navigatePages=5, 
	navigateFirstPage=1, 
	navigateLastPage=4, 
	navigatepageNums=[1, 2, 3, 4]
			
}

一共16条数据测试

1 4  7  10 13 16
2 5  8  11 14
3 6  9  12 15

Page<Object> page = PageHelper.startPage(3, 3); 想显示第3页的3条数据

PageInfo
{
	pageNum=3,
	pageSize=3, 
	size=3, 
	startRow=7, 
	endRow=9, 
	total=16, 
	pages=6, 
	
	list=Page
	{
		count=true, 
		pageNum=3, 
		pageSize=3, 
		startRow=6, 
		endRow=9, 
		total=16, 
		pages=6, 
		reasonable=false, 
		pageSizeZero=false
	}	
	[	User [id=7, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com], 
		User [id=8, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com],
		User [id=9, username=宋江, password=songjiang, age=56, sex=null, email=982902178@qq.com]], 
			 
			 prePage=2, 
			 nextPage=4, 
			 isFirstPage=false, 
			 isLastPage=false, 
			 hasPreviousPage=true, 
			 hasNextPage=true, 
			 navigatePages=5, 
			 navigateFirstPage=1, 
			 navigateLastPage=5, 
			 navigatepageNums=[1, 2, 3, 4, 5]
}

常用数据:
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]

逆向工程项目下使用分页PageHelper

/**
     * limit index,pageSize
     * index:当前页的起始索引
     * pageSize:每页显示的条数
     * pageNum:当前页的页码
     * index=(pageNum-1)*pageSize
     *
     * 使用MyBatis的分页插件实现分页功能:
     * 1、需要在查询功能之前开启分页
     * PageHelper.startPage(int pageNum, int pageSize);
     * 2、在查询功能之后获取分页相关信息
     * PageInfo<Emp> page = new PageInfo<>(list, 5);
     * list表示分页数据
     * 5表示当前导航分页的数量
     */
    @Test
    public void testPageHelper() {
    	
    	InputStream inputStream = null;
    	SqlSession sqlSession = null;
    	
        try {
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession(true);
            
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            
            //Page<Object> page = PageHelper.startPage(2, 4);
            PageHelper.startPage(2, 4);
            
            List<Employee> employees = employeeMapper.selectByExample(null);
            PageInfo<Employee> page = new PageInfo<Employee>(employees, 5);
            
            employees.forEach(employee -> System.out.println(employee));
            
            System.out.println("******************");
            
            employees.forEach(System.out::println);
            
            System.out.println("******************");
            
            System.out.println(page);
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        	sqlSession.close();
        	try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        }

    }

问题:
1、‘${}’

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis PageHelper是一个用于实现分页查询的插件,它可以帮助我们快速实现分页功能,并且与Mapper.xml完全解耦,避免了直接编写分页SQL的麻烦。在使用MyBatis PageHelper时,可以根据不同的情况进行配置。 如果你使用的是Spring Boot,可以直接配置几个属性来启用MyBatis PageHelper。在application.properties或application.yml文件中,添加以下配置项: ``` mybatis.configuration-properties.helperDialect=mysql mybatis.configuration-properties.offsetAsPageNum=true mybatis.configuration-properties.rowBoundsWithCount=true mybatis.configuration-properties.reasonable=true mybatis.configuration-properties.mapper-locations=mybatis/mapper/*.xml ``` 其中,helperDialect指定了数据库的方言,offsetAsPageNum设置为true表示使用RowBounds分页方式,rowBoundsWithCount设置为true表示查询总数时会同时执行count查询,reasonable设置为true表示当pageNum<=0或pageNum>pages时会自动修正为合理的值,mapper-locations指定了Mapper.xml文件的位置。 另外,如果你使用的是Spring Boot,还可以直接引入pagehelper-spring-boot-starter依赖,它会自动配置PageHelper,省去了许多不必要的配置。 ```xml <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.12</version> </dependency> ``` 通过以上配置,你就可以在MyBatis中使用PageHelper来实现分页查询了。 #### 引用[.reference_title] - *1* [【Mybatis】使用PageHelper进行分页查询](https://blog.csdn.net/Flying_Ape/article/details/128098911)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Mybatis分页插件——PageHelper快速入门](https://blog.csdn.net/weixin_52850476/article/details/124802877)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值