Mybatis详细教程 (万字详解)

Mybatis 3.5.14

来自于B站‘天气预报’,一名宝藏up,跟着他可以培养起独立解决编程问题的能力!!

01.简介

image-20240921222309384

1.1 官网

官方中文网: MyBatis中文网

  • 中文网参考手册

image-20240921222746402

1.2 概念

MyBatis 是一款优秀的持久层框架,支持自定义 SQL, 存储过程, 高级映射

  • 官方解释

image-20240921223207882

必要前置技术
  • Mysql [本课件以 MySQL 为例]
  • JDBC [Java Database Connection] API
通俗解释
  • Mybatis 框架 是对原生 JDBC 技术的封装 和 增强

  • Mybatis 框架 核心行为是将 JDBC ResultSet 结果集映射到类的过程 如

  • 映射关系示意

image-20240921223545754

02.入门

入门示例会引导大家熟悉 MYBATIS 环境 | 配置 | DAO 接口抽象配置 | 运行流程

2.1环境

Mybatis 当前最新版为 3.5.14 [此处创建项目 maven::java mybatis]

  • mybatis
<dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.14</version></dependency>
</dependencies>
  • pom.xml [mybatis-3.5.14.jar\META-INF\maven\org.mybatis\mybatis\pom.xml ]
<dependency><groupId>ognl</groupId><artifactId>ognl</artifactId><version>3.3.4</version><scope>compile</scope><optional>true</optional>
</dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.2-GA</version><scope>compile</scope><optional>true</optional>
</dependency><dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
<optional>true</optional>
</dependency><!--日志系列-->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.9</version><optional>true</optional>
</dependency><dependency><groupId>ch.qos.reload4j</groupId><artifactId>reload4j</artifactId><version>1.2.25</version><optional>true</optional>
</dependency><dependency><groupId>org.apache.logging.Log4j</groupId><artifactId>log4j-api</artifactId><version>${log4j.version}</version><optional>true</optional>
</dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version><optional>true</optional>
</dependency>
  • maven repository

image-20240922000431699

  • mysql
<!-- SQL: SELECT VERSION(): 查看自己的数据库版本--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>
  • pom.xml [src/main/java 非java文件编译打包配置]
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.*</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource></resources>
</build>    
  • pom.xml [完整]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>test</groupId>  <!-- 此处可更改 可见我博客主页写的Maven博客--><artifactId>untitled</artifactId> <!-- 此处可更改 --><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.14</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>ognl</groupId><artifactId>ognl</artifactId><version>3.3.4</version><scope>compile</scope><optional>true</optional></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.2-GA</version><scope>compile</scope><optional>true</optional></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version><optional>true</optional></dependency><!--日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.9</version><optional>true</optional></dependency><dependency><groupId>ch.qos.reload4j</groupId><artifactId>reload4j</artifactId><version>true</version><optional>true</optional></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>${log4j.version}</version><optional>true</optional></dependency><dependency><dependency>commons-logging</dependency><artifactId>commons-logging</artifactId><version>1.2</version><optioanl>true</optioanl></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.*</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource></resources></build></project>

2.2 数据库

  • SQL
CREATE DATABASE mybatis;USE mybatus;CREATE TABLE user(user_id 			INT PRIMARY KEY AUTO_INCREMENT,user_username       VARCHAR(20)
)

2.3 实体类

package org.example.mybatis.entity;import lombok.Data;@Data
public class User {private Integer id;private String username;
}
// 写法二
// public record User(Integer id, String username) {
//
// }

2.4 核心配置文件

  • mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="dev"><environment id="dev"><transactionManager type="POOLED"/><dataSource type="JDBC"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><!-- <property name="url" value="jdbc:mysql://127.0.0.1:3306(默认时可以省略掉)/mybatis?serverTimezone=Asia/Shanghai"/>--><property name="url" value="jdbc:mysql:///mybatis?serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments></configuration>

2.5 Mapper 抽象

Mapper 接口是 DAO (Data Access Object) 操作,对数据库表的操作抽象

  • UserMapper.java
package org.exmaple.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.exmaple.mybatis.entity.User;@Mapper
public interface UserMapper {User selectById(int id);int deleteById(int id); // mysql返回值为一个状态值 可以使用 boolean 类型
}

2.6 Mapper 配置

Mapper 接口需通过配置 [Java | Xml] 方式告知 Mybatis 执行逻辑行为

  • org.example.mybatis.mapper.UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="org.example.mybatis.mapper.UserMapper"><select id="selectById"parameterType="int"resultType="org.example.mybatis.entity.User">SELECTuser_id id,user_username usernameFORMuserWHEREuser_id = #{id}</select><delete id="deleteById" parameterType="int"> <!-- 无resultType参数可选 -->DELETE FROM user from user_id = #{id}</delete></mapper>
    

2.7 Mapper扫描

完成 Mapper 接口及其配置后 还需告知 Mybatis Mapper 接口位置

  • src/main/resources/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="dev"><environment id="dev"><transactionManager type="POOLED"/><dataSource type="JDBC"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql:///Mybatis?serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><mappers><package name="org.example.mybatis.mapper"></package></mappers></configuration>

2.8 API 入口

Mybatis 提供运行的 入口 Api, 通过 Api 引导框架读取配置, 解析 Mapper 后才能正确运行

  • Application.java
package org.example.mybatis.api;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.mybatis.mapper.UserMapper;
import org.example.mybatis.entity.User;
import java.io.IOException;
import java.io.InputStream;public class Application {public static void main(String[] args) throws IOException {String resource = "mybatis-config.xml";InputStream config = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(config);SqlSession sqlSession = sqlSessionFactory.openSession(true);UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.selectById(1);System.out.println(user);int row = mapper.deleteById(1);System.out.println("row=" + row);//  sqlSession.commit(); 开启autoCommit 或者手动提交sqlSession.close();}
}

2.9 日志

Mybatis 通过使用内置日志工厂提供日志工能

  • 官网日志机制

在这里插入图片描述

01.说明
  • 内置日志工厂将会把日志工作委托给下面的实现之一

  • SLF4J [日志抽象]

  • Apache Commons Logging [日志抽象]

  • Log4j 2 [日志实现]

  • Log4j (3.5.9起废弃)

  • JDK logging [日志实现 JDK自带 较少用]

  • 机制

	1. MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具2. MyBatis 会使用第一个查找得到的工具 (按上文列举的顺序查找) 如果一个都未找到,日志功能就会被禁用。
  • mybatis-config.xml [指定配置]
<configuration><serrings>...<setting name="logImpl" value="LOG4J"/> <!--可参考上文,上文已经配置完毕 -->...</serrings>
</configuration>
  • logImpl 可选的值有:
  • SLF4J, LOG4J, LOG4J2, JDK_LOGGING, COMMONS_LOGGING, STDOUT_LOGGING, NO_LOGGING
02.SLF4J

SLF4J 是一款日志门面抽象框架,本身并未实现,需使用具体的日志框架

  1. log4j 是一款实现的日志框架,对 SLF4J 有桥接实现
  2. log4j2 是log4j 2.y.z 版本, 同样对 SLF4J 有桥接实现
  3. logback 是 直接针对 SLF$J 实现的日志框架

官网: SLF4J Manual

  • 官方参考手册

image-20240922120637791

版本注意事项: https://github.com/gos-ch/slf4j

  • Github

image-20240922121133434

03.Logback

Logback 针对 SLF4J 的日志实现 核心坐标 [logback-core | logback-classsic]

  • dependency

image-20240922121805967

  • pom.xml
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.4.14</version><scope>test</scope>
</dependency>
  • API
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class HelloWorld {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(HelloWorld.class);logger.info("Hello World");}
}
  • logback.xml [不配置该文件时的内置日志格式]
<?xml version="1.0" encoding="UTF-8" ?>
<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender" ><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}.%M %L - %msg%n<!-- %d日期 yyyy-MM-dd 年月日,HH:mm::ss.SSS时,分,毫秒,微秒 %t线程 %-5 左对齐5个字符 level级别%logger{36}长度为36的日志记录 .%M方法 %L行 - %msg具体信息 %n换行--></pattern></encoder></appender>
</configuration>

2.10 运行逻辑流程

了解 Mybatis 大致运行流程可以更清晰在整体上,对其有良好的认识

