参考文章:
MyBatis3——入门介绍
MyBatis 常见面试题总结
(1)ORM 框架是 Object-Relational Mapping(对象关系映射)
框架的简称,用于将对象模型和关系数据库之间进行映射,即将 Java 对象映射到数据库表中的记录,或将数据库表中的记录映射为 Java 对象,从而使得开发者可以使用面向对象的方式来操作数据库。
(2)ORM 框架通常提供了一系列的映射规则和映射配置,开发者只需要编写简单的代码和配置就可以完成对象和关系数据库之间的映射。ORM 框架还提供了丰富的查询和操作 API,使得开发者可以方便地进行 CRUD 操作和复杂的查询。
(3)ORM 框架的优点包括:
(4)常见的 ORM 框架有 Hibernate、MyBatis、Spring Data JPA 等,它们在应用开发中发挥着重要的作用。
(1)MyBatis 是一款基于 Java 的持久层框架,也是一个半自动 ORM 框架,它提供了优雅的 SQL 映射方式和灵活的配置方式,可以帮助开发者快速、高效地访问数据库。在 MyBatis 中,开发者可以使用 XML 配置文件或者注解来编写 SQL 查询语句,同时可以通过一系列的对象映射配置将数据库表中的数据映射到 Java 对象中,使得开发者可以在应用程序中方便地操作这些数据。
(2)MyBatis 的主要特点包括:
(3)使用 MyBatis 可以有效地提高 Java 应用的开发效率和数据库查询性能,特别是在需要对 SQL 语句进行严格控制的场景下。同时,MyBatis 还支持多种数据库的访问,包括 MySQL、Oracle、SQL Server 等,非常适合在企业级应用中使用。
① 之所以称 Mybatis 是一个半 ORM 框架,是因为在查询关联对象或关联集合对象时,需要手动编写 SQL 来完成。
② 持久层是软件开发中的一个概念,指的是负责将数据持久化到存储介质(通常是数据库)中,并提供对数据的读取、更新和删除等操作的一部分。持久层的主要目的是为了解决数据的长期存储和访问的需求。
使用 MyBatis 相对于直接使用SQL有以下几个优势:
总的来说,使用 MyBatis 可以简化 SQL 编写、实现数据和对象的映射、提供缓存功能、提供数据库兼容性,并通过插件机制灵活扩展功能。通过这些优势,可以提高开发效率、降低维护成本,并提供更好的性能和可扩展性。然而,对于简单的数据库操作,直接使用 SQL 可能更加直观和方便。因此,对于具体的开发需求,可以根据实际情况选择适合的方式。
(1)MyBatis 作为一款流行的 Java 持久化框架,有以下优缺点:
优点:
XML
或注解
的方式来定义 SQL 语句,并且可以实现自定义的 SQL 语句和结果集的映射规则。这种灵活性使得 MyBatis 可以适应各种不同的应用场景。缓存机制
、预编译语句
等技术来提高 SQL 查询的性能。插件机制
,开发人员可以通过插件来扩展 MyBatis 的功能,实现自定义的逻辑。缺点:
(2)总之,MyBatis 是一款性能较高且灵活的持久化框架,但需要开发人员花费更多的时间和精力来编写 SQL 语句和处理结果集的映射。在应用场景选择时需要综合考虑其优缺点。
参考文章:Mybatis 层次结构与执行流程
(1)MyBatis 的执行流程如下:
SqlSessionFactory
是 MyBatis 的核心对象,负责创建 SqlSession对象。(2)总的来说,MyBatis 的执行流程可以分为两个阶段:
示例代码如下所示:
public class MyBatisTest {
//根据全局配置文件 mybatis-config.xml,利用 SqlSessionFactoryBuilder 创建 SqlSessionFactory
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
/*
* 1、根据 xml 配置文件(全局配置文件)创建一个 SqlSessionFactory 对象,其包含数据源等一些运行环境信息
* 2、sql 映射文件: 配置了每一个sql,以及sql的封装规则等
* 3、将 sql 映射文件注册在全局配置文件中
* 4、写代码:
* 1)根据全局配置文件得到 SqlSessionFactory;
* 2)使用 sqlSession 工厂,获取到 sqlSession 对象使用他来执行增删改查
* 一个 sqlSession就是代表和数据库的一次会话,用完关闭
* 3)使用 sql 的唯一标志来告诉 MyBatis 执行哪个 sql,sql都是保存在 sql 映射文件中的
*/
//新版本常用的方式:接口式编程
/*
* 1、接口式编程
* 原生: Dao ====> DaoImpl
* mybatis: Mapper ====> xxMapper.xml
*
* 2、SqlSession代表和数据库的一次会话;用完必须关闭;
* 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。
* 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
* (将接口和xml进行绑定)
* EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);
* 5、两个重要的配置文件:
* mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
* sql映射文件:保存了每一个sql语句的映射信息:将sql抽取出来。
*
*/
@Test
public void test02() throws IOException {
// 1.获取 sqlSessionFactory 对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 2.获取 sqlSession 对象
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3.获取接口的实现类对象,会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(1);
System.out.println(mapper.getClass());
System.out.println(employee);
}finally{
openSession.close();
}
}
}
(1)在 MyBatis 中,SqlSessionFactory 接口是核心接口之一,它的主要作用是用于创建 SqlSession 实例。具体来说,SqlSessionFactory 接口有以下作用:
openSession
方法可以创建一个 SqlSession 实例。SqlSession 是与数据库交互的主要对象,它提供了执行 SQL 语句、管理事务等方法。(2)总之,SqlSessionFactory 接口是 MyBatis 框架中用于管理 SqlSession 实例的工厂,它封装了数据库连接、对象映射和事务等细节,提供了方便的 API 供开发者使用。通过 SqlSessionFactory,开发者可以获取到可用的 SqlSession 实例,从而进行与数据库的交互操作。
(1)在 MyBatis 中,SqlSession 接口是执行 SQL 语句、与数据库进行交互的主要对象,它有以下几个主要的作用:
close
方法,可以关闭 SqlSession,释放数据库连接和其他资源。(2)总之,SqlSession 是 MyBatis 中与数据库交互的核心接口,它提供了执行 SQL 语句、事务管理、对象映射和缓存管理等功能。通过 SqlSession,开发者可以有效地执行、管理和控制与数据库的交互操作。
(1)在 MyBatis 中,Executor 执行器是核心组件之一,负责处理 SQL 语句的执行,包括查询、插入、更新和删除等操作。Executor 在执行 SQL 语句之前会先对 SQL 语句进行解析,并将解析得到的 SQL 语句传递给底层的 JDBC 驱动程序执行。
(2)MyBatis 提供了三种类型的 Executor 执行器:
SimpleExecutor
:每次执行都会创建一个新的 Statement 对象,并直接执行 SQL 语句,执行完毕后关闭 Statement 对象。ReuseExecutor
:在相同的 SQL 语句被多次执行时,会复用先前创建的 Statement 对象,而不是每次都创建新的 Statement 对象。在执行完毕后,会将 Statement 对象缓存起来,以供下次使用。BatchExecutor
:批量执行 SQL 语句,将多个 SQL 语句打包成一个批量请求,一次性发送给数据库执行。这种方式可以减少网络传输的开销,提高性能。(3)在默认情况下,MyBatis 会使用 ReuseExecutor 执行器,这种执行器可以有效地缓存 Statement 对象,避免重复创建,提高性能。但是,如果 SQL 语句执行的不是很频繁,或者需要执行的 SQL 语句的参数比较复杂,那么可能会造成缓存带来的性能损失。此时,可以考虑使用 SimpleExecutor 执行器或者关闭缓存功能。
(1)在 MyBatis 中,可以通过配置文件或者代码来指定使用哪一种 Executor 执行器。以下是两种常用的方式:
mybatis-config.xml
)中,可以通过
标签来配置使用的执行器类型。典型的配置项是
,其中 defaultExecutorType
用于指定默认的执行器类型,SIMPLE
表示简单执行器。你可以将 value
改为其他值,如 REUSE
表示可重用执行器,BATCH
表示批处理执行器等。下面是一个示例:<configuration>
<settings>
<setting name="defaultExecutorType" value="REUSE"/>
settings>
configuration>
Configuration
类中的 setDefaultExecutorType
方法来设置。在下面的示例中,首先创建一个 Configuration
对象,并通过 setDefaultExecutorType
方法设置执行器类型为 REUSE
。然后使用 SqlSessionFactoryBuilder
构建 SqlSessionFactory
对象时,将创建的 Configuration
对象传递进去。Configuration configuration = new Configuration();
configuration.setDefaultExecutorType(ExecutorType.REUSE);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(configuration);
(2)通过上述方式,你可以指定使用哪一种 Executor 执行器来执行 SQL 语句。根据实际需求,选择合适的执行器类型可以提高查询性能或满足特定的事务需求。
(1)在 MyBatis 中,DAO (Data Access Object) 接口是用于定义数据访问方法的接口,它的工作原理是将接口中的方法与映射文件中的 SQL 语句进行绑定,从而实现数据访问。
(2)具体来说,MyBatis 将 DAO 接口中的方法与映射文件中的 SQL 语句的 id 相对应,通过反射机制动态生成 DAO 接口的实现类,并将映射文件中的 SQL 语句和方法绑定在一起。这样,在执行 DAO 接口中的方法时,MyBatis 就会根据方法名和参数类型找到相应的 SQL 语句,并执行该 SQL 语句,最终返回查询结果或者影响的行数。例如,下面是一个 UserDao 接口的例子:
public interface UserDao {
User findUserById(int id);
List<User> findUserByUsername(String username);
void insertUser(User user);
void updateUser(User user);
void deleteUser(int id);
}
在这个例子中,UserDao 接口定义了五个方法,分别用于查询用户、插入用户、更新用户和删除用户等操作。这些方法都对应着映射文件中的 SQL 语句,例如:
<select id="findUserById" resultType="User">
select * from user where id = #{id}
select>
<select id="findUserByUsername" resultType="User">
select * from user where username = #{username}
select>
<insert id="insertUser">
insert into user (id, username, password) values (#{id}, #{username}, #{password})
insert>
<update id="updateUser">
update user set username = #{username}, password = #{password} where id = #{id}
update>
<delete id="deleteUser">
delete from user where id = #{id}
delete>
在这些 SQL 语句中,#{id}、#{username}、#{password} 等都是占位符,用于接收方法中的参数。当执行 UserDao 接口中的方法时,MyBatis 将会将占位符替换成实际的参数值,并执行相应的 SQL 语句,最终返回查询结果或者影响的行数。
需要注意的是:MyBatis 中的 DAO 接口并不需要实现类,而是通过动态代理来创建 DAO 接口的实例。因此,在使用 DAO 接口时,需要通过 MyBatis 的配置文件来指定映射文件的位置,并获取 DAO 接口的实例。
(3)Mybatis 的 Dao 接口可以有多个重载方法,但是多个接口对应的映射必须只有一个,即 XML 中的 id 不允许重复,否则启动会报错。
(1)在 MyBatis 中,获取插入数据之后的主键 id 的方式通常有以下两种:
useGeneratedKeys="true" keyProperty="id"
来自动获取主键 id,其中 id 是对应的实体类中主键字段的属性名。这样,在插入数据成功之后,MyBatis 会将生成的主键值自动赋值到对应的实体类中,并返回插入的行数。
<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
insert into tbl_employee(last_name,email,gender)
values (#{last_name},#{email},#{gender})
insert>
(2)需要注意的是,在使用自增主键或序列时,需要保证数据库中对应的表中已经存在主键或序列。否则,在插入数据时可能会出现错误。同时,MyBatis 也支持其他的主键生成方式,如使用 UUID、Snowflake 算法等,具体可以根据业务需求进行选择。
(1)延迟加载指在需要使用某个关联对象时才真正去查询数据库获取该对象。延迟加载可以减少不必要的数据库查询,提高查询性能。MyBatis 中主要通过两种方式实现:
lazyLoadingEnabled
为 true,然后使用 select 标签来定义关联查询,即可实现延迟加载。resultMap
标签的 association 或 collection 标签来定义延迟加载的属性,然后设置 lazyLoadingEnabled
为 true 即可。(2)MyBatis 延迟加载的实现原理是使用动态代理,对关联对象生成一个代理对象,在需要使用该对象时再去执行真正的查询。具体实现分为两种情况:
(1)首先,#{} 和 ${} 是 Mybatis 中提供的两种占位符语法,都是用来实现动态 SQL 的方式,通过这两种方式可以把参数传递到 XML 文件或注解中,在执行操作之前,Mybatis 会对这 2 个占位符动态地进行解析,但它们之间也存在一些区别:
#{}
:#{}
使用预编译参数的方式进行替换,相当于向 PreparedStatement 的里面的预处理语句设置参数,并且会将参数值进行自动类型转换,并使用安全的方式绑定到 SQL 语句中。这种方式可以预防 SQL 注入攻击,并且能够处理特殊字符的转义和防止数据类型错误。${}
:${}
使用字符串替换的方式,仅仅将 ${}
中的内容直接替换成对应的值,没有预编译过程。这种方式适用于简单的字符串替换和简单的表达式计算,但会增加安全风险。#{}
更安全:#{}
能够防止 SQL 注入攻击,因为参数值会被预编译和转义,不会将参数值作为用户输入的一部分直接拼接到 SQL 语句中。${}
存在安全风险:${}
直接进行字符串替换,存在 SQL 注入风险。如果 ${}
中的值来自用户输入,需要额外谨慎处理和验证。#{}
自动类型转换:#{}
可以根据参数类型进行自动类型转换,将参数值按照合适的方式绑定到 SQL 语句中。${}
没有类型转换:${}
只是简单的字符串替换,不会对参数值进行类型转换。(2)所以在实际应用中尽可能地使用 #{},不过在一些特殊场景下需要用到 ${},例如:
${}
进行替换。这是因为表名和列名无法使用预编译参数 #{}
来动态绑定。例如:SELECT * FROM ${tableName}
${}
。因为 #{}
只支持参数绑定,无法直接进行表达式计算。例如:<if test="${age} > 18">
SELECT * FROM users
if>
有关 SQL 注入攻击的具体知识可以查看 SQL 注入攻击介绍这篇文章。
(1)除了常见的 select、insert、update、delete 标签之外,MyBatis 映射文件中还有以下常用标签:
(2)除了上述标签之外,MyBatis 还有一些其他标签,如 cache 用于定义二级缓存,selectKey 用于在插入语句执行后获取生成的主键值等。不同的标签可以组合使用,以实现更加复杂的数据访问逻辑。
(1)在 MyBatis 中,resultMap
和 resultType
是用于处理查询结果映射的两种方式:
resultMap
:resultMap
是一种高级映射方式,通过自定义配置映射规则将查询结果集中的列映射到目标对象的属性上。通过使用 resultMap
可以实现复杂的对象关系映射,支持关联查询和嵌套查询,可以做到灵活的结果集处理和对象封装。resultMap
的配置信息包括列名、属性名、Java 类型、映射关系等。例如:<resultMap id="userMap" type="User">
<id property="id" column="user_id" />
<result property="name" column="user_name" />
<result property="age" column="user_age" />
resultMap>
resultType
:resultType
是一种简单的映射方式,直接将查询结果集中的列映射到 Java 对象的属性上,不支持复杂的关联查询和嵌套查询。resultType
的配置信息是一个具体的 Java 类型,将查询结果自动映射到该类型的对象中。例如:<resultType type="User" />
(2)它们区别总结如下:
resultMap
适合处理复杂映射关系,支持关联查询和嵌套查询,可以灵活地配置映射规则,适用于结果集与对象之间的复杂映射。resultType
简单方便,适用于结果集与对象之间的简单映射,不支持复杂的关联查询和嵌套查询。在实际应用中,根据查询的复杂度和对象关系,选择合适的映射方式来处理查询结果,可以更好地满足业务需求。
(1)在 MyBatis 中,SQL ID 和命名空间是用来标识一个 SQL 语句的两个重要属性。
SQL ID
是指一个 SQL 语句在其所在的 Mapper 接口或 XML 映射文件中的标识符,用于唯一标识一个映射文件中的 SQL 语句。在 Mapper 接口中,SQL ID 就是接口中的方法名,在 XML 映射文件中,SQL id 通过 select、insert、update、delete 等标签的 id 属性指定。(2)在 MyBatis 中,SQL ID 和命名空间的重复是不允许的,重复的 SQL ID 或命名空间会导致配置错误。每个 SQL ID 在同一命名空间下应该是唯一的,而不同命名空间之间可以有相同的 SQL ID。这种设计使得 MyBatis 可以更加规范和清晰地组织 SQL 语句,并且可以避免 SQL 语句冲突和混乱。
(1)MyBatis 可以映射 Enum 枚举类。在 MyBatis 的映射文件中,可以使用 Enum 的名称或者是 Enum 的全限定类名来指定 Enum 类型的参数。例如,使用 ${EnumName} 或者是 ${EnumClass.ENUM_NAME} 来引用 Enum 类型的参数。在映射文件中,可以使用 typeHandler
属性来指定 Enum 类型的处理器,MyBatis 提供了默认的 EnumTypeHandler
处理器,用于将 Enum 类型映射为数据库中的相应类型。
(2)例如,在映射文件中定义一个枚举类型的字段:
<resultMap id="personMap" type="Person">
<result column="gender" property="gender" javaType="GenderEnum" />
resultMap>
然后定义对应的 GenderEnum:
public enum GenderEnum {
MALE,
FEMALE
}
在查询时,可以通过参数指定相应的 GenderEnum:
<select id="selectPersonByGender" resultMap="personMap">
select * from person where gender = #{gender, jdbcType=VARCHAR, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
select>
这样,就可以将查询结果映射为相应的 GenderEnum 类型。
(1)在 MyBatis 中,可以通过 @Column
注解或 XML 配置来映射 String 类型的属性到数据库中的 varchar 字段:
public class User {
@Column(name = "username")
private String username;
// getter and setter
}
<resultMap id="userResultMap" type="User">
<id property="id" column="id" />
<result property="username" column="username" jdbcType="VARCHAR" />
resultMap>
(2)在上述示例中,我们将 User 类中的 username
属性映射到了数据库表中的 varchar
字段。使用注解方式时,可以使用 @Column
注解指定数据库字段名;使用 XML 配置方式时,可以在
元素内指定 column
属性,并指定 jdbcType
为 VARCHAR
。值得注意的是,MyBatis 默认情况下会根据 Java 对象的属性名和数据库表的列名进行自动映射,所以如果属性名与数据库列名保持一致,可以省略字段名的指定。
(3)另外,如果数据库表中的字段类型与 Java 对象的属性类型不完全一致,MyBatis 会进行自动类型转换。在上述示例中,String 类型的属性会被映射到 varchar 字段,如果数据库字段类型为其他字符串类型(例如 text),MyBatis 也会进行自动转换。但如果数据库字段类型为数字类型(如 int)时,可能需要进行一些特殊的配置或类型转换。
(1)如果在 MyBatis 的实体类中将一个 String 类型的属性映射到数据库中的 Integer 字段,会导致类型不匹配的错误。MyBatis 默认情况下会使用 Java 的类型和数据库的类型进行自动类型转换,但是 String 到 Integer 之间的转换无法自动进行。
(2)此时需要进行类型转换的配置。有两种方式可以解决这个问题:
TypeHandler
进行类型转换:可以自定义一个实现了 TypeHandler
接口的类型处理器,通过重写 setParameter()
和 getResult()
等方法,自定义 String 到 Integer 的转换逻辑,并在实体类的属性映射中使用 @TypeHandler
注解或在 XML 中配置
来指定使用该类型处理器,示例如下:public class StringToIntegerTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, Integer.parseInt(parameter));
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
// 根据实际情况进行逻辑处理
return String.valueOf(rs.getInt(columnName));
}
// 其他重写的 getNullableResult 方法
}
public class User {
//在实体类的属性映射中使用注解
@Column(name = "age")
@TypeHandler(StringToIntegerTypeHandler.class)
private String age;
//...
}
CAST()
或 CONVERT()
)将数据库中的 Integer 字段转换为 String 类型。示例:
<select id="getUserAge" resultType="String">
SELECT CAST(age AS CHAR) as age FROM user WHERE id = #{id}
select>
<select id="getUserAge" resultType="String">
SELECT CONVERT(age, CHAR) as age FROM user WHERE id = #{id}
select>
(1)MyBatis 将所有 XML 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 XML 映射文件中,有以下映射关系:
、
、
和
标签中定义的 SQL 语句,会映射为 MyBatis 内部的 MappedStatement
对象,其中包含了 SQL 语句的信息,如 ID、参数映射、结果映射等。
标签中的属性,会映射为 MyBatis 内部的 ParameterMapping
对象。ParameterMapping
对象包含了参数的名称、类型、模式(输入、输出等)等信息。
标签和
标签,会映射为 MyBatis 内部的 ResultMap
对象和 ResultMapping
对象。ResultMap
对象包含了结果映射的信息,如 ID、结果类型、属性映射等,而 ResultMapping
对象包含了具体的结果映射信息,如列名、属性名称、类型处理器等。
标签中的缓存配置信息,会映射为 MyBatis 内部的 Cache
对象。Cache
对象用于管理查询结果的缓存,提高查询性能。(2)通过这种方式,MyBatis 可以将 XML 映射文件中的 SQL 语句、参数映射和结果映射等信息转化为 MyBatis 内部对应的数据结构,从而实现 SQL 的执行和结果的映射。这种映射关系使得开发人员可以使用 XML 配置文件来定义和管理 SQL 语句,同时利用 MyBatis 的内部机制来完成 SQL 的执行与结果处理。
(1)MyBatis 支持两种分页方式:物理分页和逻辑分页:
(2)对于基于物理分页,MyBatis 提供了一种名为分页插件 (PageHelper
) 的机制来实现分页。分页插件的原理是通过动态修改 SQL 语句,在原始 SQL 语句中添加 limit 和 offset 子句,从而实现分页。具体来说,分页插件会在执行查询语句前,将原始 SQL 语句中的 limit 和 offset 替换成实际的分页参数,例如:
<select id="findUserByUsername" resultType="User">
select * from user where username = #{username} limit #{offset}, #{limit}
select>
在上述 SQL 语句中,#{offset} 和 #{limit} 分别代表分页查询的起始位置和每页数据的数量。当执行该 SQL 语句时,分页插件会根据传入的参数来动态生成 limit 和 offset 子句,从而实现分页查询。
(3)在使用分页插件 PageHelper 时,需要将分页插件添加到 MyBatis 的配置文件中,并在查询方法中传入分页参数,例如:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="dialect" value="mysql" />
plugin>
plugins>
// 查询用户列表,并进行分页
public List<User> findUserByUsername(String username, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
return userDao.findUserByUsername(username);
}
在上述代码中,通过 PageHelper.startPage()
方法设置分页参数,并调用 userDao.findUserByUsername()
方法执行分页查询。PageHelper 会在执行查询方法时,根据传入的分页参数自动添加 limit 和 offset 子句,从而实现分页查询。
需要注意的是:分页插件是一种实现分页的机制,它并不是 MyBatis 的核心功能。因此,在使用分页插件时,需要选择稳定的版本,并根据实际需求来配置分页参数,以保证分页查询的效率和准确性。
(1)MyBatis 的插件 (Interceptor) 是 MyBatis 中提供的一种扩展机制,可以在 SQL 执行前后、结果集处理前后等不同的阶段对 MyBatis 的核心功能进行增强或修改。插件可以用于实现自定义的功能,如日志记录、性能监控、权限控制等。
(2)插件的运行原理是基于 Java 的动态代理机制。当 MyBatis 执行 SQL 语句时,MyBatis 会将 SQL 语句交给 Executor
对象进行处理。在执行 SQL 语句前,MyBatis 会依次将 Executor 对象和所有的 Interceptor 对象进行包装。Interceptor 对象会按照配置的顺序依次执行,可以在 SQL 执行前后、结果集处理前后等不同的阶段进行自定义处理。最后,Executor 对象执行 SQL 语句,并返回结果。
(3)在执行过程中,Interceptor 对象通过动态代理机制,将 Executor 对象进行包装,并在 Executor 对象的方法执行前后进行自定义处理。例如,在执行 SQL 语句前可以记录 SQL 执行日志,在执行 SQL 语句后可以进行性能统计,对返回结果进行加工等。Interceptor 对象对 Executor 对象的包装,类似于装饰器模式,可以实现对 Executor 对象的无侵入式扩展。
(4)自定义插件的一般步骤:
Interceptor
接口,并实现其中的方法;import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.util.Properties;
//完成插件签名:告诉 MyBatis 当前插件用来拦截哪个对象的哪个方法
@Intercepts(
{
@Signature(type=StatementHandler.class, method="parameterize",args=java.sql.Statement.class)
})
public class MyFirstPlugin implements Interceptor {
//intercept:拦截目标对象的目标方法的执行
@Override
public Object intercept(Invocation invocation) throws Throwable {
//执行目标方法
Object proceed = invocation.proceed();
//返回执行后的返回值
return null;
}
// plugin: 包装目标对象的,包装:为目标对象创建一个代理对象
@Override
public Object plugin(Object target) {
//我们可以借助 Plugin 的 wrap 方法来使用当前 Interceptor 包装我们目标对象
System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
Object wrap = Plugin.wrap(target, this);
//返回为当前target创建的动态代理
return wrap;
}
//setProperties:将插件注册时的 property 属性设置进来
@Override
public void setProperties(Properties properties) {
System.out.println("插件配置的信息:"+properties);
}
}
<plugins>
<plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin">
<property name="username" value="root"/>
<property name="password" value="123456"/>
plugin>
plugins>
(1)MyBatis 的缓存机制可以分为一级缓存和二级缓存两个层级:
SQL Session
内部有效。Mapper
接口的。
标签,并在 Mapper 接口上添加 @CacheNamespace
注解或者在映射文件中配置
标签。
标签进行二级缓存的配置,可以指定缓存的类型(如 FIFO、LRU、LRU-Soft、Soft)和大小等参数来进行详细的配置。需要注意的是,缓存是有一定的开销的,使用缓存的同时要考虑数据一致性的问题。在某些情况下,可能需要手动清空缓存或者关闭缓存功能,以保证数据的正确性。
(2)二级缓存是在不同的 SQL Session 之间共享的缓存,它的工作机制可以概括为以下几个步骤:
标签进行配置,指定缓存的类型(如 FIFO、LRU、LRU-Soft、Soft)和大小等参数。可以根据具体需求来调整缓存的策略和行为。需要注意的是,二级缓存是基于 Mapper 接口的作用域的,不同的 Mapper 接口之间的缓存是隔离的。而且,在多个应用程序实例中使用二级缓存时,需要考虑缓存的共享和数据一致性的问题。