前置知识:JDBC

学习视频

Mybatis——一种ORM框架:将Java中的Bean映射为数据库的记录

  • ORM:用于实现面向对象编程语言里不同类型系统的数据之间的转换

Mybatis运行过程——工厂模式

#{}${} ——三点区别

动态Sql

分页——两种方法

缓存——查询缓存顺序

MyBatis

文档

官方文档

下载链接

sql相关

  • sql引擎
  • innoDB底层
  • 索引
  • 索引优化

概述

JDBC

JDBC驱动程序:JDBC(Java Database Connectivity, Java 数 据 库 连 接)是 一 种可用于执行 SQL 语句的 Java API(Application Programming Interface)

  • 实现了从 Java 程序内调用标准的 SQL命令 对数据库进行查询、插入、删除和更新等操作, 并确保数据事务的正常进行

  • 基本层次结构由 Java 程序、JDBC 驱动程序管理器、数据库驱动程序和数据库四部分组成

  • Java 程序依赖于 JDBC API,通过 DriverManager 来获取驱动,并且针对不同的数据库可以使用不同的驱动。

  • 这是典型的桥接的设计模式,把 抽象 Abstraction行为实现Implementation 分离 开来,从而可以保持各部分的独立性以及应对他们的功能扩展。

JDBC步骤