01.动态代理

动态代理实现主要有 JDK[仅支持接口 类型] | CGLIB [支持类和接口的 类型]

  • 这里仅需知晓

    • 生成的代理对象确实属于代理的接口类型,以及代理对象调用接口方法会执行到特定机制中
  • Mybatis 利用 动态代理 主要完成 mapper 代理 和 SQL 解析处理

  • ProxyUsage.java

package org.example.mybatis.api;import org.example.mybatis.mapper.UserMapper;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JdkProxyUsage {public static void main(String[] args) {ClassLoader loader = UserMapper.class.getClassLoader();Class<?>[] classes = { UserMapper.class };InvocationHandler handler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("method.getName() = " + method.getName());System.out.println("args[0] = " + args[0]);System.out.println("...");return null;}};UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(loader, classes, handler);userMapper.deleteById(1000);}
}
02.Javassist

Javassist是 Apache 提供的动态字节码技术, 可动态生成类及类中成员

  • Mybatis 利用 Javassist 主要完成 对象成员对应列 延迟装配功能

  • JavassistUsage.java

package org.example.mybatis.api;import javassist.*;public class JavassistUsage {public static void main(String[] args) throws Exception {ClassPool classPool = ClassPool.getDefault();CtClass ctClass = classPool.makeClass("x.y.z.People");CtField ctField = CtField.make("private boolean alive;", ctClass);ctClass.addField(ctField);String methodBody = "public void message() { System.out.println(\"动态生成的方法\"); }";CtMethod ctMethod = CtMethod.make(methodBody, ctClass);ctClass.addMethod(ctMethod);ctClass.writeFile();}
}
03.逻辑流程
  1. 读取并,解析核心配置文件 mybatis-config.xml
  2. 装配数据库连接以及配置事务管理
  3. 读取 mapper 接口及 xml 文件所在位置并完成其对应的逻辑关联
  4. mapper 代理对象调用 mapper 接口方法时 mybatis 利用动态代理找到对应的标签 [xpath]
  5. mybatis 找到对应标签 解析 SQL 表达式及动态代理完成参数的适配
  6. mybatis 使用 JDBC 执行 SQL 操作, 拿到 ResultSet
  7. 通过配置告知 mybatis 列和对象属性的对应关系,让 mybatis 完整封装

03.全局配置

了解掌握 Mybatis 全局配置的 是将 Mybatis 熟练运用和解决问题的关键

  • Mybatis 全局配置都位于 mybatis-config.xml 中, 也可同理基于 Java 配置

image-20240923093855766

3.1 属性

Mybatis 允许读取外部 properties 文件,并读取为上下文 通过 ${key} 获取值

  • src/main/resources/db.properties
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql:///Mybatis?serverTimezone=Asia/Shanghai <!-- 博主的数据库名为Mybatis-->
mysql.username=root
mysql.password=123456
  • mybatis-config-xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><properties resource="db.properties"><!-- <property name="" value=""/> --></properties><environments default="dev"><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${mysql.driver}"/><property name="url" value="${mysql.url}"/><property name="username" value="${mysql.username}"/><property name="password" value="${mysql.password}"/></dataSource></environment></environments><mappers><package name="org.example.mybatis.mapper"/></mappers>
</configuration>

3.2 设置

Mybatis 预留全局 key 用于控制 Mybatis 整体运行行为

  • 当未配置内全局 key 时, Mybatis 将使用默认的内置初始值
  • 参考链接: 配置_MyBatis中文网

image-20240923102507889

  • mybatis-config.xml
<settings><setting name="cacheEnabled" value="true"/><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="true"/><setting name="multipleResultSetsEnabled" value="true"/><setting name="useColumnLabel" value="true"/><setting name="useGeneratedKeys" value="false"/><setting name="autoMappingBehavior" value="PARTIAL"/><setting name="autoMappingUnknownColumnBehavior" value="WARNING"/><setting name="defaultExecutorType" value="SIMPLE"/><setting name="defaultStatementTimeout" value="25"/><setting name="defaultFetchSize" value="100"/><setting name="safeRowBoundsEnabled" value="false"/><setting name="safeResultHandlerEnabled" value="true"/><setting name="mapUnderscoreToCamelCase" value="false"/><setting name="localCacheScope" value="SESSION"/><setting name="jdbcTypeForNull" value="OTHER"/><setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/><setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/><setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/><setting name="callSettersOnNulls" value="false"/><setting name="returnInstanceForEmptyRow" value="false"/><setting name="logPrefix" value="exampleLogPrefix_"/><setting name="logImpl" value="SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | ..."/><setting name="proxyFactory" value="CGLIB | JAVASSIST"/><setting name="vfsImpl" value="org.mybatis.example.YourselfVfsImpl"/><setting name="useActualParamName" value="true"/><setting name="configurationFactory" value="org.mybatis.example.ConfigurationFactory"/>
</settings>

3.3 类型别名

类型别名可为 Mapper 接口返回的 [自定义类型] 定义一个短名称别名以便使用

3.3.1 自定义类型
  • mybatis-config.xml 自定义指定类型别名名称
<typeAliases><typeAlias alias="Author" type="domain.blog.Author"/><typeAlias alias="Bolg" type="domain.blog.Blog" /><typeAlias alist="Comment" type="domain.blog.Comment" /><typeAlias alist="Post" type="domain.blog.Post" /><typeAlias alias="Section" type="domain.blog.Section" /><typeAlias alias="Tag" type="domain.blog.Tag" />
</typeAliases>
  • mybatis-config.xml 指定包统一定义别名,规则是类名首字母小写作为名称
<typeAliases><packaage name="org.example.project.entity"/>
</typeAliases>
  • Author.java (不太推荐 当注解逐渐变多的时候类的格式会逐渐混乱)
@Alias("author")
public class Author {...
}
3.3.2 内置类型别名

官方网址: 配置_MyBatis中文网

image-20240923111817308

3.4 类型处理器

Mybatis 内置类型处理器用于完成 列和 对象属性的数据类型的对应关系

  • 当内置的所有处理器都不能对应 列和属性的数据类型时, Mybatis 将抛出异常

  • 解决

    • 调整 列 或者 属性的数据类型 使用 Mybatis 能够处理 [推荐]
    • 自行实现类型处理器并注册到 Mybatis 框架中 [注册分为全局和局部]
    01.内置类型处理器

    参考链接: 配置_MyBatis中文网

  • 内置类型处理器

image-20240923112454379

  • 自定义数据类型

Mybatis 内置 BaseTypeHandler 抽象用于实现自定义数据类型对应处理

  • BaseTypeHandler<泛型> 泛型表示 Java 数据类型

  • @MappedJdbcTypes (value = 数据库类型)

  • ExampleTypeHandler.java

package org.example.mybatis.type;import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class ExampleTypeHandler extends BaseTypeHandler<String> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, parameter);}@Overridepublic String getNullableResult(ResultSet rs, String columnName) throws SQLException {return rs.getString(columnName);}@Overridepublic String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getString(columnIndex);}@Overridepublic String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return cs.getString(columnIndex);}
}
  • GenderTypeHandler.java
package org.example.mybatis.type;import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.example.mybatis.entity.Gender;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;@MappedJdbcTypes(JdbcType.INTEGER)
public class GenderTypeHandler extends BaseTypeHandler<Gender> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Gender gender, JdbcType jdbcType) throws SQLException {int sex = gender == Gender.MAN ? 0 : 1;ps.setInt(i, sex);}@Overridepublic Gender getNullableResult(ResultSet rs, String columnName) throws SQLException {int sex = rs.getInt(columnName);return sex == 0 ? Gender.MAN : Gender.WOMAN;}@Overridepublic Gender getNullableResult(ResultSet rs, int columnIndex) throws SQLException {int sex = rs.getInt(columnIndex);return sex == 0 ? Gender.MAN : Gender.WOMAN;}// 没有相关的调用方法@Overridepublic Gender getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return null;}
}
  • 全局注册
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><properties resource="db.properties"><!-- <property name="" value=""/> --></properties><settings><setting name="cacheEnabled" value="true"/></settings><typeAliases><!-- <typeAlias alias = "User" type="org.example.mybatis.entity.User" />--><package name="org.example.mybatis.entity"/></typeAliases><typeHandlers><typeHandler handler="org.example.mybatis.type.GenderTypeHandler"/></typeHandlers><environments default="dev"><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${mysql.driver}"/><property name="url" value="${mysql.url}"/><property name="username" value="${mysql.username}"/><property name="password" value="${mysql.password}"/></dataSource></environment></environments><mappers><package name="org.example.mybatis.mapper"/></mappers></configuration>

