文章目录
一、SQL自动注入器AutoSqlInjector
根据 MybatisPlus 的 AutoSqlInjector 可以自定义各种你想要的 sql ,注入到全局中,相当于自定义 Mybatisplus 自动注入的方法。
之前需要在 xml 中进行配置的 SQL 语句,现在通过扩展 AutoSqlInjector 在加载 mybatis 环境时就注入。
1、在 Mapper 接口中定义相关的 CRUD 方法
public interface EmployeeMapper extends BaseMapper<Employee> {
int deleteAll();
}
2、扩展 AutoSqlInjector inject 方法,实现 Mapper 接口中方法要注入的 SQL
package com.ming.mp.injector;
import com.baomidou.mybatisplus.entity.TableInfo;
import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;
/**
* 自定义全局 sql注入操作
*/
public class MySqlInject extends AutoSqlInjector {
@Override
public void inject(Configuration configuration, MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo table) {
super.inject(configuration, builderAssistant, mapperClass, modelClass, table);
//Mapper接口中定义的方法deleteAll()处理成MappedStatement对象、加入到configuration中
//1.注入SQL语句
String sql = "delete from " +table.getTableName();
//2.注入的方法名 与mapper接口中的方法名一致
String sqlMethod = "deleteAll";
//3.构建sqlSource对象
SqlSource sqlSource = languageDriver.createSqlSource(configuration,sql,modelClass);
//4.构建删除的MappedStatement对象
this.addDeleteMappedStatement(mapperClass,sqlMethod,sqlSource);
}
}
3、在MP全局策略中、配置自定义注入器
<!-- 定义MybatisPlus的全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
<property name="dbColumnUnderline" value="true"></property>
<!-- 全局的主键策略 -->
<property name="idType" value="0"></property>
<!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
<!--注入自定义的全局操作-->
<property name="sqlInjector" ref="mySqlInject"/>
</bean>
<!--自定义SQL注入器-->
<bean id="mySqlInject" class="com.ming.mp.injector.MySqlInject"/>
测试:
private ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
private EmployeeMapper employeeMapper = context.getBean("employeeMapper",EmployeeMapper.class);
@Test
public void testSqlInjector(){
int i = employeeMapper.deleteAll();
System.out.println(i);
}
报错:
Caused by: com.baomidou.mybatisplus.exceptions.MybatisPlusException: com.baomidou.mybatisplus.exceptions.MybatisPlusException: Error: Full table operation is prohibited. SQL: delete from tbl_employee
at com.baomidou.mybatisplus.plugins.SqlExplainInterceptor.sqlExplain(SqlExplainInterceptor.java:131)
at com.baomidou.mybatisplus.plugins.SqlExplainInterceptor.intercept(SqlExplainInterceptor.java:86)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy19.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
at com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor.intercept(OptimisticLockerInterceptor.java:71)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy19.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
at com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor.intercept(OptimisticLockerInterceptor.java:71)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy19.update(Unknown Source)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
... 34 more
报错原因:因为使用了注册执行分析插件,将他注释掉
<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
<!--作用就是我发现了当前你的操作是全表删除或更新、会阻止你的操作-->
<property name="stopProceed" value="true"/>
</bean>
MP启动的时候会加载MappedStatement
DEBUG 06-08 22:58:57,285 addMappedStatement: com.ming.mp.mapper.EmployeeMapper.deleteAll (MybatisConfiguration.java:67)
二、自定义注入器的应用之逻辑删除
假删除、逻辑删除:并不会真正的从数据库中将数据删除掉,而是将当前被删除的这条数据中的一个逻辑删除字段置为删除状态
update tbl_user set logic_flag = 1 → -1
步骤:
1、com.baomidou.mybatisplus.mapper.LogicSqlInjector
<!-- 定义MybatisPlus的全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
<property name="dbColumnUnderline" value="true"></property>
<!-- 全局的主键策略 -->
<property name="idType" value="0"></property>
<!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
<!--注入自定义的全局操作-->
<!-- <property name="sqlInjector" ref="mySqlInject"/>-->
<!--注入逻辑删除-->
<property name="sqlInjector" ref="logicSqlInjector"/>
</bean>
<!--逻辑删除-->
<bean id="logicSqlInjector" class="com.baomidou.mybatisplus.mapper.LogicSqlInjector"/>
<!--自定义SQL注入器-->
<bean id="mySqlInject" class="com.ming.mp.injector.MySqlInject"/>
2、logicDeleteValue 逻辑删除全局值
<!-- 逻辑删除全局值为-1-->
<property name="logicDeleteValue" value="-1"></property>
3、logicNotDeleteValue 逻辑未删除全局值
<!-- 定义MybatisPlus的全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
<property name="dbColumnUnderline" value="true"></property>
<!-- 全局的主键策略 -->
<property name="idType" value="0"></property>
<!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
<!--注入SQL自定义的全局操作-->
<!-- <property name="sqlInjector" ref="mySqlInject"/>-->
<!--注入逻辑删除-->
<property name="sqlInjector" ref="logicSqlInjector"/>
<!--注入逻辑删除的全局值-->
<!-- 逻辑删除全局值为-1就是删除状态-->
<property name="logicDeleteValue" value="-1"></property>
<!--逻辑未删除全局值为1未删除状态-->
<property name="logicNotDeleteValue " value="1"></property>
</bean>
4、在 POJO 的逻辑删除字段 添加 @TableLogic 注解
public class User {
private Integer id;
private String name;
@TableLogic
private Integer logicFlag;//逻辑删除属性
}
5、会在 mp 自带查询和更新方法的 sql 后面,追加[逻辑删除字段]=[LogicNotDeleteValue默认值]
删除方法: deleteById()和其他 delete 方法, 底层 SQL 调用的是 update tbl_XXX set [逻辑删除字段] =[LogicNotDeleteValue默认值]
逻辑删除测试
@Test
public void testLogicDelete(){
int i = userMapper.deleteById(1);
System.out.println(i);
}
DEBUG 06-08 23:52:15,864 ==> Preparing: UPDATE tbl_user SET logic_flag=-1 WHERE id=? (BaseJdbcLogger.java:159)
DEBUG 06-08 23:52:15,884 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159)
DEBUG 06-08 23:52:15,886 <== Updates: 1 (BaseJdbcLogger.java:159)
Time:6 ms - ID:com.ming.mp.mapper.UserMapper.deleteById
Execute SQL:
UPDATE
tbl_user
SET
logic_flag=-1
WHERE
id=1]
DEBUG 06-08 23:52:15,890 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@769a1df5] (SqlSessionUtils.java:191)
DEBUG 06-08 23:52:15,890 Returning JDBC Connection to DataSource (DataSourceUtils.java:327)
1
逻辑删除后–查询测试查询不到结果的
@Test
public void testLogicDelete(){
// int i = userMapper.deleteById(1);
// System.out.println(i);
User user = userMapper.selectById(1);
System.out.println(user);
}
DEBUG 06-08 23:58:59,350 ==> Preparing: SELECT id,`name`,logic_flag AS logicFlag FROM tbl_user WHERE id=? AND logic_flag=1 (BaseJdbcLogger.java:159)
DEBUG 06-08 23:58:59,370 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159)
DEBUG 06-08 23:58:59,378 <== Total: 0 (BaseJdbcLogger.java:159)
Time:11 ms - ID:com.ming.mp.mapper.UserMapper.selectById
Execute SQL:
SELECT
id,
`name`,
logic_flag AS logicFlag
FROM
tbl_user
WHERE
id=1
AND logic_flag=1]
DEBUG 06-08 23:58:59,381 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@769a1df5] (SqlSessionUtils.java:191)
DEBUG 06-08 23:58:59,381 Returning JDBC Connection to DataSource (DataSourceUtils.java:327)
null
三、公共字段填充
1、实现元对象处理器接口
com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
公共字段填充:比如我们插入修改操作有一些字段没有提供值,我们希望有一些默认的值填充上去
public abstract void insertFill(MetaObject metaObject);
public abstract void updateFill(MetaObject metaObject);
MetaObject :元对象、它是mybatis提供的一个用于更加方便访问对象的属性、给对象的属性设置值的一个对象。还会用于包装我们的对象,支持object,mapper,collection对象等进行包装
本质上MetaObject 获取对象的属性值,或者给对象的属性设置值是要底层最终要通过rflector反射获取我们属性对应的方法的Invoker,最终Invoker.
2、开发步骤
1、注解填充字段注解填充字段 @TableField(… fill = FieldFill.INSERT) 查看FieldFill
有时候开发的时候不会提供该字段值,我们提供一个默认值,name为公共字段填充
public class User {
private Integer id;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String name;
}
2、自定义公共字段填充处理器
package com.ming.mp.beans.metaobject;
import com.baomidou.mybatisplus.mapper.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
/**
* 自定义公共字段填充处理器
*/
public class MyMetaObject extends MetaObjectHandler {
/**
* 插入操作自动填充
*
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
//获取到需要被填充的字段值
Object fieldValByName = getFieldValByName("name", metaObject);
if (fieldValByName == null) {
System.out.println("*********插入操作,满足填充条件**********");
setFieldValByName("name","公共字段填充的名字",metaObject);
}
}
/**
* 修改操作自动填充
*
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
//获取到需要被填充的字段值
Object fieldValByName = getFieldValByName("name", metaObject);
if (fieldValByName == null) {
System.out.println("*********修改操作,满足填充条件**********");
setFieldValByName("name","公共字段填充的名字",metaObject);
}
}
}
3、MP全局注入 自定义公共字段填充处理器
<!-- 定义MybatisPlus的全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
<property name="dbColumnUnderline" value="true"></property>
<!-- 全局的主键策略 -->
<property name="idType" value="0"></property>
<!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
<!--注入自定义的全局操作-->
<!-- <property name="sqlInjector" ref="mySqlInject"/>-->
<!--注入逻辑删除-->
<property name="sqlInjector" ref="logicSqlInjector"/>
<!--注入逻辑删除的全局值-->
<!-- 逻辑删除全局值为-1就是删除状态-->
<property name="logicDeleteValue" value="-1"></property>
<!--逻辑未删除全局值为1未删除状态-->
<property name="logicNotDeleteValue" value="1"></property>
<!--注入自定义公共字段填充处理器-->
<property name="metaObjectHandler" ref="myMetaObject"/>
</bean>
<!--自定义公共字段填充处理器-->
<bean id="myMetaObject" class="com.ming.mp.beans.metaobject.MyMetaObject"/>
测试:插入的name字段是我们定义的公共字段填充的值、
@Test
public void testMetaObjectHandler() {
User user = new User();
user.setLogicFlag(1);
userMapper.insert(user);
}
DEBUG 06-09 22:45:09,072 Fetching JDBC Connection from DataSource (DataSourceUtils.java:110)
DEBUG 06-09 22:45:09,072 JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6ca18a14 [wrapping: com.mysql.jdbc.JDBC4Connection@c667f46]] will not be managed by Spring (SpringManagedTransaction.java:87)
DEBUG 06-09 22:45:09,076 ==> Preparing: INSERT INTO tbl_user ( `name`, logic_flag ) VALUES ( ?, ? ) (BaseJdbcLogger.java:159)
DEBUG 06-09 22:45:09,097 ==> Parameters: 公共字段填充的名字(String), 1(Integer) (BaseJdbcLogger.java:159)
DEBUG 06-09 22:45:09,100 <== Updates: 1 (BaseJdbcLogger.java:159)
Time:8 ms - ID:com.ming.mp.mapper.UserMapper.insert
Execute SQL:
INSERT
INTO
tbl_user
( `name`, logic_flag )
VALUES ( '公共字段填充的名字', 1 )]
四、oracle主键Sequence(序列)
mysql支持注解自增、oracle不支持主键自增、Sequence序列去做主键自增
<!--oracle驱动:因为oracle授权问题,不能从Maven仓库中下载到Oracle驱动-->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.4.0</version>
</dependency>
1、实体类配置主键Sequence、 @KeySequence(value = “序列名”,clazz = Integer.class 主键属性类型)
//Oracle主键自增
@KeySequence(value = "seq_user",clazz = Integer.class)
public class User {
private Integer id;
}
2、全局MP主键生成策略为IdType.INPUT
实体类主键上配置
@KeySequence(value = "序列名",clazz = Integer.class)
public class User {
@TableId(type = IdType.INPUT)
private Integer id;
}
racle全局的主键策略
<!-- 定义MybatisPlus的全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
<property name="dbColumnUnderline" value="true"></property>
<!-- oracle全局的主键策略 -->
<property name="idType" value="1"></property>
3、全局MP中配置oracle注解Sequence com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
<!--配置oracle主键sequence-->
<bean id="oracleKeyGenerator" class="com.baomidou.mybatisplus.incrementer.OracleKeyGenerator"/>
<!-- 定义MybatisPlus的全局策略配置-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<!-- 在2.3版本以后,dbColumnUnderline 默认值就是true 表名、字段名、是否使用下划线命名(默认 true: 数据库下划线命名) -->
<property name="dbColumnUnderline" value="true"></property>
<!-- 全局的主键策略 -->
<property name="idType" value="0"></property>
<!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
<!--注入自定义的全局操作-->
<!-- <property name="sqlInjector" ref="mySqlInject"/>-->
<!--注入逻辑删除-->
<property name="sqlInjector" ref="logicSqlInjector"/>
<!--注入逻辑删除的全局值-->
<!-- 逻辑删除全局值为-1就是删除状态-->
<property name="logicDeleteValue" value="-1"></property>
<!--逻辑未删除全局值为1未删除状态-->
<property name="logicNotDeleteValue" value="1"></property>
<!--注入自定义公共字段填充处理器-->
<property name="metaObjectHandler" ref="myMetaObject"/>
<!--oracle主键生成策略配置-->
<property name="keyGenerator" ref="oracleKeyGenerator"/>
</bean>
4、可以将@KeySequence定义在父类中、可实现多个子类对应的多个表公用一个Sequence
多个实体类公用一个序列实现主键自增
@KeySequence(value = "seq_user",clazz = Integer.class)
public abstract class Parent {
}
//Oracle主键自增
//@KeySequence(value = "序列名",clazz = Integer.class)
public class User extends parent{
//@TableId(type = IdType.INPUT)
private Integer id;
}
五、idea的快速开发插件
Mybatisx辅助idea快速开发
可以实现java与xml跳转、根据mapper中的方法自动生成xml结构
在线安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。
jar安装: File -> Settings -> Plugins ->install plugins from disk…选中mybatisx.jar安装