• MyBatis-Plus(2.0)


    ActiveRecord

    ActiveRecord(简称AR)一直广受动态语言(PHP、Ruby等)的喜爱,而java作为准静态语言,对于ActiveRecord往往只能感叹器优雅

    什么是ActiveRecord?

    ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的实现模型的操作,而且简洁易懂

    ActiveRecord的主要思想是:

    • 每一个数据库表对应创建一个类,类的每个对象实例对应于数据库表的一行记录;通常表的每个字段在类中都有相应的Field
    • ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CRUD
    • ActiveRecord是一种领域模型(Domain Model),封装了部分业务配置

    快速使用

    在MP中,开启AR非常简单,只需要将实体对象继承Model即可

    注意:先将数据库的tb_user表改为user

    将实体对象继承Model

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User extends Model<User> {
    
        private Long id;
        private String userName;
        private String password;
        private String name;
        private Integer age;
        private String email;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    根据主键查询
        @Test
        public void testAR() {
            User user = new User();
            user.setId(2L);
            User user1 = user.selectById();
            System.out.println(user1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    效果:

    img

    新增数据
        @Test
        public void testAR2() {
            User user = new User();
            user.setUserName("liubei");
            user.setAge(30);
            user.setName("刘备");
            user.setPassword("123456");
            user.setEmail("liubei@dc.cn");
            boolean insert = user.insert();
            System.out.println(insert);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    效果:

    img

    更新操作
        @Test
        public void testAR3() {
            User user = new User();
            user.setId(8L);
            user.setAge(35);
    
            boolean b = user.updateById();
            System.out.println(b);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    效果:

    img

    删除操作
        @Test
        public void testAR4() {
            User user = new User();
            user.setId(7L);
            boolean b = user.deleteById();
            System.out.println(b);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    效果:

    img

    根据条件查询
        @Test
        public void testAR5() {
            User user = new User();
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.le("age", 24);
    
            List<User> users = user.selectList(wrapper);
            for (User user1 : users) {
                System.out.println(user1);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    效果:

    img

    插件

    mybatis的插件机制

    MyBatis允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法调用包括:

    1. Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
    2. ParameterHandler(getParameterObject, setParameters)
    3. ResultSetHandler(handlerResultSets, handleOutputParameters)
    4. StatmentHandler(prepare, parameterize, batchm, update, query)

    总体概括为:

    1. 拦截执行器的方法
    2. 拦截参数的处理
    3. 拦截结果集的处理
    4. 拦截sql语法构建的处理

    拦截器示例:

    @Intercepts({
            @Signature(
            type = Executor.class,
            method = "update",
            args = {MappedStatement.class, Object.class}
        )
    })
    public class MyInterceptor implements Interceptor {
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            // 拦截方法,具体业务逻辑编写的位置
            return invocation.proceed();
        }
    
        @Override
        public Object plugin(Object o) {
            // 创建target对象的代理对象,目的是将当前拦截器加入到该对象中
            return Plugin.wrap(o, this);
        }
    
        @Override
        public void setProperties(Properties properties) {
            // 属性配置
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    拦截器配置

    @Configuration
    @MapperScan("com.dc.mapper")
    public class MybatisPlusConfig {
    
        /**
         * 分页插件
         * @param
         * @return
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    
        @Bean
        public MyInterceptor myInterceptor() {
            return new MyInterceptor();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    或者通过xml配置,MyBatis-config.xml:

    
    DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<plugins>
    		<plugin interceptor="cn.itcast.mp.plugins.MyInterceptor">plugin>
    	plugins>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    执行分析插件

    在MP中提供了对SQL执行的分页的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境

    SpringBoot配置:

    @Bean
        public SqlExplainInterceptor sqlExplainInterceptor() {
            SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
            ArrayList<ISqlParser> iSqlParsers = new ArrayList<>();
            iSqlParsers.add(new BlockAttackSqlParser());
            sqlExplainInterceptor.setSqlParserList(iSqlParsers);
    
            return sqlExplainInterceptor;
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果:

    org.apache.ibatis.exceptions.PersistenceException: 
    ### Error opening session.  Cause: org.apache.ibatis.plugin.PluginException: Could not find method on interface java.util.concurrent.Executor named update. Cause: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
    ### Cause: org.apache.ibatis.plugin.PluginException: Could not find method on interface java.util.concurrent.Executor named update. Cause: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
    
    	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    	at org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource(DefaultSqlSessionFactory.java:100)
    	at org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSession(DefaultSqlSessionFactory.java:57)
    	at org.mybatis.spring.SqlSessionUtils.getSqlSession(SqlSessionUtils.java:98)
    	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:428)
    	at com.sun.proxy.$Proxy58.update(Unknown Source)
    	at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:294)
    	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:63)
    	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:62)
    	at com.sun.proxy.$Proxy64.update(Unknown Source)
    	at com.dc.UserMapperTest.testInterceptor(UserMapperTest.java:296)
    	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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
    	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
    Caused by: org.apache.ibatis.plugin.PluginException: Could not find method on interface java.util.concurrent.Executor named update. Cause: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
    	at org.apache.ibatis.plugin.Plugin.getSignatureMap(Plugin.java:83)
    	at org.apache.ibatis.plugin.Plugin.wrap(Plugin.java:44)
    	at com.dc.interceptor.MyInterceptor.plugin(MyInterceptor.java:31)
    	at org.apache.ibatis.plugin.InterceptorChain.pluginAll(InterceptorChain.java:31)
    	at com.baomidou.mybatisplus.core.MybatisConfiguration.newExecutor(MybatisConfiguration.java:168)
    	at org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource(DefaultSqlSessionFactory.java:96)
    	... 41 more
    Caused by: java.lang.NoSuchMethodException: java.util.concurrent.Executor.update(org.apache.ibatis.mapping.MappedStatement, java.lang.Object)
    	at java.lang.Class.getMethod(Class.java:1786)
    	at org.apache.ibatis.plugin.Plugin.getSignatureMap(Plugin.java:80)
    	... 46 more
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    性能分析插件

    性能分析拦截器,用于输出每条sql语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。

    该插件只用于开发环境,不建议生产环境使用

    配置:

        <plugins>
            <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
                <property name="maxTime" value="100"/>
                <property name="format" value="true"/>
            plugin>
        plugins>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果:

    img

    可以看到执行时间为22ms,如果将maxTime设置为1,该操作会直接报错

    乐观锁插件

    主要使用场景

    意图:

    当要更新的时候,希望这条记录没有被别人更新

    乐观锁实现方式:

    • 取出记录时,获取当前version
    • 更新时,带上version
    • 执行更新时,set version = newVersion where version = oldVersion
    • 如果version不对,就更新失败

    插件配置

    config.xml:

    <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
    
    • 1

    SpringBoot:

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    	return new OptimisticLockerInterceptor();
    }
    
    • 1
    • 2
    • 3
    • 4

    注解实体字段

    需要为实体字段添加@Version注解

    第一步,为表添加version字段,并且设置初始值为1

    ALTER TABLE 'user'
    	ADD COLUMN 'version' int(10) NULL AFTER 'email';
    UPDATE 'user' SET 'version' = '1';
    
    • 1
    • 2
    • 3

    第二步,为User实体对象添加version字段,并且添加@Version注解:

    @Version
    private Integer version;
    
    • 1
    • 2

    测试用例:

        @Test
        public void testUpdate() {
            User user = new User();
            user.setAge(30);
            user.setId(2L);
            // 获取到version为1
            user.setVersion(1);
    
            int i = this.userMapper.updateById(user);
            System.out.println("result = " + i);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    执行日志:

    img

    可以看到,更新的条件中有version条件,并且更新的version为2

    如果再次执行,更新则不成功,这样就避免了多人同时更新时导致数据的不一致

    特别说明

    • 支持的数据类型只有:int,Integer,long,Date, LocalDateTime
    • 整数类型下newVersion = oldVersion + 1
    • newVersion 会回写到entity中
    • 仅支持updateById(id)与update(entity, wrapper)方法
    • 在update(entity, wrapper)方法下,wrapper不能复用!!!

    sql注入器

    在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到MyBatis容器,这样这些方法才可以正常执行

    那如果需要扩展BaseMapper中的方法,又该如何实现?

    编写MyBatisMapper

    package cn.itcast.mp.mapper;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import java.util.List;
    public interface MyBaseMapper<T> extends BaseMapper<T> {
    	List<T> findAll();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    其他的Mapper都可以继承该Mapper,这样实现了统一的扩展

    package cn.itcast.mp.mapper;
    import cn.itcast.mp.pojo.User;
    public interface UserMapper extends MyBaseMapper<User> {
    	User findById(Long id);
           List<User> findAll();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    编写MySqlInjector

    如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以选择继承DefaultSqlInjector进行扩展

    public class MySqlInjector extends DefaultSqlInjector {
    
        @Override
        public List<AbstractMethod> getMethodList() {
            List<AbstractMethod> methodList = super.getMethodList();
            methodList.add(new FindAll());
            return methodList;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    编写FindAll

    public class FindAll extends AbstractMethod {
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
            String sqlMethod = "findAll";
            String sql = "select * from " + tableInfo.getTableName();
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
            return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注册到Spring容器中

    spring.xml:

    <bean class="com.dc.injector.MySqlInjector"/>
    
    • 1

    SpringBoot:

    /**
    * 自定义SQL注入器
    */
    @Bean
    public MySqlInjector mySqlInjector(){
    	return new MySqlInjector();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试:

        @Test
        public void testFindAll() {
            List<User> all = userMapper.findAll();
            for (User user : all) {
                System.out.println(user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果

    img

    自动填充功能

    有些时候可能会有这样的需求,插入或者更新数据的时候,希望有些字段可以自动填充数据,比如密码,version等。在MP中提供了这样的功能,可以实现自动填充

    添加@TableField注解

    @TableField(fill = FieldFill.INSERT) // 插入数据时进行填充
    private String password;
    
    • 1
    • 2

    为password添加自动填充功能,在新增数据时有效

    FiledFill提供了多种模式选择:

    public enum FieldFill {
        /**
        * 默认不处理
        */
        DEFAULT,
        /**
        * 插入时填充字段
        */
        INSERT,
        /**
        * 更新时填充字段
        */
        UPDATE,
        /**
        * 插入和更新时填充字段
        */
        INSERT_UPDATE
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    编写MyMetaObjectHandler

    首先,在User实体类中添加注解

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName("tb_user")
    public class User extends Model<User> {
    
        private Long id;
        private String userName;
        @TableField(select = false, fill = FieldFill.INSERT)
        private String password;
        private String name;
        private Integer age;
        private String email;
        @Version
        private Integer version;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    然后编写MyMetaObjectHandler类

    public class MyMetaObjectHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
            Object password = getFieldValByName("password", metaObject);
            if (password == null) {
                // 字段为空,进行填充
                setFieldValByName("password", "88888888", metaObject);
            }
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    spring:最后需要在applicationContext.xml配置文件中配置插件:

    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
        
        <context:property-placeholder location="classpath:jdbc.properties">context:property-placeholder>
        
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="maxActive" value="10"/>
            <property name="minIdle" value="5"/>
        bean>
        <context:component-scan base-package="com.dc.injector"/>
        
        <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="typeAliasesPackage" value="com.dc.domain"/>
            <property name="plugins">
                <array>
                    
                    <bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"/>
                    
                    <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
                array>
            property>
            
            <property name="globalConfig" ref="globalConfig"/>
        bean>
    
        <bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
            <property name="metaObjectHandler" ref="myMetaObjectHandler"/>
        bean>
    
        <bean class="com.dc.injector.MyMetaObjectHandler" id="myMetaObjectHandler"/>
    
        <bean class="com.dc.injector.MySqlInjector"/>
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.dc.mapper"/>
        bean>
        <beans default-autowire="byType"/>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    SpringBoot:在MyMetaObjectHandler类上添加@Component注解

    测试:

    @Test
        public void testInsertFill() {
            User user = new User();
            user.setName("关羽");
            user.setUserName("guanyu");
            user.setAge(30);
            user.setEmail("guanyu@dc.cn");
            user.setVersion(1);
    
            int insert = userMapper.insert(user);
            System.out.println("result = " + insert);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果:

    img

    img

    逻辑删除

    开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。

    修改表的结构

    为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除

    alter table tb_user add COLUMN deleted int(1) null DEFAULT 0 comment '1代表删除,0代表未删除' after version;
    
    • 1

    同时,也修改User实体,增加deleted属性并且添加@TableLogic注解

    @TableLogic
    private Integer deleted;
    
    • 1
    • 2

    配置

    SpringBoot:

    # 逻辑已删除值(默认为 1)
    mybatis-plus.global-config.db-config.logic-delete-value=1
    # 逻辑未删除值(默认为 0)
    mybatis-plus.global-config.db-config.logic-not-delete-value=0
    
    • 1
    • 2
    • 3
    • 4

    测试

    @Test
    public void testDeleteById(){
    	this.userMapper.deleteById(2L);
    }
    
    • 1
    • 2
    • 3
    • 4

    结果:

    img

    测试查询:

    @Test
    public void testSelectById(){
    	User user = this.userMapper.selectById(2L);
    	System.out.println(user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果:

    img

    通用枚举

    解决了繁琐的配置,让mybatis优雅的使用枚举属性

    修改表结构

    ALTER TABLE tb_user
    ADD COLUMN sex int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER deleted;
    
    • 1
    • 2

    定义枚举

    public enum SexEnum implements IEnum<Integer> {
    
        MAN(1, "男"),
        WOMAN(2, "女");
        private int value;
        private String desc;
    
        SexEnum(int value, String desc) {
            this.value = value;
            this.desc = desc;
        }
    
        @Override
        public Integer getValue() {
            return this.value;
        }
    
        @Override
        public String toString() {
            return this.desc;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    配置:

    # 枚举包扫描
    mybatis-plus.type-enums-package=cn.itcast.mp.enums
    
    • 1
    • 2

    修改实体

    private SexEnum sex;
    
    • 1

    测试:

    @Test
    public void testInsert1() {
        User user = new User();
        user.setName("貂蝉");
        user.setUserName("diaochan");
        user.setAge(20);
        user.setEmail("diaochan@dc.cn");
        user.setSex(SexEnum.WOMAN);
    
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果:

    img

    img

    查询:

    @Test
    public void testSelect1() {
        User user = userMapper.selectById(2L);
        System.out.println(user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果:

    img

    代码生成器

    AutoGenerator是MyBatis-Plus的代码生成器,通过AutoGenerator可以快速生成Entity、Mapper、Mapper XML、Service、Controller等各个模块的代码,极大的提升了开发效率

    创建工程

    pom.xml

    <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starterartifactId>
            dependency>
    
            <dependency>
                <groupId>com.mysqlgroupId>
                <artifactId>mysql-connector-jartifactId>
                <scope>runtimescope>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>3.1.1version>
            dependency>
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-generatorartifactId>
                <version>3.1.1version>
            dependency>
            <dependency>
                <groupId>org.slf4jgroupId>
                <artifactId>slf4j-log4j12artifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-freemarkerartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    代码:

    package com.dc;
    
    import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
    import com.baomidou.mybatisplus.core.toolkit.StringPool;
    import com.baomidou.mybatisplus.core.toolkit.StringUtils;
    import com.baomidou.mybatisplus.generator.AutoGenerator;
    import com.baomidou.mybatisplus.generator.InjectionConfig;
    import com.baomidou.mybatisplus.generator.config.*;
    import com.baomidou.mybatisplus.generator.config.po.TableInfo;
    import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
    import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    /**
     * -----在希望中绽放,在苦难中坚持------
     *
     * @author 暮辰
     */
    public class MySqlGenerator {
    
        public static String scanner(String tip) {
            Scanner scanner = new Scanner(System.in);
            StringBuilder help = new StringBuilder();
            help.append("请输入" + tip + ":");
            System.out.println(help.toString());
            if (scanner.hasNext()) {
                String ipt = scanner.next();
                if (StringUtils.isNotEmpty(ipt)) {
                    return ipt;
                }
            }
            throw new MybatisPlusException("请输入正确的" + tip + "!");
        }
        /**
         * RUN THIS
         */
        public static void main(String[] args) {
    // 代码生成器
            AutoGenerator mpg = new AutoGenerator();
    // 全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            gc.setOutputDir(projectPath + "\\smptest\\src\\main\\java");
            gc.setAuthor("暮辰");
            gc.setOpen(false);
            mpg.setGlobalConfig(gc);
    // 数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false&characterEncoding=utf8");
    // dsc.setSchemaName("public");
            dsc.setDriverName("com.mysql.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("root");
            mpg.setDataSource(dsc);
    // 包配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName(scanner("模块名"));
            pc.setParent("com.dc.mp");
            mpg.setPackageInfo(pc);
    // 自定义配置
            InjectionConfig cfg = new InjectionConfig() {
                @Override
                public void initMap() {
    // to do nothing
                }
            };
            List<FileOutConfig> focList = new ArrayList<>();
            focList.add(new FileOutConfig("\\templates\\mapper.xml.ftl") {
                @Override
                public String outputFile(TableInfo tableInfo) {
    // 自定义输入文件名称
                    return projectPath + "/smptest/src/main/resources/mapper/" + pc.getModuleName()
                    + "/" + tableInfo.getEntityName() + "Mapper" +
                            StringPool.DOT_XML;
                }
            });
            cfg.setFileOutConfigList(focList);
            mpg.setCfg(cfg);
            mpg.setTemplate(new TemplateConfig().setXml(null));
    // 策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setNaming(NamingStrategy.underline_to_camel);
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);
            //strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseE ntity");
            strategy.setEntityLombokModel(true);
           //strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.B aseController");
            strategy.setInclude(scanner("表名"));
            strategy.setSuperEntityColumns("id");
            strategy.setControllerMappingHyphenStyle(true);
            strategy.setTablePrefix(pc.getModuleName() + "_");
            mpg.setStrategy(strategy);
    // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
            mpg.setTemplateEngine(new FreemarkerTemplateEngine());
            mpg.execute();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    测试:

    img

    代码生成

    img

    实体类对象:

    @Data
        @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    public class TbUser implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
                /**
                * 用户名
                */
        private String userName;
    
                /**
                * 密码
                */
        private String password;
    
                /**
                * 姓名
                */
        private String name;
    
                /**
                * 年龄
                */
        private Integer age;
    
                /**
                * 邮箱
                */
        private String email;
    
        private Integer version;
    
                /**
                * 1代表删除,0代表未删除
                */
        private Integer deleted;
    
                /**
                * 1-男,2-女
                */
        private Integer sex;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    MyBatisX快速开发插件

    MyBatisX是一款基于IDEA的快速开发插件,为效率而生。

    安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。

    功能:

    • Java 与 XML 调回跳转
    • Mapper 方法自动生成 XML

    img

  • 相关阅读:
    【数据结构与算法】之“堆”介绍
    QoS服务质量七交换机拥塞管理
    最新AI创作程序源码ChatGPT系统网站源码/Ai绘画系统/支持OpenAI GPT全模型+国内AI全模型/详细搭建部署教程
    Java 注解与反射
    写JDBC遇到的问题
    新机Word/PowerPoint新建空白文档后闪退问题
    自调试打印
    go处理json
    POJ 2991 Crane 线段树
    【dgl学习】dgl处理图中的节点/边的属性/特征/类型
  • 原文地址:https://blog.csdn.net/qq_47070121/article/details/131146343