3.5 对象工厂(仅了解)

MyBatis 创建结果对象实例是 都会使用一个内置对象工厂实例来完成实例化工作

  • 置的对象工厂需要做的仅仅是实例化目标类, 要么通过默认无参构造方法,要么是有参构造

  • 如果像覆盖对象工厂的默认行为 可以通过创建自己的对象工厂来实现

  • ExampleObjectFactory.java (不推荐改,因为没有需求需要覆盖对象工厂,而且对技术要求极高)

public class ExampleObjectFactory extends DefaultObjectFactory {@Overridepublic <T> T create(Class<T> type) {return super.create(type);}@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {return super.create(type, constructorArgTypes, constructorArgs);}@Overridepublic void setProperties(Properties properties) {super.setProperties(properties);}@Overridepublic <T> boolean isCollection(Class<T> type) {return Collection.class.isAssignableFrom(type);}
}
  • mybatis-config.xml
<objectFactory type="org.mybatis.example.ExampleObjectFactory"><property name="someProperty" value="100" />
</objectFactory>               

3.6 插件

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用

  • Executor (update query flushStatements commit rollback getTransaction close isClosed)

  • ParameterHandler (getParameterObject setParameters)

  • ResultSetHandler (handleResultSets handleOutputParameters)

  • StatementHandler (perpare parameterize batch update query)

  • ExamplePlugin.java

@Intercepts ({@Signature (tyep= Executor.class,method = "update",args = {MappedStatement.class, Object.class})}
)public class ExamplePlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// implement pre processing if needObject returnObject = invocation.proceed();// implement post processing if needreturn returnObject;}private Properties properties = new Properties();@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}
  • mybatis-config.xml
<plugins><plugin interceptor="org.mybatis.example.ExamplePlugin"><property name="someProperty" value="100"/></plugin>
</plugins>

3.7 环境配置

MyBatis 可以配置成适应多种环境 如 开发,测试,生产环境 需不同的配置

01 机制
  • 记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境
  • 每个数据库对应的 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);SqlSessionGactory factory = new SqlSessionFactoryBuilder().build(reader, enviroment, properties);
  • mybatis-config.xml
<environments default="development"><enviroment 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></enviroment>
</environments>
02 事务管理器

Mybatis 关闭 MySQL 的事务自动提交,并推荐在关闭连接时,不再处理连接的事务自动提交

  • mybatis-config.xml
<transactionManager type="JDBC"><property name="skipSetAutoCommitOnClose" value="true" />
</transactionManager>

当 Mybatis + Spring 一起使用时 Mybatis 推荐使用 Spring 事务

  • 无论采用什么技术, 事务都应当放在业务层处理,持久层任何一个接口都是 单条 SQL操作

  • Demo

record UserService(UserMapper userMapper) {// 此处登录public void transferAccounts(int userId, int otherId, int amount) {userMapper.updateAmountById(userId, -amount); // 这是一条 SQLuserMapper.updateAmountById(otherId, +amount); // 这是一条 SQWL}
}

3.8 数据库厂商标识

MyBatis 可根据不同数据库厂商执行 同一 mapper 接口的不同 SQL 语句

01 数据库名称
package org.example.mybatis.api;import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;public class JdbcApi {public static void main(String[] args) throws SQLException {String url = "jdbc:mysql:///mybatis?serverTimezone=Asia/Shanghai";Connection connection = DriverManager.getConnection(url, "root", "123456");DatabaseMetaData metaData = connection.getMetaData();String productName = metaData.getDatabaseProductName();System.out.println("productName =" + productName);}}
02 标识机制
  • mybatis-config.xml
<databaseIdProvider type="DB_VENDOR"><property name="SQL Server" value="sqlserver" /><property name="DB2" value="db2" /><property name="Oracle" value="oracle" /><property name="数据库产品名称" value="别名" />
</databaseIdProvider>
  • mapper [针对 selectById 方法可提前配置多条 SQL语句]
<select id="selectById"parameterType="_int"resultType="user"databaseId="oracle">SELECTuser_id id,user_username usernameuser_create_datetime createDatetimeuser_gender genderFROMuserWHERE user_id = #{id}
</select><select id="selectById"parameterType="_int"resultType="user"databaseId="mysql">SELECTuser_id id,user_username usernameuser_create_datetime createDatetimeuser_gender genderFROMuserWHERE user_id = #{id} AND 1 = 1 <!--为了区别上一个select语句-->
</select>

[!note]

备注: 实际开发时因尽量使用 SQL规范关键值或查询方式, 避免使用数据库特殊关键值

3.9 映射器

映射器是 Mybatis 预言指定 Mapper 接口所在位置的手段

  • 其指定逻辑方式有:mybatis-config.xml 使用 mappers 标签配置

  • 指定 全限定名 mapper xml 位置 路径目录用 / 表示

  • 指定 全限定名 本地 mapper xml 本地位置

  • 指定 全限定名 mapper 接口 位置 路径目录用 .表示

  • 指定 全限定名 mapper 接口所在包位置 路径目录用 .表示[常用]

  • mappers

<!-- 使用相对于类路径的资源引用 -->
<mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"?><mapper resource="org/mybatis/builder/PostMapper.xml">
</mappers>
  • mappers
<!--使用完全限定资源定位符(URL)-->
<mappers>
<mapper urL="file:///var/mappers/AuthorMapper.xm"/>
<mapper url="file:///var/mappers/BlogMapper.xmL"/>
<mapper urL="file:///var/mappers/PostMapper.xmL"/>
</mappers>
  • mappers
<!--使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
  • mappers
<!-- 将包内的映射器接口全部注册为映射器 -->
<mappers><package name="org.mybatis.builder"/>
</mappers>

04.映射文件

Mapper.xml 中 mapper 根元素下只允许出现以下子元素

----- SQL 映射文件只有很少的几个顶级元素 (按照应被定义的顺序列出)

  • cache - 该命名空间的缓存配置

  • cache-ref -引用其他命名空间的缓存配置

  • resultMap -描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素

  • sql - 可被其他语句引用的可重用语句块

  • insert - 映射插入语句

  • update -映射更新语句

  • delete -映射删除语句

  • select -映射查询语句

4.1 select

select 标签用于 SQL 查询和逻辑映射

01 属性列表
  • select 标签元素只允许的出现的属性
<selectid="methodName"parameterType="int"parameterMap="deprecated"resultType="hashmap"resultMap="resultMapId"flushCache="false"useCache="true"timeout="10"fetchSize="256"statementType="PREPARED"resultSetType="FORWARD_ONLY">
  • select 标签属性说明

image-20240924104447487

02 resultType

resultType 用于返回类型,基础类型,Map, 集合,对象类型

01 基础类型【单个值】
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.Gender;
import org.exampl.mybatis.entity.User;import java.util.List;
import java.util.Map;@Mapper
public interface UserMapper {User selectById(int id);User selectByUsernameAndGender(User user);User selectByGenderAndUsername(@Param("gender") Gender gender,@Param("username") String username);long count();String selectUsernameById(int id);}
02 对象类型
03 集合对象类型
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.Gender;
import org.example.mybatis.entity.User;import java.util.List;
import java.util.Map;@Mapper
public interface UserMapper {User selectById(int id);User selectByUsernameAndGender(User user);User selectByGenderAndUsername(@Param("gender") Gender gender,@Param("username") String username);long count();String selectUsernameById(int id);List<User> selectList();
}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><select id="selectById" parameterType="_int" resultType="User">SELECTuser_id id,user_username username,user_create_datetime createDateTime,user_gender genderFROMuserWHERE user_id = #{id}</select><select id="selectByUsernameAndGender" parameterType="User" resultType="User">SELECTuser_id id,user_username username,user_create_datetime createDatetime,user_gender genderFROMuserWHEREuser_username = #{username} AND user_gender = #{gender}</select><select id="selectByGenderAndUsername" resultTyep="User">SELECT user_id id,user_username username,user_create_datetime createDatetime,user_gender genderFROMuserWHEREuser_username = #{username} AND user_gender = #{gender}</select><select id="count" resultType="_long">SELECT COUNT(1) FROM user</select><select id="selectUsernameById" parameterType="_int" resultType="string">SELECT user_username FROM user WHERE user_id = #{id}</select><select id="selectList" resultType="User">SELECT user_id id,user_username username,user_creae_datetime createDateTime,user_gender genderFROMuser</select>
</mapper>
04 Map类型
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.Gender;
import org.example.mybatis.entity.User;import java.util.List;
import java.util.Map;@Mapper
public interface UserMapper {User selectById(int id);User selectByUsernameAndGender(User user);User selectByGenderAndUsername(@Param("gender") Gender gender,@Param("username") String username);long count();String selectUsernameById(int id);List<User> selectList();Map<String Object> selectByIdToHashMap(int id);List<Map<String, Object>> selectListOfHashMap();}

