一、定义
MyBatis是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
官网:https://mybatis.org/mybatis-3/zh_CN/index.html
二、核心概念
1、SqlSessionFactoryBuilder
2、SqlSessionFactory
3、SqlSession
4、插件
(1)定义
MyBatis允许通过使用插件在映射语句执行过程中的某一点进行拦截。
默认情况下,MyBatis允许使用插件来拦截的方法调用有:
A、Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)(执行器拦截器)
允许拦截和自定义MyBatis执行器的行为。例如,可以添加缓存、日志记录或审计功能到执行器中。这些拦截器可以在MyBatis执行的不同阶段扩展或修改其行为。您可以通过实现MyBatis提供的相应接口并在MyBatis配置文件中进行配置来实现这些拦截器
B、ParameterHandler (getParameterObject, setParameters)(参数拦截器)
允许在将参数设置到SQL语句之前修改或验证它们。例如,可以对作为参数传递的敏感信息进行加密或解密。
C、ResultSetHandler (handleResultSets, handleOutputParameters)(结果集拦截器)
可以在将结果集返回给应用程序之前修改或分析它们。例如,可以对结果集数据进行转换或执行额外的计算。
D、StatementHandler (prepare, parameterize, batch, update, query)(语句拦截器)
可以在SQL语句执行之前修改或增强它们。例如,可以向WHERE子句添加额外的条件或记录执行的语句。分页等
(2)自定义插件
在MyBatis中,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可对某个方法进行拦截。
A、Executor方法的拦截
示例代码:对query执行过程的拦截
@Intercepts({@Signature(type= Executor.class,method="query",args={MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class })})
public class QueryExecutorPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 执行query方法
Object obj=invocation.proceed();
// 修改执行结果
List<Object> list= JSONUtil.parseArray(obj);
list.add(new Category().setName("测试插件1"));
return list;
}
@Override
public Object plugin(Object target) {
// 包装目标对象的:包装:为目标对象创建一个代理对象
return Interceptor.super.plugin(target);
}
@Override
public void setProperties(Properties properties) {
// 将插件注册时的property属性设置进来
Interceptor.super.setProperties(properties);
}
}
B、StatementHandler方法的拦截
示例代码:对sql语句的修改
@Intercepts({@Signature(type = StatementHandler.class,method ="prepare",args = {Connection.class,Integer.class})})
public class StatementPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler= PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject= SystemMetaObject.forObject(statementHandler);
BoundSql boundSql= (BoundSql) metaObject.getValue("delegate.boundSql");
String originSql=boundSql.getSql();
System.out.println("原始sql:"+originSql);
// 对原始sql进行改写
metaObject.setValue("delegate.boundSql.sql",originSql.replace("?","8888888"));
return invocation.proceed();
}
}
或者
@Intercepts({@Signature(type = StatementHandler.class,method ="prepare",args = {Connection.class,Integer.class})})
public class StatementPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler= (StatementHandler) invocation.getTarget();
BoundSql boundSql= statementHandler.getBoundSql();
String originSql=boundSql.getSql();
System.out.println("原始sql:"+originSql);
// 直接对原始sql进行改写
ReflectUtil.setFieldValue(boundSql,"sql",originSql.replace("?","9878948"));
return invocation.proceed();
}
}
C、ParameterHandler方法的拦截
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)})
public class ParameterPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 修改参数值
return null;
}
}
D、ResultSetHandler方法的拦截
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class)})
public class ResultSetPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 修改结果集
return null;
}
}
E、测试
a、添加插件
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(){
DriverManagerDataSource dataSource=new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://xxx:xxx/xxx?characterEncoding=utf-8&useSSL=false");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
org.apache.ibatis.session.Configuration config=new org.apache.ibatis.session.Configuration(environment);
config.addMapper(CategoryMapper.class);
// 添加插件
config.addInterceptor(new QueryExecutorPlugin());
config.addInterceptor(new ParameterPlugin());
config.addInterceptor(new StatementPlugin());
return new SqlSessionFactoryBuilder().build(config);
}
}
b、测试代码
public class TestMyBatis {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(MyBatisConfig.class);
SqlSessionFactory factory= (SqlSessionFactory) context.getBean("sqlSessionFactory");
try(SqlSession sqlSession=factory.openSession()){
CategoryMapper categoryMapper=sqlSession.getMapper(CategoryMapper.class);
categoryMapper.insert(new Category().setName("222222"));
List<Category> list=categoryMapper.selectList();
System.out.println(JSONUtil.toJsonPrettyStr(list));
sqlSession.commit();// 默认mybatis是不会自动提交的,需要手动自动提交修改才会生效
}
}
}
5、类型转换器TypeHandler
(1)常用的TypeHandler
(2)自定义TypeHandler
可以通过继承BaseTypeHandler来自定义TypeHandler
三、使用
1、Spring使用MyBatis
(0)数据库中已存在category表
(1)引入依赖
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.16</version>
</dependency>
(2)编写配置类MyBatisConfig
@ComponentScan(basePackages = "org.example.mybatis")
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(){
DriverManagerDataSource dataSource=new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://xxx:xxx/xxx?characterEncoding=utf-8&useSSL=false");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
org.apache.ibatis.session.Configuration config=new org.apache.ibatis.session.Configuration(environment);
config.addMapper(CategoryMapper.class);
return new SqlSessionFactoryBuilder().build(config);
}
}
(3)编写测试类
public class TestMyBatis {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(MyBatisConfig.class);
SqlSessionFactory factory= (SqlSessionFactory) context.getBean("sqlSessionFactory");
try(SqlSession sqlSession=factory.openSession()){
CategoryMapper categoryMapper=sqlSession.getMapper(CategoryMapper.class);
categoryMapper.insert(new Category().setName("222222"));
List<Category> list=categoryMapper.selectList();
System.out.println(JSONUtil.toJsonPrettyStr(list));
sqlSession.commit();// 默认mybatis是不会自动提交的,需要手动自动提交修改才会生效
}
}
}
四、原理
五、关于MyBatisPlus
1、定义
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。