public static void connectionTest(){Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {// 1. 加载并注册 MySQL 驱动器实例Class.forName("com.mysql.cj.jdbc.Driver").newInstance();// 2. 将Mysql驱动程序注册到驱动管理程序中//        根据特定的数据库连接URL,返回与此URL所匹配的数据库驱动对象Driver driver = DriverManager.getDriver("jdbc:mysql://localhost:3306/[dbName]"); // 3. 传入参数,比如说用户名和密码Properties props = new Properties();props.put("user", USER_NAME);props.put("password", PASSWORD);// 4. 使用数据库驱动创建数据库连接 Connectionconnection = driver.connect(URL, props);// 5. 从数据库连接 connection 中获得 Statement 对象statement = connection.createStatement();// 6. 执行 sql 语句,返回结果resultSet = statement.executeQuery("select * from activity");// 7. 处理结果,取出数据while(resultSet.next()){System.out.println(resultSet.getString(2));}.....}finally{// 8.关闭链接,释放资源  按照JDBC的规范,使用完成后管理链接,// 释放资源,释放顺序应该是: ResultSet ->Statement ->ConnectionresultSet.close();statement.close();connection.close();}
}

JDBC存在的问题

  • 传统的JDBC代码复杂
  • 实现步骤多
  • 需要设计一种 将数据映射到数据库的框架 来简化JDBC的步骤

Mybatis特点

  • 持久层框架

    持久化:将程序中的数据从 瞬时状态【内存:断电即失】转化为 持久状态【数据库jdbc,io文件持久化】的过程

    持久层:完成数据持久化工作的代码块,层次间界限分明

  • 定制化Sql

  • 避免JDBC代码,手动设置参数和获取结果集

优点

  • 简单:两个jar文件(mybatis.jar+mysql-connector.jar)+配置几个sql映射文件(Mapper)
  • 灵活:sql写在xml里,统一管理(mybatis-config.xml
  • 解除sql与程序的耦合:通过提供Mapper层,将业务逻辑与数据访问逻辑分离
  • 提供映射标签:JavaBean与数据库字段的关系映射
  • 提供xml标签,支持编写动态sql

Mybatis执行流程

通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO

  1. 获取配置文件
  2. 实例化 SqlSessionFactoryBuilder
  3. 加载 mybatis-config.xml 中的配置信息
  4. 实例化 SqlsessionFactory
  5. 创建执行器 executor
  6. 创建 SqlSession
  7. 实现CRUD逻辑
  8. CRUD后提交事务,判断是否执行成功
#mermaid-svg-NVpap7Rp8SLvnviA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .error-icon{fill:#552222;}#mermaid-svg-NVpap7Rp8SLvnviA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NVpap7Rp8SLvnviA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NVpap7Rp8SLvnviA .marker.cross{stroke:#333333;}#mermaid-svg-NVpap7Rp8SLvnviA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NVpap7Rp8SLvnviA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster-label text{fill:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster-label span{color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .label text,#mermaid-svg-NVpap7Rp8SLvnviA span{fill:#333;color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .node rect,#mermaid-svg-NVpap7Rp8SLvnviA .node circle,#mermaid-svg-NVpap7Rp8SLvnviA .node ellipse,#mermaid-svg-NVpap7Rp8SLvnviA .node polygon,#mermaid-svg-NVpap7Rp8SLvnviA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NVpap7Rp8SLvnviA .node .label{text-align:center;}#mermaid-svg-NVpap7Rp8SLvnviA .node.clickable{cursor:pointer;}#mermaid-svg-NVpap7Rp8SLvnviA .arrowheadPath{fill:#333333;}#mermaid-svg-NVpap7Rp8SLvnviA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NVpap7Rp8SLvnviA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NVpap7Rp8SLvnviA .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-NVpap7Rp8SLvnviA .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster text{fill:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster span{color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NVpap7Rp8SLvnviA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

Resources获取加载全局配置文件
实例化SqlSessionFactoryBuilder构造器
解析配置文件流XMLConfigBuilder
Configuration加载所有的配置信息
SqlSessionFactory实例化
transactional事务管理器
创建executor执行器
创建SqlSession
实现CRUD
查看是否执行成功
提交事务
关闭

1. 导包——Maven

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version>
</dependency>

SqlSessionFactoryBuilder

一旦创建了 SqlSessionFactory ,就不再需要它了。

因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域

  • 作用域:局部变量

SqlSessionFactory <=> 数据库连接工厂

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心

构造方法:从xml中配置文件中构建SqlSessionFactory实例

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在

  • 作用域:应用作用域

最简单的就是使用单例模式或者静态单例模式。

SqlSession => JDBC:Connection对象

通过 SqlSessionFactory 获得 SqlSession 的实例。

SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。

SqlSession的实例时线程不安全的,不能被共享

  • 每次收到一个数据库访问请求,打开一个SqlSession,返回响应后,立即关闭

Mapper => JDBC:Statement

代理对象 执行具体业务

将接口与xml进行绑定

Mybatis示例程序

#mermaid-svg-GeLKu5fxhYgbgLBt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .error-icon{fill:#552222;}#mermaid-svg-GeLKu5fxhYgbgLBt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GeLKu5fxhYgbgLBt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GeLKu5fxhYgbgLBt .marker.cross{stroke:#333333;}#mermaid-svg-GeLKu5fxhYgbgLBt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GeLKu5fxhYgbgLBt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster-label text{fill:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster-label span{color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .label text,#mermaid-svg-GeLKu5fxhYgbgLBt span{fill:#333;color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .node rect,#mermaid-svg-GeLKu5fxhYgbgLBt .node circle,#mermaid-svg-GeLKu5fxhYgbgLBt .node ellipse,#mermaid-svg-GeLKu5fxhYgbgLBt .node polygon,#mermaid-svg-GeLKu5fxhYgbgLBt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GeLKu5fxhYgbgLBt .node .label{text-align:center;}#mermaid-svg-GeLKu5fxhYgbgLBt .node.clickable{cursor:pointer;}#mermaid-svg-GeLKu5fxhYgbgLBt .arrowheadPath{fill:#333333;}#mermaid-svg-GeLKu5fxhYgbgLBt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GeLKu5fxhYgbgLBt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GeLKu5fxhYgbgLBt .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-GeLKu5fxhYgbgLBt .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster text{fill:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster span{color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GeLKu5fxhYgbgLBt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

搭建环境
编写代码
测试
导入mysql驱动,MyBatis包
核心配置文件mybatis-config.xml
编写工具类提供SqlSession对象

1. 搭建数据库

create table user(id int(11) not null primary key,user_name varchar(30) default null,pwd varchar(30) default null
)engine=InnoDB default charset=utf8;insert into user(id,user_name,pwd) values
(1,'a','123456'),
(2,'b','123456'),
(3,'c','c123456');

2. 新建项目

3. 删除src,使项目成为父工程

4. maven导入依赖

<!-- 父工程 -->
<groupId>com.kuang.MyBatis</groupId>
<artifactId>MyBatis</artifactId>
<version>1.0-SNAPSHOT</version><!-- 导入依赖 -->
<dependencies><!-- 导入MySql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!-- 导入MyBatis驱动 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!-- 导入junit依赖 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>
</dependencies>

5. 新建模块

6. 获取数据库连接对象

a. 编写核心配置文件——mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- configuration的核心配置 -->
<configuration><!-- 可配置多套环境,defaulte属性选择当前属性 --><environments default="development"><environment id="development"><!-- 事务管理器 --><transactionManager type="JDBC"/><dataSource type="POOLED"><!-- 配置数据库驱动器类型及连接参数 --><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="2017002231"/></dataSource></environment></environments><!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册 --><mappers><mapper resource="com/kuang/dao/UserMapper.xml"/></mappers>
</configuration>
  • useSSL:使用安全连接
  • useUnicode:保证中文不乱码
  • characterEncoding:编码格式

b. 编写MyBatis工具类

新建dao包,utils包

public class MyBatisUtils {private static SqlSessionFactory sqlSessionFactory;// 1.获取SqlSessionFactory对象static{try {//1. 将资源中的配置文件以流的形式读入String resource = "mybatis-config.xml";InputStream configuration = Resources.getResourceAsStream(resource);//2. 通过工厂类构建器构建SqlSessionFactory类sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);} catch (IOException e) {e.printStackTrace();}}// 2.获取SqlSession对象public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}
}

7. 编写代码

实体类

pojo的作用就是将从数据库获取到的数据封装为一个一个的对象,让java能够更好的进行操作DO、VO

package com.kuang.pojo;public class User {private Integer id;private String user_name;private String pwd;public User(){}public User(Integer id, String user_name, String pwd) {this.id = id;this.user_name = user_name;this.pwd = pwd;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUser_name() {return user_name;}public void setUser_name(String user_name) {this.user_name = user_name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User{" +"id=" + id +", user_name='" + user_name + '\'' +", pwd='" + pwd + '\'' +'}';}
}

Dao接口

public interface UserDao{List<User> getUserList();
}

接口的实现

由 UserDaoImpl 转化为 Mapper 配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- 绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.kuang.dao.UserDao"><!--id:方法名--><select id="getUserList" resultType="com.kuang.pojo.User">select *from mybatis.user;</select>
</mapper>
  • namespace:相当于指定要实现的接口

    • 将不同的语句隔离开来,同时也实现了接口绑定

      • 全限定名(比如 “com.mypackage.MyMapper.selectAllThings)将被直接用于查找及使用
      • 短名称(比如 “selectAllThings”)如果全局唯一也可以作为一个单独的引用。 如果不唯一,有两个或两个以上的相同名称(比如 “com.foo.selectAllThings” 和 “com.bar.selectAllThings”),那么使用时就会产生“短名称不唯一”的错误,这种情况下就必须使用全限定名。
  • id:方法名
  • resultType:返回单个
  • resultMap:返回多个

8. 测试

新建 测试类

编写测试代码

package com.kuang.dao;import com.kuang.pojo.User;
import com.kuang.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class UserDaoTest {@Testpublic void test(){//1.获取SqlSession对象SqlSession sqlSession = MyBatisUtils.getSqlSession();//2.执行Sql
//通过反射机制,获取方法区中UserMapper的Class类实例,这个实例中有UserMapper全部信息UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<User> userList = userMapper.getUserList();/*//方式二:强制类型转换,不安全List<User> userList = sqlSession.selectOne("com.kuang.UserDao.getUserList");*/for (User user:userList){System.out.println(user);}//关闭sqlSessionsqlSession.close();}
}

遇到的各种错误

org.apache.ibatis.io不存在——IDEA2020.1


class not found:ClassTest

执行UserDaoTest的test方法之前,要先 mvn test-compile 生成 test classes才可被部署并发现


Type interface com.kuang.dao.UserDao is not known to the MapperRegistry

<!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册 -->
<mappers><mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>

Could not find resource com/kuang/dao/UserMapper.xml

Maven约定大于配置,自己写的配置文件默认不会被导出或生效

Maven默认的资源(自己配置的xml)位置在resources目录下,当前项目的xml位于java目录下,所以找不到

<!-- build中配置resources,防止资源导出失败问题 -->
<build><resources><resource><!-- 使得directory目录下的资源可以被导出 --><directory>src/main/java</directory><!-- 设置可被识别通过的文件类型 --><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><!-- 使得directory目录下的资源可以被导出 --><directory>src/main/resources</directory><!-- 设置可被识别通过的文件类型 --><includes><include>**/*.propertes</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources>
</build>

终于成功

增删改查CRUD

CUD 需要通过connection对象以Transition(事务)的形式提交

  1. 编写接口
  2. (实现接口)编写mapper中对应的sql语句
  3. 测试

select

选择,查询语句:

  • id:方法名
  • resultType:Sql语句执行的返回值
  • parameterType:参数类型

通过id获取用户

模糊查询

  1. Java代码执行时,传递通配符 %%

  2. 在sql语句拼接中使用通配符

    • 存在sql注入的风险

insert



并没有新增

更新

删除



参数传递&Map

单个参数传递方式

  • 只有一个 基本数据类型 ,可省略
  • 实体类对象作为参数,sql语句中的参数取对象的属性
  • Map作为参数,sql语句中参数取Map的属性

多个参数的传递

使用Map的情况

当字段过多时,考虑使用 Map,可以自定义需要传递的参数

  • 若使用实体类作为参数传递,当字段过多时,一个实体类的每个属性都必须设置值

Plugin——通用Mapper

核心配置——mybatis-config.xml

configuration(配置)

  • properties(属性)
  • settings(设置)
  • typeAliases(类型别名)
  • environments(环境配置)
    • environment(环境变量)

      • transactionManager(事务管理器)
      • dataSource(数据源)
  • mappers(映射器)

属性(properties)

通过Properties引用配置文件

  • 优先使用外部配置文件
  1. properties文件定义属性的键值对——定义变量
#db.properties
mysql_driver=com.mysql.cj.jdbc.Driver
#不需要转义&amp;
MyBatis_url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8
db_username=root
db_pwd=2017002231
  1. 通过 <properties/> 声明引用属性

    <!-- properties引用属性变量 -->
    <properties resource="db.properties"/>
    
  2. 使用属性

设置Settings

Setting Description Valid Values Default
cacheEnabled 是否缓存Globally enables or disables any caches configured in any mapper under this configuration. true | false true
lazyLoadingEnabled 懒加载,提高开发效率When enabled, all relations will be lazily loaded. This value can be superseded for a specific relation by using the fetchType attribute on it. true | false false
mapUnderscoreToCamelCase Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn. true | false false
logImpl MyBatis的日志实现方式Specifies which logging implementation MyBatis should use. LOG4J|STDOUT_LOGGING No Set
日志实现——logImpl
  • SLF4J
  • LOG4J | LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING
  • NO_LOGGING
STDOUT_LOGGING
<!--设置日志实现方式-->
<settings><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

  • 由日志可见,MyBatis底层是基于JDBC实现的
LOG4J
  • 控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等
  • 控制每一条日志的输出格式
  1. 导入 LOG4J

    <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
    </dependency>
    
  2. 配置log4j.properties资源

# 将等级为DEBUG的日志信息输出到console和file两个目的地,console和file的定义在下面的代码
log4j.rootLogger = debug,console,file# 控制台处处的相关配置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n# 文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./logs/log.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n# 日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

程序中使用log4j
  1. 导包

    import org.apache.log4j.Logger;
    
  2. 设置变量

    static Logger logger = Logger.getLogger(UserMapperTest.class);
    

    Logger.getLogger(className):将日志对象与目标对象绑定

  3. 使用

    log级别

    • info([信息])
    • debug([信息])
    • error([信息])

环境配置 enviroments

MyBatis 可以配置成适应多种环境,但每个 SqlSessionFactory 实例只能选择一种环境

如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。

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

事务管理器(transactionManager)

两种类型的事务管理器(也就是 type=“[JDBC|MANAGED]”)

  • 使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

数据源(dataSource)

连接数据库:

  • jdbc
  • dbcp
  • c3p0
  • druid

三种数据源类型

  1. UNPOOLED——用完即销毁

    • 无连接池,每次请求时打开和关闭连接

    • 浪费资源

  2. POOLED——用完即回收

  3. JNDI

类型别名typeAliases

用于减少完全限定名的冗余给Bean取别名

配置方式

  1. 实体类较少,可逐一指定

    <!-- mybatis-config.xml -->
    <typeAliases><typeAlias type="com.kuang.pojo.User" alias="User"/>
    </typeAliases><!-- UserMapper.xml -->
    <mapper namespace="com.kuang.mapper.UserMapper"><!--id:方法名--><select id="getUserList" resultType="User">select *from mybatis.user;</select>
    </mapper>
    
  2. You can also specify a package where MyBatis will search for all beans.包中实体类的别名为 lowercase(类名的首字母)

    <!-- mybatis-config.xml -->
    <typeAliases><package name="com.kuang.pojo" />
    </typeAliases><!-- UserMapper.xml -->
    <mapper namespace="com.kuang.mapper.UserMapper"><!--id:方法名--><select id="getUserList" resultType="user">select *from mybatis.user;</select>
    </mapper>
    
  3. If the @Alias annotation is found its value will be used as an alias. 优先级 :注解别名>配置别名

MyBatis默认配置的别名

Alias Mapped Type
_普通数据类型 普通数据类型(int,short,long,byte,double,float,boolean)
小写首字母(数据类型名) 首字母大写的数据类型(基本数据类型 + Date,Object,Map,HashMap,List,ArrayList,Collection,Iterator)
Integer,int BigDecimal
decimal,bigdecimal Integer

插件plugins

  • mybatis-generator-core

  • mybatis-plus

  • 通用mapper

映射器mapper

接口实现(mapper.xml)必须在configuration中注册才可被发现

第一种方式:资源路径【推荐】

<!-- Using classpath relative resources -->
<mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"/><mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

第二种方式:类名

<!-- Using mapper interface classes -->
<mappers><mapper class="org.mybatis.builder.AuthorMapper"/><mapper class="org.mybatis.builder.BlogMapper"/><mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

第三种方式:包内全导入

<!-- Register all interfaces in a package as mappers -->
<mappers><package name="org.mybatis.builder"/>
</mappers>

第二、三种方式的问题

  • 接口和Mapper配置文件必须同名
  • 接口和Mapper配置资源必须在同一包下

Mapper.xml(Dao实现类)

  • resultMap – The most complicated and powerful element that describes how to load your objects from the database result sets.

    • javaType:class——POJO| ArrayList
    • ofType:list 或 set 中的POJO
  • insert – A mapped INSERT statement.
  • update – A mapped UPDATE statement.
  • delete – A mapped DELETE statement.
  • select – A mapped SELECT statement.

解决属性名和字段名不一致问题——resultMap

简单的例子

public class User {private Integer id;private String user_name;private String password;
}

解决思路:起别名

sql 中,用 as 关键字,可以给某一字段起别名

select *from user where id=#{id}selectid as id,user_name as user_name,pwd as password
from user where id=#{id};

Mybatis 中,使用 ResultMap 做结果映射,只需要将有差异的属性与字段映射即可

  • property:POJO中的属性
  • column:数据库中的字段

复杂查询

实体间的复杂关系&环境搭建

关联association:多对一

  • 查到的是结果是满足某种关系的个体集

集合collection:一对多

  • 返回的结果是一个个体,其中某个属性是个体集

create table teacher(id int(10) not null,user_name varchar(30) default null,primary key(id)
)engine=InnoDB default charset=utf8;insert into teacher(id,user_name) values(1,'秦老师');
insert into teacher(id,user_name) values(2,'江老师');create table student(id int(10) not null,user_name varchar(30) default null,tid int(10) default null,primary key (id),key fktid(tid),constraint fktid foreign key (tid) references teacher(id)
)engine=InnoDB default charset=utf8;insert into student(id,user_name,tid) values(1,"小明",1);
insert into student(id,user_name,tid) values(2,"小红",2);
insert into student(id,user_name,tid) values(3,"小张",1);
insert into student(id,user_name,tid) values(4,"小李",1);
insert into student(id,user_name,tid) values(5,"小王",2);
  1. 导入lombok
  2. 新建实体类
  3. 建立Mapper接口
  4. 建立Mapper.xml资源
  5. 在核心配置文件中绑定注册Mapper
  6. 测试查询成功

Association

联表查询

select s.id as sid,s.user_name as sname,t.id as tid,t.user_name as tname
from student as s,teacher as t
where s.tid=t.id

  1. 接口

    List<Student> getStudent2();
    
  2. 接口实现

    <!--BFS:联表查询,处理结果-->
    <select id="getStudent2" resultMap="StudentTeacher2">select s.id as sid,s.user_name as sname,t.id as tid,t.user_name as tnamefrom student as s,teacher as twhere s.tid=t.id
    </select><resultMap id="StudentTeacher2" type="student"><result property="id" column="sid"/><result property="user_name" column="sname"/><association property="teacher" javaType="teacher"><result property="id" column="tid"/><result property="user_name" column="tname"/></association>
    </resultMap>
    
  3. 测试

嵌套查询
select *
from student as s
where s.tid
in (select t.id from teacher as t);

  1. 定义接口

    //查询学生对应的老师信息
    List<Student> getStudent();
    
  2. 实现接口

    <!--思路:DFS 查询嵌套,1. 查询所有学生信息2. 根据查出来学生的tid,查找对应的teacher
    -->
    <select id="getStudent" resultMap="StudentTeacher">select *from mybatis.student;
    </select><resultMap id="StudentTeacher" type="student"><!--简单属性用 <result property="" column=""/>映射即可--><!--复杂属性多对*————关联association一对*————集合collection--><association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
    </resultMap><select id="getTeacher" resultType="teacher">select *from mybatis.teacher where id=#{tid};
    </select>
    

Collection

@Data
public class Student {private Integer id;private String user_name;private Integer tid;
}@Data
public class Teacher {private Integer id;private String user_name;//一个老师拥有多个学生private List<Student> students;
}

实现根据teacher.id查找该老师对应的所有学生

联表查询
select t.id tid,t.user_name tname, s.id sid,s.user_name sname
from teacher t,student s
where t.id=s.tid and t.id=1;

  1. 定义接口

    //获取某个老师下所有的学生信息
    Teacher getTeacherById(@Param("tid") Integer id);
    
  2. 实现接口

    <select id="getTeacherById" resultMap="StudentTeacher">select t.id tid,t.user_name tname, s.id sid,s.user_name snamefrom teacher t,student swhere t.id=s.tid and t.id=#{tid};
    </select>
    <resultMap id="StudentTeacher" type="Teacher"><result property="id" column="tid"/><result property="user_name" column="tname"/><!-- 集合中的泛型用ofType指定 --><collection property="students" ofType="student"><result property="id" column="sid"/><result property="user_name" column="sname"/><result property="tid" column="tid"/></collection>
    </resultMap>
    
  3. 测试

嵌套查询
select tid,(select user_name from teacher where id=1) tname,id sid,user_name sname
from student s
where tid=1;

  1. 定义接口

    Teacher getTeacherById2(@Param("tid") Integer id);
    
  2. 实现接口

    <select id="getTeacherById2" resultMap="StudentTeacher2">select *from mybatis.teacher where id=#{tid}
    </select>
    <resultMap id="StudentTeacher2" type="teacher"><collection property="students" column="id" javaType="ArrayList" ofType="student" select="GetStudentByTid" />
    </resultMap>
    <select id="GetStudentByTid" resultType="student">select *from mybatis.studentwhere tid=#{tid};
    </select>
    
  3. 测试

动态sql

根据不同的条件生成不同的sql语句

搭建环境

create table blog(id varchar(50) not null comment '博客id',title varchar(100) not null comment '博客标题',author varchar(30) not null comment '博客作者',create_time datetime not null comment '创建时间',views int(30) not null comment '浏览量'
)engine=InnoDB default charset=utf8;
@Data
public class Blog {private String id;private String title;private String author;private Date createTime;private Integer views;
}
@SuppressWarnings("all")//抑制所有警告
public class TestBlog {@Testpublic void test(){SqlSession sqlSession = MyBatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Blog blog = new Blog();blog.setId(IDUtil.getId());blog.setAuthor("kuang");blog.setTitle("MyBatis如此简单!");blog.setCreateTime(new Date());blog.setViews(9999);mapper.insert(blog);blog.setId(IDUtil.getId());blog.setTitle("Java如此简单!");blog.setViews(9999);mapper.insert(blog);blog.setId(IDUtil.getId());blog.setTitle("Spring如此简单!");mapper.insert(blog);blog.setId(IDUtil.getId());blog.setTitle("微服务如此简单!");mapper.insert(blog);sqlSession.close();}
}

查询

IF

  1. 接口

    //查询blog信息List<Blog> queryBlogIF(Map map);
    
  2. 接口实现

    <select id="queryBlogIF" resultType="blog" parameterType="map">select *from mybatis.blog where 1=1<if test="title!= null">and titie=#{title}</if><if test="author!= null">and author = #{author}</if>
    </select>
    
  3. 测试


where优化
<select id="queryBlogIF" resultType="blog" parameterType="map">select *from mybatis.blog<where><if test="title!= null">title=#{title}</if><if test="author!= null">and author = #{author}</if></where>
</select>
  • The where element knows to only insert “WHERE” if there is any content returned by the containing tags. (满足条件插入)
  • Furthermore, if that content begins with “AND” or “OR”, it knows to strip it off.(保证第一个 where前没有逻辑判断)
choose-when-otherwise&where

switch-case-default | if-else if - else

  1. 定义接口

    List<Blog> queryBlogIF1(Map map);
    
  2. 实现接口

    <select id="queryBlogIF1" parameterType="map" resultType="blog">select *from mybatis.blog<where><choose><when test="id!=null">id=#{id}</when><when test="title != null">title=#{title}</when><when test="author != null">author=#{author}</when><otherwise>views>1000</otherwise></choose></where>
    </select>
    
  3. 测试

更新

set
  • The set element can be used to dynamically include columns to update, and leave out others.(选目标字段,删除无关字符)

    • the set element will dynamically prepend the SET keyword,(前置)
    • and also eliminate any extraneous commas that might trail the value assignments after the conditions are applied.(删逗号)
  1. 定义接口

    //更新信息
    int updateBlog(Map map);
    
  2. 实现接口

    <update id="updateBlog" parameterType="map">update mybatis.blog<set><if test="title!=null">title=#{title},</if><if test="author!=null">author=#{author},</if><if test="views!=null">views=#{views},</if>create_time =#{createTime}</set>where id=#{id}
    </update>
    
  3. 测试

trim替换

前缀后缀都是 prefix,XXOverrides决定替换的位置

<select id="queryBlogIFByTrim" resultType="blog" parameterType="map">select *from mybatis.blog<trim prefix="where" prefixOverrides="and |or "><if test="title!= null">title=#{title}</if><if test="author!= null">and author = #{author}</if></trim>
</select>
  • The prefixOverrides attribute takes a pipe delimited list of text to override, where whitespace is relevant.前缀Overrides 属性采用管道分隔文本列表来重写,其中空白是相关的。(最好写上,替换后可能会出问题)

    • The result is the removal of anything specified in the prefixOverrides attribute
    • and the insertion of anything in the prefix attribute
<trim prefix="SET" suffixOverrides=",">...
</trim>

sql片段

公共部分抽取出来,方便复用

  • <sql id=""></sql> 抽取
  • <include refid="" /> 引用
<sql id="if-title-author"><if test="title!= null">title=#{title}</if><if test="author!= null">and author = #{author}</if>
</sql><select id="queryBlogIFByTrim" resultType="blog" parameterType="map">select *from mybatis.blog<trim prefix="where" prefixOverrides="and |or "><include refid="if-title-author" /></trim>
</select>
  • 基于单表查询
  • 不要存在 <where> 标签

foreach

sql in 的动态范围查询

select *from user where 1=1 and (id=1 or id=2 or id=3);<foreach item="item" collection="ids" open="(" separator=" or " close=")">#{item}
</foreach>
  • open:开始符
  • separator:分隔符
  • close:结束符
  • item:项
  • colloetion:遍历集合
  1. 定义接口

    List<Blog> queryBlogIn(Map map);
    
  2. 实现接口

    <select id="queryBlogIn" parameterType="map" resultType="blog">select *from mybatis.blog<where><foreach collection="ids" item="id" open="(" separator="or" close=")">id=#{id}</foreach></where>
    </select>
    
  3. 测试

分页

limit实现分页

sql语句
select *from [table_name] limit [offset],[limit];# [offset]缺省,默认从0开始,到[end]
select *from [table_name] limit [end];
MyBatis方式
  1. 接口

    //分页查询用户信息
    List<User> getUserWithLimit(Map<String,Integer> map);
    
  2. 接口配置

    <select id="getUserWithLimit" resultMap="UserMap" resultType="user" parameterType="map">select *from mybatis.user limit #{offset},#{limit};
    </select>
    
  3. 测试

    @Test
    public void testGetUserWithLimit(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Integer> map = new HashMap<String, Integer>();map.put("offset",1);map.put("limit",2);List<User> userList = mapper.getUserWithLimit(map);for (User user : userList) {System.out.println(user);}sqlSession.close();
    }
    

RowBounds实现分页[不建议使用]

不在sql进行分页,通过sqlSession对象实现分页——RowBounds

  1. 接口

    List<User> getUserWithLimit2();
    
  2. 配置Mapper

    <select id="getUserWithLimit2" resultMap="UserMap" resultType="user">select *from mybatis.user;
    </select>
    
  3. 测试

    @Test
    public void testGetUserWithLimit2(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);RowBounds rowbounds = new RowBounds(1,2);List<User> userList = sqlSession.selectList("com.kuang.mapper.UserMapper.getUserWithLimit2",null,rowbounds);for (User user : userList) {System.out.println(user);}sqlSession.close();
    }
    

插件——pageHelper

缓存

简介

问题:连接数据库消耗资源

解决:一次查询,保存到高速存储——> 内存

缓存:

  • 放在内存中的临时数据
  • 经常查询且不常改变 的数据存放在缓存,直接从服务器内存取比从服务器磁盘IO速度快,提高查询效率,解决高并发系统的性能问题

使用缓存,减少与数据库交互次数,减少系统开销,提高系统效率

#mermaid-svg-5j8hTzdinpGfqAUy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .error-icon{fill:#552222;}#mermaid-svg-5j8hTzdinpGfqAUy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5j8hTzdinpGfqAUy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5j8hTzdinpGfqAUy .marker.cross{stroke:#333333;}#mermaid-svg-5j8hTzdinpGfqAUy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5j8hTzdinpGfqAUy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster-label text{fill:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster-label span{color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .label text,#mermaid-svg-5j8hTzdinpGfqAUy span{fill:#333;color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .node rect,#mermaid-svg-5j8hTzdinpGfqAUy .node circle,#mermaid-svg-5j8hTzdinpGfqAUy .node ellipse,#mermaid-svg-5j8hTzdinpGfqAUy .node polygon,#mermaid-svg-5j8hTzdinpGfqAUy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5j8hTzdinpGfqAUy .node .label{text-align:center;}#mermaid-svg-5j8hTzdinpGfqAUy .node.clickable{cursor:pointer;}#mermaid-svg-5j8hTzdinpGfqAUy .arrowheadPath{fill:#333333;}#mermaid-svg-5j8hTzdinpGfqAUy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5j8hTzdinpGfqAUy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5j8hTzdinpGfqAUy .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-5j8hTzdinpGfqAUy .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster text{fill:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster span{color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5j8hTzdinpGfqAUy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

缓存merCached缓存服务器
读写分离,主从复制

MyBatis缓存

系统默认定义两级缓存:一级缓存和二级缓存

  • 一级缓存:SqlSession级,本地缓存
  • 二级缓存:手动开启和配置,namespace级缓存
  • MyBatis自定义缓存接口Cache,通过实现接口自定义二级缓存
一级缓存——Map

一级缓存默认开启,在一次SESSION期间有效

  1. 开启日志

  2. 测试一个Session中查询两次相同记录

    @Test
    public void test(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user1 = mapper.getUserById(1);System.out.println(user1);System.out.println("====================");User user2 = mapper.getUserById(1);System.out.println(user2);System.out.println(user1==user2);sqlSession.close();
    }
    
  3. 查看日志输出

    两次查找一次查表

    两次结果引用同一对象

缓存失效
  • R不同的东西

  • CUD必定刷新缓存

  • 不同的Mapper

  • 手动清理缓存

二级缓存

工作机制:

一个Session期间的数据会被放到一级缓存,当Session关闭或提交,对应的一级缓存中的数据被保存到二级缓存中

  • 新的Session查询信息,从二级缓存中获取内容
  • 不同的mapper查出的数据会放到自己对应的缓存中
  1. mybatis-config.xml 开启二级缓存

    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
    
  2. 配置mapper.xml

    <!--在当前mapper中使用二级缓存-->
    <cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>
    
    • mapper.xml中的所有 select 语句的结果将会被缓存。
    • mapper.xml中的所有 insert、update 和 delete 语句会刷新缓存。
    • eviction:替换策略
      • LRU:默认
      • FIFO
    • flushInterval:刷新间隔
      • 以毫秒为单位
      • 不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新
    • size:引用数目
      • 默认值是 1024
    • readOnly:只读
      • 只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改
      • 可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false
  3. 测试

  4. 问题

    • 将实体类序列化,否则保错
    java.io.NotSerializableException: com.kuang.pojo.User
    
    package com.kuang.pojo;import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;import java.io.Serializable;@Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable {private Integer id;private String user_name;private String pwd;
    }
    
缓存原理

查找顺序:

  1. 二级缓存
  2. 一级缓存
  3. 数据库
@Test
public void test(){SqlSession sqlSession1 = MyBatisUtils.getSqlSession();User user1 = sqlSession1.getMapper(UserMapper.class).getUserById(1);System.out.println(user1);sqlSession1.close();SqlSession sqlSession2 = MyBatisUtils.getSqlSession();User user2 = sqlSession2.getMapper(UserMapper.class).getUserById(1);System.out.println(user2);sqlSession2.close();System.out.println(user1==user2);SqlSession sqlSession3 = MyBatisUtils.getSqlSession();User user3 = sqlSession3.getMapper(UserMapper.class).getUserById(2);System.out.println(user3);sqlSession3.close();
}

  • 由Cache Hit Ratio的计算,可知cache机制是先查二级缓存,再数据库

自定义缓存——Ehcache

开源Java分布式缓存

<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.1.0</version>
</dependency>
<!--mapper.xml-->
<cache type="com.domain.something.MyCustomCache"/>
public interface Cache {String getId();int getSize();void putObject(Object key, Object value);Object getObject(Object key);boolean hasKey(Object key);Object removeObject(Object key);void clear();
}

注解开发

面向接口编程

目的:解耦

接口的理解

  • 定义实现 分离
  • 接口反映系统设计人员对系统的抽象理解
  • 接口分类:
    • 一个个体的抽象——抽象体(abstract class)
    • 一个个体的某一方面的抽象——抽象面(Interface)
  • 接口设计更多体现对系统整体的架构

使用注解开发

本质:反射机制

底层:动态代理

Java Annotations are both limited and messier for more complicated statements.

  1. 注解在接口上实现

    public interface UserMapper {@Select("select *from user")List<User> getUsers();
    }
    
  2. 绑定接口

    <!--mybatis-config.xml-->
    <!-- 绑定接口 -->
    <mappers><mapper class="com.kuang.mapper.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void test(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> users = mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close();
    }
    

参数

当有多个参数,基本数据类型或String的参数前加注解 @param关联参数

引用类型不需要加

sql中使用的是@Param()中设定的属性名


#{} 与 ${} 的区别
  • ${}是字符串替换,,Mybatis 在处理${}时,就是把他替换成变量的值
  • #{}是预编译处理,会将 #{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;
  • 使用#{}可以有效的防止 SQL 注入,提高系统安全性

自动提交事务

public class MyBatisUtils{public static SqlSession getSqlSession(){return sqlSessionFactory.openSession(true);}
}

CRUD

Create
//UserMapper.java
public interface UserMapper{@Insert("insert into user(id,user_name,pwd) values(#{id},#{user_name},#{pwd})")
int insertUser(User user);
}

Update
//UserMapper.java
public interface UserMapper{@Update("update user set user_name=#{user_name},pwd=#{pwd} where id=#{id}")int updateUser(User user);
}

POJO方法的简化——Lombok

  1. IDEA中安装插件

  2. 项目中导入依赖

    <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope>
    </dependency>
    
  3. 使用注解简化

    @Getter and @Setter
    @ToString
    @EqualsAndHashCode
    @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
    @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
    @Data
    
    • @Data,@AllArgsConstructor,@NoArgsConstructor

MybatisPlus

简介

在MyBatis基础上,只做增强不做改变,为简化开发、提高效率而生

  • 无侵入
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • CRUD:内置通用 Mapper、通用 Service
  • 支持主键自动生成
  • 支持 XML 热加载 :Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
  • 支持 ActiveRecord 模式
  • 支持自定义全局通用操作:支持全局通用方法注入
  • 内置代码生成器 :采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎
  • 内置分页插件 、性能分析插件
  • 全局拦截(提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作)
  • 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击

MtbatisPlus架构

通过简单语句,生成SQL语句,交给MyBatis执行

使用

1. 建库建表

创建数据库 haoke

use haoke;CREATE TABLE `user` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`name` varchar(30) DEFAULT NULL COMMENT '姓名',`age` int(11) DEFAULT NULL COMMENT '年龄',`email` varchar(50) DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- 插入数据
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('1', 'Jone', '18','test1@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('2', 'Jack', '20','test2@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('3', 'Tom', '28','test3@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('4', 'Sandy', '21','test4@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('5', 'Billie', '24','test5@baomidou.com');


2. 创建工程及导入依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.3</version>
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mybatis-plus的springboot支持--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency>
</dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>

3. 编写application.properties文件

spring.application.name = mybatis-plus
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://8.140.130.91:3306/haoke?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root

4. 创建User对象

package com.mybatisplus.pojo;public class User {private Long id;private String name;private Integer age;private String email;public User() {}public User(Long id, String name, Integer age, String email) {this.id = id;this.name = name;this.age = age;this.email = email;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}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;}
}

5. 编写UserMapper

package com.mybatisplus.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;public interface UserMapper extends BaseMapper<User> {}

6. 编写SpringBoot启动类

package com.mybatisplus;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.mybatisplus.mapper") //设置mapper接口的扫描包
@SpringBootApplication
public class Myapplication {public static void main(String[] args) {SpringApplication.run(Myapplication.class,args);}
}

7. 编写SpringBoot启动类

package com.mybatisplus;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.mybatisplus.mapper") //设置mapper接口的扫描包
@SpringBootApplication
public class Myapplication {public static void main(String[] args) {SpringApplication.run(Myapplication.class,args);}
}

8. 编写单元测试用例

package com.mybatisplus;import com.mybatisplus.mapper.UserMapper;
import com.mybatisplus.pojo.User;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void test(){System.out.println("-------selectAll method test-------");List<User> users = userMapper.selectList(null);for (User user : users) {System.out.println(user);}}
}

通用Mapper

在MybatisPlus中,BaseMapper中定义了一些常用的CRUD方法,当我们自定义的Mapper接口继承BaseMapper后即可拥有了这些方法 【这些方法仅适合单表操作】

/*** Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能*/
public interface BaseMapper<T> extends Mapper<T> {/*** 插入一条记录** @param entity 实体对象*/int insert(T entity);/*** 根据 ID 删除** @param id 主键ID*/int deleteById(Serializable id);/*** 根据 columnMap 条件,删除记录** @param columnMap 表字段 map 对象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,删除记录** @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 删除(根据ID 批量删除)** @param idList 主键ID列表(不能为 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 根据 ID 修改** @param entity 实体对象*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根据 whereEntity 条件,更新记录** @param entity        实体对象 (set 条件值,可以为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);/*** 根据 ID 查询** @param id 主键ID*/T selectById(Serializable id);/*** 查询(根据ID 批量查询)** @param idList 主键ID列表(不能为 null 以及 empty)*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 查询(根据 columnMap 条件)** @param columnMap 表字段 map 对象*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,查询一条记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询总记录数** @param queryWrapper 实体对象封装操作类(可以为 null)*/Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录* <p>注意: 只返回第一个字段的值</p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件,查询全部记录(并翻页)** @param page         分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null)*/<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录(并翻页)** @param page         分页查询条件* @param queryWrapper 实体对象封装操作类*/<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}

通过id查询——selectById

@Test
public void testSelectById(){System.out.println("通过Id查询");User user = userMapper.selectById(3L);//数据类型为Long,id为3System.out.println(user);
}

模糊查询——like

条件查询

https://mp.baomidou.com/guide/wrapper.html#abstractwrapper

插入数据

@Test
public void testSave(){User user = new User();user.setAge(25);user.setEmail("zhangsan@qq.com");user.setName("zhangsan");int count = userMapper.insert(user);System.out.println("新增数据成功! count=>"+count);
}
id自增问题


所以自增问题出现在java参数传递中

public class User {@TableId(value = "ID", type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;
}


删除数据

修改数据

根据id修改,只修改指定的字段


分页查询

/*** 分页插件*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false// paginationInterceptor.setOverflow(false);// 设置最大单页限制数量,默认 500 条,-1 不受限制// paginationInterceptor.setLimit(500);PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();paginationInnerInterceptor.setDbType(DbType.MYSQL);interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;
}

配置

使用MyBatis原生配置文件

# 指定全局配置文件
mybatis-plus.config-location = classpath:mybatis-config.xml
# 指定mapper.xml文件
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml

若指定配置文件,无需配置环境,只需要

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- configuration的核心配置 -->
<configuration><!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册 -->
</configuration>

https://mp.baomidou.com/guide/config.html#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE

Lombok

  • @Data:注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
  • @Setter:注解在属性上;为属性提供 setting 方法
  • @Getter:注解在属性上;为属性提供 getting 方法
  • @Slf4j:注解在类上;为类提供一个 属性名为log 的 slf4j日志对象
  • @NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
  • @AllArgsConstructor :注解在类上;为类提供一个全参的构造方法
  • @Builder :使用Builder模式构建对象


【开发】后端框架——Mybatis相关推荐

  1. java开发后端框架_java开发后端框架

    1 java开发后端框架 java从推出到现在技术不断发展,语言也优化的越来越好,对于java工程师来说技术的不断发展,他们需要不断学习java进阶,而对于新手来说就能从基础到核心.那么新手该怎么学习 ...

  2. 【基于Springboot、Mybatis后端框架开发——招生管理网站(系统)】附源码

    招生管理网站(系统) 招生管理系统项目简介 内容及步骤 1. 招生管理系统的总体设计与实现 1.1需求分析 1.2系统功能设计 1.4系统功能测试(部分) 1.5代码下载 招生管理系统项目简介 搭建J ...

  3. 一文搞定7大流行后端框架:Spring、Netty、MyBatis、Hibernate、Dubbo...

    框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法:另一种定义认为,框架是可被应用开发者定制的应用骨架.前者是从应用方面而后者是从目的方面给出的定义. 可 ...

  4. mysql后台框架_后端服务开发 - 认识后端框架

    后端的基本概念 在软件架构和程序设计领域,前端是软件系统中直接和用户交互的部分,而后端控制着软件的输出. 前端控制ajax等技术向后端进行网络请求:后端收到请求后对数据库进行操作,返回给前端JSON数 ...

  5. 后端开发知识框架汇总

    后端开发知识框架汇总 Spring框架 Spring/Springboot/SpringMVC Spring ​ 其是一个引擎,众多衍生产品例如boot.security.jpa等等:但他们的基础都是 ...

  6. 跟我学Springboot开发后端管理系统6:缓存框架Caffeine

    Caffeine是一个基于Java8的高性能缓存框架,号称趋于完美.Caffeine受启发于Guava Cache的API,使用API和Guava是一致的.它借鉴了Guava Cache和Concur ...

  7. Java软件开发:自定义MyBatis持久层框架

    自定义MyBatis持久层框架 1 框架概述 1.1 什么是框架 1.2 框架要解决的问题 1.3 软件开发的分层的重要性 2 MyBatis框架 3 JDBC编程 3.1 JDBC程序的回顾 3.2 ...

  8. python后端框架flask_Vue+Flask轻量级前端、后端框架,如何完美同步开发

    导言我们的Vue2.0应用:简读-微信公众号RSS,即将进入后端开发. Vue+Flask作为轻量级前端.后端框架,非常适合组合起来快速开发.一个是js,一个是Python. Bonus: 可以完美实 ...

  9. python web后端和vue哪个难_全栈开发用纯后端模板与Vue+后端框架组合哪个好?

    全栈开发没有明确的定义,但应该指的就是前端+后端+数据库.所以只用纯后端框架,不算全站开发.至少在Angularjs出现以前,我没听说过全站开发这个词. 你问题描述中的感觉是对的,这就是前后端分离的好 ...

最新文章

  1. 【Java挠头】Java异常、捕获、处理、throw、throws等绝妙剖析
  2. Python之一行代码
  3. 【Python】Effective Python 读书笔记
  4. [python爬虫] Selenium常见元素定位方法和操作的学习介绍(转载)
  5. Boost库之function的使用
  6. 蓝桥杯第六届省赛JAVA真题----生命之树
  7. 网站被DDOS***怎么防御,推荐网站CDN防御
  8. Python十行代码带你穿越管世界
  9. 疫情期间我们与你同在:关爱障碍群体刚需,坚持做无障碍的倡议书
  10. [转载] numpy.reshape用法(自用)
  11. SVN安装-配置-使用及myeclipse的插件安装(图文)
  12. 安装HDFS过程中Browse Directory报错
  13. 全网首发:JDK绘制文字:四、绘制文字的具体函数分析
  14. 苯酚吸附专用树脂 污水中的苯酚怎么去除
  15. jquery实现类似以前凡客诚品右侧图文切换结合效果
  16. 【JPress】jpress-core架构
  17. 【金猿技术展】同盾科技知识联邦技术——3.0人工智能的坚强基石
  18. 科技巨头纷纷发力AI,智能硬件已来临,变现还会远吗?
  19. 如何在Windows 10 IoT Core中添加其他语言的支持,如中文
  20. 软件测试工程师项目业绩怎么写,软件工程师的“项目业绩”如何才能脱颖而出?...

热门文章

  1. Java 扫描微信公众号二维码,关注并自动登录网站
  2. BAPI_PRODORDCONF_GET_TT_PROP 生产订单完工确认
  3. C#基础+面向对象学习
  4. Vue运行项目常用命令
  5. 免费开源好用还佛系的国产PDF软件:pdf补丁丁下载 | 含pdf补丁丁使用手册
  6. fedroa设置启动快捷键
  7. A Benchmark and Simulator for UAV Tracking(论文翻译)
  8. 华为HCIA鲲鹏生态体系介绍
  9. UVA10815 安迪的第一个字典 Andy‘s First Dictionary
  10. 字体的分类图示——对网页设计很有益的图