4.2 insert update delete

insert update delete 用于完成 插入 更新 删除

01 属性列表
<insertid="insertAuthor"parameterType="domain.blog.Ahthor"flushCache="true"statementType="PREPARED"keyProperty=""useGeneratedKeys=""timeout="20">
</insert>
<updateid="updateAuthor"parameterType="domain.blog.Author"flushCache="true"statementType="PREPARED"timeout="20">
</update>
<deleteid="deleteAuthor"parameterType="domain.blog.Author"flushCache="true"statementType="PREPARED"timeout="20">
</delete>
  • 属性说明

image-20240924222443061

强调
  1. insert update delete 没有返回指定的类型
  2. insert update delete 只能返回 int 或 boolean 类型
增改删实例
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotation.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.Gender;
import org.example.mybatis.entity.User;import java.util.List;
import java.util.Map;@Mapper
public interface UserMapper {int insert(User user);int updateUsernameById(@Param("username") String username,@Param("id") int id);int deleteByLikeUsername(String username);}
  • UserMapper.xml
<?xml version="1.0" encoding="TUF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><insert id="insert" parameterType="User">INSERT INTO user(user_id,user_username,user_create_datetime,user_gender)VALUE (null,#{username},#{createDatetime},#{gender})</insert><update id="updateUsernameById">UPDATE user SET user_username = #{username} WHERE user_id = #{id}</update><delete id="deleteByLikeUsername" parameterType="string">DELETE FROM WHERE user_name LIKE CONCAT('%', #{username}, '%')</delete>
</mapper>
02 自增主键
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.Gender;
import org.example.mybatis.entity.User;import java.util.List;
import java.util.Map;@Mapper
public interface UserMapper {int insert(User user);}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><insert id="insert"patameterType="User"userGeneratedKeys="true"keyColumn="user_id"keyProperty="id">INSERT INTO user(user_id,user_username,user_create_datetime,user_gender)VALUES (null,#{username},#{createDatetime},#{gender})</insert></mapper>

4.3 参数

Mybatis 无论查询还是更新 都支持单个基本参数,对象参数,多个基本参数

  • parameterType 支持单个基本参数
  • parameterType 对象参数
  • parameterType 多个基本参数
01 单个参数
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis,entity.Gender;
import org.example.mybatis.entity.User;@Mapper
public interface UserMapper {public User selectById(int id);}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><select id="selectById" parameterType="_int" resultType="User">SELECTuser_id id,user_username username,user_create_datetime createDatetime,user_gender genderFROM	userWHEREuser_id = #{id}</select></mapper>
02 对象参数
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotaions.Param;
import org.example.mybatis.entity.Gender;
import org.example.mybatis.entity.User;@Mapper
public interface UserMapper {public User selectById(int id);public User selectByUsernameAndGender(User user);}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"<select id="selectById" parameterType="_int" resultType="User">SELECTuser_id id,user_username username,user_create_datetime createDatetime,user_gender genderFROMuserWHEREuser_id = #{id}</select>
03 多个参数
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.Gender;
import org.example.mybatis.entity.User;@Mapper
public interface UserMapper {public User selectById(int id);public User selectByUsernameAndGender(User user);public User selectByGenderAndUsername(@Param("gender") Gender gender),@Param("username") String username);
}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><select id="selectById" parameterType="_int" resultType="User">SELECTuser_id id,user_username usernameuser_create_datetime createDatetime,user_gender genderFROMuserWHEREuser_id = #{id}</select><select id="selectByUsernameAndGender" parameterType="User" resultType="User">SELECTuser_id id,user_username usernameuser_create_datetime createDatetime,user_gender genderFROMuserWHEREuser_username = #{username} AND user_gender = #{gender}</select><select id="selectByGenderAndUsername" resultType="User">SELECTuser_id id,user_username usernameuser_create_datetime createDatetime,user_gender genderFROMuserWHEREuser_username = #{username} AND user_gender = #{gender}</select>
</mapper>

4.4 高级结果映射

resultMap 可完成单个类型,嵌套类型等复杂类型指定映射

01 resultMap
  • resultMap 子标签

    • constructor 用于指定构造方法创建对象
      • idArg 指定 主键列 列提高性能
      • arg 指定 普通列
  • id 无参构造创建对象 指定 主键 列

  • result 无参构造创建对象 指定 普通列

  • association 指定嵌套结果集映射

  • collection 指定被集合包裹的嵌套结果集映射

  • discriminator 指定某列值来决定选取 另外的 ResultMap 映射

    • case
  • resultMap 属性

    • id 指定当前映射的 ID 唯一标识
    • type 指定当前映射的主类型
    • autoMapping 开启或关闭默认自动映射 会覆盖 autoMappingBehavior 默认 unset
02 基础使用

实体类

  • User.java
package org.example.mybatis.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;@Data
@AllArgsConstructor
@NoArgsConstructorpublic class User {private Integer id;private String username;private LocalDateTime createDatetime;private String gender;}
  • Mapper

  • UserMapper.java

package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.User;import java.util.List;@Mapper
public interface UserMapper {User selectById(int id);List<User> selectList();
}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org///DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><!-- <resultMap id="baseUser" type="User"><constructor><idArg column="user_id" javaType="integer"/><arg column="user_username" javaType="string"/><arg column="user_create_datetime" javaType="java.time.LocalDateTime"/><arg column="user_gender" javaType="string"/></constructor></resultMap>--><resultMap id="baseUser" type="User" autoMapping="false"><id column="user_id" property="id"/><result column="user_username" property="username"/><result column="user_create_datetime" property="createDatetime"/><result column="user_gender" property="gender"/></resultMap><select id="selectById" parameterType="_int" resultMap="baseUser">SELECTuser_id,user_username,user_create_datetime,user_genderFROMuserWHEREuser_id = #{id}</select><select id="selectList" resultMap="baseUser">SELECTuser_id,user_username,user_create_datetime,user_genderFROMuser</select>
</mapper>
03 association

association 用于完成嵌套结果集映射, 嵌套关系是 Java 的和 Mybatis 无关

  • association 允许指定指定列映射到 类中各个复杂成员

第一种 一条 SQL语句

  • Role.java
package org.example.mybatis.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {private Integer id;private String name;}
  • User.java
package org.example.mybatis,entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok,NoArgsConstructor;import java.time.LocalDateTime;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private Integer id;private String username;private LocalDateTime createDatetime;private Role role;
}
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.User;import java.util.List;@Mapper
public interface UserMapper {User selectById(int id);List<User> selectList();
}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="baseUser" type="User" autoMapping="false"><id column="user_id" property="id"/><result column="user_username" property="username"/><result column="user_create_datetime" property="createDatetime"/><result column="user_gender" property="gender"/></resuLtMap><resultMap id="baseRole" type="Role"><id column="role_id" property="id"/><result column="role_name" property="name"/></resultMap><resultMap id="userAndRole" type="User" extends="baseUser"><association property="role" resultMap="baseRole" fetchType="lazy"/></resultMap><select id="selectById" parameterType="_int" resultMap="userAndRole">SELECTU.user_id,U.user_username,U.user_create_datetime,U.user_gender,R.role_id,R.role_nameFROMUserUJOINuser_role URON		U.user_id = #{id} AND U.user_id = UR.ur_user_idJOINRole RON		UR.ur_role_id = R.role_id</select><select id="selectList" resultMap="baseUser">SELECTuser_id,user_usernameuser_create_datetime,user_genderFROMuser</select></mapper>

第二种 多条SQL 语句 [各独立 Mapper]

  • RoleMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotationsMapper;
import org.example.mybatis.entity.Role;@Mapper
public interface RoleMapper {Role selectByUserId(int userId);
}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.RoleMapper"><resultMap id="baseRole" type="Role"><id column="role_id" property="id"/><result column="role_name" property="name"/></resultMap><select id="selectByUserId" parameterType="_int" resultMap="baseRole">SELECTR.role_id,R.role_nameFROMRole RJOINuser_role URONR.role_id = UR.ur_role_id AND UR.ur_user_id = #{userId}</select></mapper>
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="baseUser" type="User"autoMapping="false"><id column="user_id" property="id"/><result column="user_username" property="username"/><result column="user_create_datetime" property="createDatetime"/><result column="user_gender" property="gender"/></resuLtMap><resultMap id="userAndRole"type="User"extends="baseUser"><association property="role"select="org.example.mybatis.mapper.RoleMapper.selectByUserId"column="user_id"fetchType="lazy"/></resultMap><!-- 	<resultMap id="baseRole" type="Role"><id column="role_id" property="id"/><result column=”role_name" property="name"/></resultMap><resultMap id="userAndRole” type="User" extends="baseUser"><association property="role” resultMap="baseRole" fetchType="lazy"/></resultMap>--><select id="selectById" parameterType="_int" resultMap="userAndRole">SELECTuser_id,user_username,user_create_datetime,user_genderFROMuserWHEREuser_id =#{id}</select>
</mapper>
04 collection
  • DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.RoleMapper"><resultMap id="baseDepartment" type="Department"><id column="department_id" property="id"/><result column="department_name" property="name"/></resultMap><resultMap id="baseEmployee" type="Employee"><id column="employee_id" property="id"/><result column="employee_name" property="name"?/><result column="employee_phone" property="phone"/></resultMap><resultMap id="deparmentAndEmployee" type="Department" extends="baseDepartment"><colleciont property="employees"javaType="list"ofType="Employee"resultMap="baseEmployee"fetchType="lazy"/></resultMap><select id="selectById" parameterType="_int" resultMap="departmentAndEmployee">SELECTD.department_id,D.department_name,E.employee_id,E.employee_name,E.employee_phoneFROMdepartment DJOIN 	employee EOND.department_id = #{id} AND D.department_id = E.employee_department_id</select>
</mapper>

自行 SQL 逻辑关联

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.RoleMapper"><resultMap id="baseEmployee" type="Employee"><id column="employee_id" property="id"/><result column="employee_name" property="name"/><result column="employee_phone" property="phone"/></resultMap><select id="selectByDepartmentId" parameterType="_int" resultMap="">SELECT employee_id,employee_name,employee_phone,FROMemployeeWHEREemployee_department_id = #{departmentId}</select>
</mapper>
05 discriminator

期望根据某个列的值 [这个指一般固定 比如 男 女] 再来决定指定那个 resultMap 映射

  • SQL
CREATE TABLE people (people_id INT PRIMARY KEY AUTO_INCREMENT,people_id VARCHAR(10),people_phone VARBINARY(12),people_gender VARCHAR(10)
)CREATE TABLE male_health_form (mhf_id INT PRIMARY KEY AUTO_INCREMENT,mhf_height INT,mhf_weight INT,mhf_pulmonary INT,mhf_strong INT,mhf_people_id INT
)CREATE TABLE female_health_foem (fhf_id       INT PRIMARY KEY AUTO_INCREMENT,fhf_height	 INT,fhf_weight   INT,fhf_bust	 INT,fhf_waist    INT,fhs_people_id   INT
)

实体类

  • People.java
package org.example.mybatis.entity;import lombok.Data;@public class People {private Integer id;private String name;private String phone;private String gender;private HealthForm healthForm;
}
  • HealthForm.java
package org.example.mybatis.entity;import lombok.Data;@Data 
public class HealthForm {private Integer id;private Integer height;private Integer weight;
}
  • MaleHealthForm.java
package org.example.mybatis.entity;import lom.bok.Data;@Data
public class MaleHealthForm extends HealthForm {private Integer pulmonary;private Integer strong;}
  • FemaleHealthForm.java
package org.example.mybatis.entity;import lombok.Data;@Data
public class FemaleHealthForm extends HealthForm {private Integer bust;private Integer waist;}
  • PeopleMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis,entity.People;@Mapper
public interface PeopleMapper {People selectById(int id);}
  • PeopleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.PeopleMapper"><resultMap id="basePeople" tyle="People"><id column="people_id" property="id"/><result column="people_name" property="name"/><result column="people_phone" property="phone"/><result column="people_gender" property="gender"/></resultMap><resultMap id="maleForm" type="MaleHealthForm"><id column="mhf_id" property="id"/><result column="mhf_height" property="height"/><result column="mhf_weight" property="weight"/><result column="mhf_pulmonary" property="puLmonary"/><result column="mhf_strong" property="strong"/></resultMap><resultMap id="femaleForm" type="FemaleHealthForm"><id column="fhf_id" property="id"/><result column="fhf_height" property="height"/><result column="fhf_weight" property="weight"/><result column="fhf_bust" property="bust"/><result column="fhf_waist" property="waist"/></resultMap><resultMap id="peopleAndHealthForm" type="People" extends="basePeople"><association property="healthForm"><discriminator javaType="string" column="people_gender"><case value="MALE" resultMap="maleForm"/><case value="FEMALE" resuLtMap="femaLeForm"/></discriminator></association></resultMap><select id="selectById" parameterType="_int" resultMap="peopleAndHealthForm">SELECTP.people_id,P.people_name,P.people_phone,P.people_gender,MHF.mhf_id,MHF.mhf_height,MHF.mhf_weight,MHF.mhf_pulmonary,MHF.mhf_strong,FHF.fhf_id,FHF.fhf_height,FHF.fhf_weight,FHF.fhf_bust,FHF.fhf_waistFROM 	people PLEFT JOINmale_health_form MHFON		P.people_id = MHF.mhf_people_idLEFT JOINfemale_health_form FHFON		P.people_id = FHF.fhf_people_idWHERE	P.people_id= #{id}</select></mapper>
06 反向关联

Mybatis 的关联关系是单项的,如果有双向关联则是相互独立的

  • 若有双向关联时,要注意 A 关联 B 关联 A [此时这个 A 不能再关联 B了] 否则死循环

  • 解决方式为 灵活选择 ResultMap

  • 避免双向关联, 设计时考虑从主到次的关联方式

  • Employee.java

package org.example.mybatis.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {private Integer id;private String name;private String phone;private Department department;
}
  • EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.EmployeeMapper"><resuLtMap id="baseEmployee" type="Employee"><id column="employee_id" property="id"/><result column="employee_name" property="name"/><result column="empLoyee_phone" property="phone"/></resultMap><resuLtMap id="empLoyeeAndDepartment"type="Employee"eextends="baseEmpLoyee"><association property="department"column="employee_department_id"select="org.example.mybatis.mapper.DepartmentMapper._selectById"fetchType="lazy"/></resultMap><select id="selectByDeartmentId"parameterType="_int"resuLtMap="empLoyeeAndDepartment">SELECTemployee_id,employee_name,employee_phone,employee_department_idFROMemployeeWHEREemployee_department_id = #{departmentId}</select>
</mapper>
  • DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.EmployeeMapper"><resultMap id="baseDepartment" type="Department"><id column="department_id" property="id"/><result column="department_name" property="name"/></resultMap><resultMap id="departmentAndEmployee" type="Department" extends="baseDepartment"><collection property="employees"javaType="list"ofType="EmpLoyee"column="department_id"select="org.example.mybatis.mapper.EmployeeMapper.selectByDepartmentId"fetchType="lazy"/></resultMap><select id="selectById" parameterType="_int" resuLtMap="departmentAndEmployee">SELECTdepartment_id,department_nameFROMdepartmentWHEREdepartment_id =#(id}</select><select id="_selectById" parameterType="_int" resultMap="baseDepartment">SELECTdepartment_id,department_nameFROMdepartmentWHEREdepartment_id =#{id}</select></mapper>

4.5 自动映射

Mybatis 默认支持两种情况的自动映射

  1. 当表列名和对象属性名称一致时, mybatis 能完自动映射 [可借助此点给列别名]
  2. 开启全局驼峰映射时,列 user_id,属性 userId, mybatis 能完自动映射

4.6 缓存

Mybatis 有一级缓存默认开启,二级缓存需 cache 标签配置

01 一级缓存

Mybatis 的一级缓存是针对 SqlSession

  • 证据 [多次执行相同查询 不会多次发送 SQL 语句]
package org.example.mybatis.api;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatisl.session.SqlSessionFactoryBuilder;
import org.example.mybatis.mapper.UserMapper;import java.io.IOException;
import java.io.Reader;public class Application {String resources = "mybatis-config.xml";Reader config = Resources.getResourceAsReader(resources);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);UserMapper userMapper = sqlSession.getMapper(UserMapper.class);userMapper.selectById(1);userMapper.selectById(1);userMapper.selectById(1);sqlSession.close();.
}
  • 只要查询就会被缓存到 SqlSession, 只要查询就会刷新 SqlSession 缓存, 只要更新就会刷新当前对应 namespace SqlSession 缓存。

  • Mybatis 一级缓存是基于命名空间隔离的, 各个 namespace 不会互相影响

  • 一级缓存难以享受且暴力,没有良好的可视化管理方案

02 二级缓存

二级缓存基于 SqlSessionFactory 先获取一级缓存 若无 再获取二级缓存

证据
package org.example.mybatis.api;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlsessionFactory;
import org.apache.ibatis.session.SqlsessionFactoryBuilder;
import org.example.mybatis.mapper.UserMapper;import java.io.IOException;
import java.io.Reader;public class Application {public static void main(String[] args) throws IOEception {String resources = "mybaits-config.xml";Reader config = Resources.getResourceAsReader(resorces);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().builder(config);SqlSession sqlSessionl = sqlSessionFactory.openSession();UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);userMapper1.selectById(1);sqlSession1.commit();SqlSession sqlSession2 = sqlSessionFactory.openSession();UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);userMapper2.selectById(1);sqlSession2.commit();}
}
缓存命中率

image-20240927131212183

结论
  • 二级缓存默契开启,但需要使用 < cache> 标签显式对其使用 cache 可轻微控制缓存算法等

  • 二级缓存是基于命名空间隔离的, 各个 namespace 不会相互影响

  • 二级缓存在暴力, 没有良好的可视化管理方案

  • 二级缓存有命中率的概念

  • 特殊的

    • 无论一级二级缓存 数据库没有数据也是一种数据 null 也会缓存
03 缓存方案
  1. 缓存方案应该业务层中实现,业务层会处理数据, 业务层才对业务敏感

  2. 缓存方案必须放在读多写少的场景,否则缓存难以享受且徒增系统负担

  3. 缓存方案必须保证 查询被缓存,更新可能要清除缓存 [是否一定清除看策略]

  4. 缓存方案可以借助 命名空间 + KEY, 思路去隔离缓存来进行管理

  5. 缓存方案不一定非要等到更新操作去刷新缓存, 可以周期性的刷新

  6. 缓存要提供良好的可视化管理方案

4.7 sql

sql 标签用于组装重复的 SQL 语句,不推荐使用 会使得 Mapper 难以维护

  • UserMapper.java
pack org.example.mybaits.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.User;import java.util.List;@Mapper
public interface UserMapper {User selectById(int id);List<User> selectList();
}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.UserMapper"><sql id="baseSelectUser">SELECTuser_id id,user_username username,user_create_datetime createDateTime,user_gender genderFROMuser</sql><select id="selectById" parameterType="_int" resultType="User"><include refid="baseSelectUser"/>WHEREuser_id = #{id}</select><select id="selectList" resultType="User"><include refid="baseSelectUser"/></select></mapper>

05.动态SQL

Mybatis 提供一些特殊标签 用于运行时拼接 SQL语句

  • if | choose | when | otherwise | where |set | bind | foreach
  • 以上标签都是 select | update | delete 的子元素

5.1 where if

  • Mapper.xml
<select id="selectByCondition" parameterType="User" resultMap="baseUser">SELECTuser_id,user_username,user_create_datetime,user_genderFROMuser<where><if test="username != null">user_username = #{username}</if><if test="gender != null">AND user_gender = #{gender}                          </if></where>
</select>

5.2 choose, when, otherwise

  • Mapper.xml
<select id="selectByOnlyOneCondition" parameterType="User" resultMap="baseUesr">SELECTuser_id,user_username,user_create_datetime,user_genderFROMuser<where><choose><when test="username != nulll">user_username = #{username}</when> <when test="gender != null">user_gender = #{gender}</when><otherwise>1 = 1</otherwise></choose></where>
</select>

5.3 set

  • 一个条件都不满足时, SQL 会是错误状态:拿条件列去做一个更新

  • Mapper.xml

<update id="update" parameterType="User">UPDATE user<set><if test="id != null">user_id = #{id},</if><if test="username != null">user_username = #{username},</if></set>WHERE user_id = #{id}
</update>

5.4 foreach

  • **foreach 用于遍历集合或数组 比如 in 查询 | 批量插入 **

  • UserMapper.java

package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.User;import java.util.List;@Mapper
public interface UserMapper {User selectById(int id);int updateGenderById(@Param("gender") String gender,@Param("id") int id);User selectByCondition(User user);User selectByOnlyOneCondition(User user);int update(User user);List<User> selectByIdList(List<Integer> ids);int insertBatch(List<User> userList);
}
  • Mapper.xml
<select id="selectByIdList" parameterType="list" resultMap="baseUser">SELECTuser_id,user_username,user_create_datetime,user_genderFROMuserWHEREuser_id IN<foreach collection="list" item="itemId" separator=", " open="(" close=")">#{itemId}</foreach>
</select><insert id="insertBatch" parameterType="list">INSERT INTO user(user_id, user_name, user_create_datetime, user_gender) VALUES<foreach collection="list" item="user" separator=", ">(null, #{user.username}, #{user.createDatetime}, #{user.gender})</foreach>	
</insert>

5.5 script

  • Java
@Update({"<script>","update Author","	<set>","		<if rest='username != null'>username=#{username}, </if>","		<if test='password != null>'password=#{password}, </if>","		<if test='email != null'>email=#{email}, </if>","		<if test='bio != null'>bio=#{bio}</if>,"   </set>","where id=#{id}","</script>"})void updateAuthorValues(Author author);

5.6 bind

  • 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文
<select id="selectBlogsLike" resultType="Blog"><bind name="pattern" value="'%' + _parameter.getTitle() + '%'"/>SELECT * FROM BLOGWHERE title LIKE #{pattern}
</select>

5.7 ${}

  • ${} 为上下文表达式获取变量不转义, #{} 是 SQL 占位解析符放入变量会转义满足 SQL

  • #{} 是 SQL 占位符 是 Mybatis 自行实现的

  • 请参考类: org.apache.ibatis.builder.SqlSourceBuilder

  • UserMapper.java

package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.example.mybatis.entity.User;import java.util.List;@Mapper 
public interface UserMapper {String selectOneColumnOneValue(@Param("column") String column,@Param("id") int id);
}
  • UserMapper.xml
<select id="selectOneColumnOneValue" resultType="string">SELECT${column}FORMuserWHEREuser_id = #{id}
</select>

06.API

6.1 核心配置

  • Application.java
package org.example.mybatis.api;import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.example.mybatis.entity.User;
import org.example.mybatis.mapper.UserMapper;public class Application {public static void main(String[] args) {JdbcTransactionFactory factory = new JdbcTransactionFactory();pooledDataSource dataSource = new PooledDataSource();String driver = "com.mysql.cj.jdbc.Driver";String url = "jdbc:mysql:///mybatis?serverTimezone=Asia/Shanghai";String username="root";String password="root";dataSource.setDriver(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);Environment environment = new Environment("dev", factory, dataSource);Configuration configuration = new Configuration(environment);configuration.addMappers("org.example.mybatis.mapper");configuration.getTypeAliasRegistry().registerAliases("org.example.mybatis.entity");// configuration.addInterceptor();configuration.setCacheEnabled(true);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);SqlSession sqlSession = sqlSessionFactory.openSession(true);UserMapper mapper = sqlSession.getMapper(UserMapper.class);// User user = mapper.selectById(3);// System.out.println(user);mapper.selectList().forEach(System.out::println);sqlSession.commit();}}

6.2 映射注解

Mybatis 提供 @Select | @Update @Result 用于完成对应 xml 的映射行为

  • User.java
package org.example.mybatis.entity;import lombok.Data;import java.time.LocalDateTime;@Data
public class User {private Integer id;private String username;private LocalDateTime createDatetime;private Gender gender;}public enum Gender {MAN("男"), WOMAN("女")private final String gender;private Gender(String gender) {this.gender = gender;}public String getGender() {return gender;}
}
  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotaions.Select;
import org.example.mybatis.entity.User;import java.util.List;@Mapper
public interface UserMapper {@Select ("SELECTuser_id,user_username,user_create_datetime,user_genderFROMuserWHERE user_id = #{id}")@Results(id = "baseUser", value= {@Result(id = "true", column = "user_id", property = "id"),@Result(id = "user_username", property = "username"),@Result(column = "user_create_datetime", property = "createDatetime"),@Result(column = "user_gender", property = "gender")})User selectById(int id);@Select ("SELECTuser_id,user_username,user_create_datetime,FROMuser")@ResultMap("bassUser")List<User> selectList();
}

07.SQL构建器

Mybatis 提供 Java API 方式构建 SQL 语句

  • Demo
package org.example.mybatis.api;import org.apache.ibatis.jdbc.SQL;public class SqlBuilderUsage {public static void main(String[] args) {String SQL  = new SQL() {SELECT("user_id", "user_username");FROM("USER");WHERE("user_id = #{id}");}.toString();System.out.prinltn(SQL);}
}

08.分页插件

8.1 分页逻辑

当分页数据为全表数据或条件查询部分数据时, 可采用不同分页策略

01 全表
  • 当对全表数据进行分页时,可直接借助 ID 进行 SQL 逻辑分页
  • 页码: page = 1
  • SQL
page = 1SELECT *
FROMTABLE_NAME
WHEREid >= ((page - 1) * size) && id <= (page * size)
02 条件查询
  • 页码: page = 1 起始位置 = (page - 1) * size
  • SQL
SELECT *
FROMTABLE_NAME
WHERE查询条件 LIMIT startIndex, count
分页数据
  • 必须返回 总数据量, 总页码, 当前页码数据
  • 总数据量 = SELECT COUNT(*) FROM TABLE [WHERE 条件]
  • 总页码数 = 总数据量 / 每页数据量 [如果除不尽需要 + 1]

8.2 PageHelper

https://pagehelper.github.io/

01 概念
  1. PageHelper 是针对 Mybatis 框架的分页插件,同时也能适配各种数据库
  2. PageHelper 是通过 Mybatis 拦截器 拦截 SQL 并改变 SQL 来实现分页
  • 官网
02 环境
  • pom.xml
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pageheler -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>6.0.0</version>
</dependency>
  • dependency

image-20240927173114313

  • mysql
<!-- SQL: SELECT VERSION(): -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>
  • pom.xml [src/main/java 非java文件编译打包配置]
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.*</include></includes></resource><resource><directory>src/mian/resources</directory><includes><include>**/*.*</include></includes></resource></resources>
</build>
03 应用
  • GoodsMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.Goods;import java.util.List;@Mapper
public interface GoodsMapper {List<Goods> selectByTitleLikeKeyword(String keyword);}
  • s
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN"""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mybatis.mapper.GoodsMapper"><resultMap id="baseGoods" type="Goods"><id column="goods_id" property="id"/><result column="goods_url" property="url"/><result column="goods_title" property="title"/><result column="goods_type" property="type"/><result column="goods_price"property="price"/></resultMap><select id="selectByTitleLikeKeyword"parameterType="string"resultMap="baseGoods">SELECTgoods_id,goods_url,goods_title,goods_type,goods_priceFROMtb_goodsWHEREgoods_title LIKE CONCAT('%',#{keyword}, '%'}</select>
</mapper>
  • Api
GoodsMapper mapper = sqlSession.getMapper(GoodsMapper.class);Page<Goods> page = PageHelper.startPage(5, 20)
mapper.selectByTitleLikeKeyWord("手机");// System.out.println("page.getPages() = " + page.getPages());
// System.out.println("page.getTotal() =" + page.getTotal());
// page.getResult().forEach(System.out::println);
  • mybatis-config.xml
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
  • Console

image-20240927180233319

09.权限模型实战

基于角色的控制权限 RBAC (Role-Based Access Control)

9.1 表

CREATE TABLE user (user_id			INT PRIMARY KEY AUTO_INCREMENT,user_username	VARCHAR(20)user_phone 		VARCHAR(20)...
)
CREATE TABLE role (role_id INT PRIMARY KEY AUTO_INCREMENT,role_name 	VARCHAR(20),
)
CREATE TABLE permission (permission_id INT PRIMARY KEY AUTO_INCREMENT,permission_name VARCHAR(20),
)
CREATE TABLE user_role (ur_id INT PRIMARY KEY AUTO_INCREMENT,ur_user_id INTur_role_id INT
)
CREATE TABLE role_permission (rp_id INT PRIMARY KEY AUTO_INCREMENT,rp_role_id 	INT,rp_permission_id	INT
)

9.2 实战

实体类

  • User.java
package org.example.mybatis.entity;import lombok.Data;@Data
public class User {private Integer id;private String username;private String phone;private Role role;
}
  • Roel.java
package org.example.mybatis.entity;import lombok.Data;import java.util.List;@Data
public class Role {private Integer id;private String name;private List<Permission> permissions;
}
  • Permission.java
package org.example.mybatis.entity;import lombok.Data;@Data
public class Permission {private Integer id;private String name;}

Mapper

  • UserMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.User;@Mapper
public interface UserMapper {User selectById(int id);}
  • UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="baseUser" type="User"><id column="user_id" property="id"/><result column="user_username" property="username"/><result column="user_phone" property="phone"/></resultMap><resultMap id="userAndRole" type="User" extends="baseUser"><association property="role"column="user_id"select="org.example.mybatis.mapper.RoleMapper.selectByUserId"fetchType="lazy"/></resultMap><select id="selectById" parameterType="_int" resultMap="userAndRole">SELECTuser_id,user_username,user_phoneFROMuserWHEREuser_id = #{id}</select></mapper>
  • RoleMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.Role;@Mapper
public interface RoleMapper {Role selectByUserId(int userId);}
  • RoleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="baseRole" type="Role"><id column="role_id" property="id"/><result column="role_name" property="name"/></resultMap><resultMap id="roleAndPermission" type="Role" extends="baseRole"><association property="permissions"javaType="list"ofType="Permission"column="role_id"select="org.example.mybatis.mapper.PermissionMapper.selectListByRoleId"fetchType="lazy"/></resultMap><select id="selectByUserId" parameterType="_int" resultMap="roleAndPermission">SELECTR.role_id,R.role_nameFROMROLE RJOIN 	user_role URON		R.role_id = UR.ur_role_id AND UR.ur_user_id = #{userId}</select></mapper>
  • PermissionMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.Permission;import java.util.List;@Mapper
public interface PermissionMapper {List<Permission> selectListByRoleId(int roleId);}
  • PermissionMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="basePermission" type="Permission"><id column="permission_id" property="id"/><result column="permission_name" property="name"/></resultMap><select id="selectListByRoleId" parameterType="_int" resultMap="basePermission">SELECTP.permission_id,P.permission_nameFROMpermission PJOIN 	role_permission RPON		RP.rp_permission_id = P.permission_id AND RP.rp_role_id = #{roId}</select></mapper>
  • RoleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="baseRole" type="Role"><id column="role_id" property="id"/><result column="role_name" property="name"/></resultMap><resultMap id="roleAndPermission" type="Role" extends="baseRole"><association property="permissions"javaType="list"ofType="Permission"column="role_id"select="org.example.mybatis.mapper.PermissionMapper.selectListByRoleId"fetchType="lazy"/></resultMap><select id="selectByUserId" parameterType="_int" resultMap="roleAndPermission">SELECTR.role_id,R.role_nameFROMROLE RJOIN 	user_role URON		R.role_id = UR.ur_role_id AND UR.ur_user_id = #{userId}</select></mapper>
  • PermissionMapper.java
package org.example.mybatis.mapper;import org.apache.ibatis.annotations.Mapper;
import org.example.mybatis.entity.Permission;import java.util.List;@Mapper
public interface PermissionMapper {List<Permission> selectListByRoleId(int roleId);}
  • PermissionMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="org.example.mybatis.mapper.UserMapper"><resultMap id="basePermission" type="Permission"><id column="permission_id" property="id"/><result column="permission_name" property="name"/></resultMap><select id="selectListByRoleId" parameterType="_int" resultMap="basePermission">SELECTP.permission_id,P.permission_nameFROMpermission PJOIN 	role_permission RPON		RP.rp_permission_id = P.permission_id AND RP.rp_role_id = #{roId}</select></mapper>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/433760.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ZLMediaKit快速上手【保姆级简单快速版】

一、前言 1、ZLMediaKit使用场景 最近在写一个摄像头检测的项目&#xff0c;其中需要做拉流测试&#xff0c;但是摄像头数量不够用&#xff0c;如果直接重复拉流可能会出现问题&#xff0c;使用ZLMediaKit&#xff08;一个基于C11的高性能运营级流媒体服务框架&#xff09;可…

UE5: Content browser工具编写02

DebugHeader.h 中的全局变量&#xff0c;已经在一个cpp file中被include了&#xff0c;如果在另一个cpp file中再include它&#xff0c;就会有一些conflicts。先全部给加一个static Add static keyword to debug functionsWrap all the functions inside of a namespaceprint …

【Redis技能熟练掌握之十年内功】

Redis技能熟练掌握之十年内功 1.redis是什么&#xff1f;为什么要使用redis&#xff1f;2.redis一般应用于什么场景&#xff08;四个场景&#xff09;&#xff1f;3. Redis持久化机制是什么&#xff1f;各自的优缺点&#xff1f;一般咋么用&#xff1f;4. redis五个基础类型支持…

【开源免费】基于SpringBoot+Vue.JS服装销售平台(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 054 &#xff0c;文末自助获取源码 \color{red}{T054&#xff0c;文末自助获取源码} T054&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

docker -私有镜像仓库 - harbor安装

文章目录 1、镜像仓库简介2、Harbor简介3、下载与安装3.1、下载3.2、安装3.2.1、上传harbor-offline-installer-v2.8.2.tgz到虚拟机中解压并修改配置文件3.2.2、解压tgz包3.2.3、切换到解压缩后的目录下3.2.4、准备配置文件3.2.5、修改配置文件 4、启动Harbor5、启动关闭命令6、…

gitlab添加CI自动测试

1. CI运行规格配置文件.gitlab-ci.yml yml 配置文件语法&#xff1a; https://docs.gitlab.com/17.3/ee/ci/yaml/index.html 添加.gitlab-ci.yml文件并配置 &#xff1a; ## 定义几个阶段 stages: # List of stages for jobs, and their order of execution- buil…

982. 按位与为零的三元组

1. 题目 982. 按位与为零的三元组 2. 解题思路 随机选择两个数&#xff0c;记录两个数的与结果。以及它的次数。 然后再遍历数组&#xff0c;用第三个数去与前两个数的结果&#xff0c;如果等于0&#xff0c;则满足条件。 3. 代码 3.1. 注意点 首先用简单的思路切入&…

【顺序表使用练习】发牌游戏

【顺序表使用练习】发牌游戏 1. 介绍游戏2. 实现52张牌3. 实现洗牌4. 实现发牌5. 效果展示 1. 介绍游戏 首先先为大家介绍一下设计要求 实现52张牌&#xff08;这里排除大小王&#xff09;洗牌——打乱牌的顺序发牌——3个人&#xff0c;1人5张牌 2. 实现52张牌 创建Code对象创…

MMD模型及动作一键完美导入UE5-IVP5U插件方案(二)

1、下载并启用IVP5U插件 1、下载IVP5U插件, IVP5U,点击Latest下载对应引擎版本,将插件放到Plugins目录,同时将.uplugin文件的EnableByDefault改为false 2、然后通过Edit->Plugins启用插件 2、导入pmx模型 1、直接在Content的某个目录拖入pmx模型,选择默认参数 2、…

项目实战:k8s部署考试系统

一、新建nfs服务器&#xff08;192.168.1.44&#xff09; 1.基础配置&#xff08;IP地址防火墙等&#xff09; 2.配置时间同步 [rootlocalhost ~]# yum -y install ntpdate.x86_64 [rootlocalhost ~]# ntpdate time2.aliyun.com 27 Sep 10:28:08 ntpdate[1634]: adjust tim…

【巅峰算力,静谧之作】4卡4090GPU深度学习“静音”服务器

各位同仁&#xff0c;随着人工智能浪潮的汹涌澎湃&#xff0c;我们正步入一个前所未有的创新纪元。在这个充满挑战与机遇的时代&#xff0c;我愈发频繁地在工作场景中邂逅那些致力于深度学习探索的智者们。他们&#xff0c;对计算力的渴望如同对知识的追求一般&#xff0c;永无…

React表单:formik、final-form和react-hook-form

表单无处不在&#xff0c;它是每个网站的必备部分。在用React构建web应用时&#xff0c;处理表单是不可避免的。 你可以选择自己的方式来处理&#xff0c;或者选择社区中现成的库。然而&#xff0c;当你选择一个第三方库时&#xff0c;你会立即面临一个问题&#xff1a;有太多的…

Spring Boot 学习之路 -- 配置项目

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门到精…

SpringMVC5-域对象共享数据

目录 使用ServletAPI向request域对象共享数据 使用ModelAndView向request域对象共享数据 使用Model向request域对象共享数据 使用map向request域对象共享数据 使用ModelMap向request域对象共享数据 Model、ModelMap、Map的关系 向session域共享数据 向application域共享…

SQLite3模块使用详解

目录 一、引言 1.1 SQLite3 简介 1.2 Python sqlite3 模块 二、连接数据库 2.1 导入 sqlite3 模块 2.2 连接数据库 2.3 创建游标对象 三、执行 SQL 语句 3.1 创建表 3.2 插入数据 3.3 查询数据 3.4 更新数据 3.5 删除数据 四、处理查询结果 4.1 fetchall() 4.2…

探探Java与python中的闭包

说在前面&#xff1a;在计算机科学中&#xff0c;闭包是指一个函数以及其引用的周围环境&#xff08;变量&#xff09;所组成的整体。简单来说&#xff0c;闭包允许一个函数访问并操作其外部函数作用域中的变量&#xff0c;即使外部函数已经执行完毕。 Java函数式编程—闭包&am…

C++map与set

文章目录 前言一、map和set基础知识二、set与map使用示例1.set去重操作2.map字典统计 总结 前言 本章主要介绍map和set的基本知识与用法。 一、map和set基础知识 map与set属于STL的一部分&#xff0c;他们底层都是是同红黑树来实现的。 ①set常见用途是去重 &#xff0c;set不…

【Java】包装类【主线学习笔记】

文章目录 前言包装类基本数据类型与包装类之间的转换基本数据类型转换为包装类可以通过以下几种方式&#xff1a;包装类转换为基本数据类型可以通过以下几种方式&#xff1a;初始化值不同与String之间的转换 前言 Java是一门功能强大且广泛应用的编程语言&#xff0c;具有跨平台…

“数字武当”项目荣获2024年“数据要素×”大赛湖北分赛文化旅游赛道一等奖

9月26日&#xff0c;由国家数据局、湖北省人民政府指导的首届湖北省数据要素创新大会暨2024年“数据要素”大赛湖北分赛颁奖仪式在湖北武汉举行。由大势智慧联合武当山文化旅游发展集团有限公司参报的武当山“数字武当”项目&#xff0c;荣获文化旅游赛道一等奖。 据悉&#x…

在系统开发中提升 Excel 数据导出一致性与可维护性的统一规范与最佳实践

背景&#xff1a; 在系统开发过程中&#xff0c;数据导出为 Excel 格式是一个常见的需求。然而&#xff0c;由于各个开发人员的编码习惯和实现方式不同&#xff0c;导致导出代码风格不一。有的人使用第三方库&#xff0c;有的人则自定义实现。这种多样化不仅影响了代码的一致性…