Browse Source

增加批量逻辑删除转换方法.

nieqiurong 1 năm trước cách đây
mục cha
commit
ac951d0b3d

+ 1 - 1
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/batch/BatchMethod.java

@@ -16,7 +16,7 @@ public class BatchMethod<T> {
     /**
      * 方法参数转换器,默认传递批量的entity的参数
      */
-    private ParameterConvert<T> parameterConvert;
+    private ParameterConvert<T> parameterConvert = (entity) -> entity;
 
     public BatchMethod(String statementId) {
         this.statementId = statementId;

+ 75 - 11
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/batch/MybatisBatch.java

@@ -22,6 +22,7 @@ import java.util.function.Function;
  * <li>返回值为批处理结果,如果对返回值比较关心的可接收判断处理</li>
  * <li>saveOrUpdate尽量少用把,保持批处理为简单的插入或更新</li>
  * <li>关于saveOrUpdate中的sqlSession,如果执行了select操作的话,BatchExecutor都会触发一次flushStatements,为了保证结果集,故使用包装了部分sqlSession查询操作</li>
+ * <li>autoCommit参数,在spring下使用的是{@link org.mybatis.spring.transaction.SpringManagedTransaction},控制无效,只能通过datasource控制(建议不要修改),单独使用mybatis下{@link org.apache.ibatis.transaction.jdbc.JdbcTransaction}是可用的</li>
  * <pre>
  *     Spring示例:
  * 		transactionTemplate.execute(new TransactionCallback<List<BatchResult>>() {
@@ -47,45 +48,98 @@ public class MybatisBatch<T> {
         this.dataList = dataList;
     }
 
+    /**
+     * 执行批量操作
+     *
+     * @param statement 执行的 mapper 方法 (示例: com.baomidou.mybatisplus.core.mapper.BaseMapper.insert )
+     * @return 批处理结果
+     */
     public List<BatchResult> execute(String statement) {
         return execute(false, statement, (entity) -> entity);
     }
 
+    /**
+     * 执行批量操作
+     *
+     * @param statement        执行的 mapper 方法 (示例: com.baomidou.mybatisplus.core.mapper.BaseMapper.insert )
+     * @param parameterConvert 参数转换器
+     * @return 批处理结果
+     */
     public List<BatchResult> execute(String statement, ParameterConvert<T> parameterConvert) {
         return execute(false, statement, parameterConvert);
     }
 
+    /**
+     * 执行批量操作
+     *
+     * @param autoCommit 是否自动提交(这里生效的前提依赖于事务管理器 {@link org.apache.ibatis.transaction.Transaction})
+     * @param statement  执行的 mapper 方法 (示例: com.baomidou.mybatisplus.core.mapper.BaseMapper.insert )
+     * @return 批处理结果
+     */
     public List<BatchResult> execute(boolean autoCommit, String statement) {
-        return execute(autoCommit, statement, null);
+        return execute(autoCommit, statement, (entity) -> entity);
     }
 
+    /**
+     * 执行批量操作
+     *
+     * @param batchMethod 批量操作方法
+     * @return 批处理结果
+     */
     public List<BatchResult> execute(BatchMethod<T> batchMethod) {
         return execute(false, batchMethod);
     }
 
+
+    /**
+     * 执行批量操作
+     *
+     * @param autoCommit  是否自动提交(这里生效的前提依赖于事务管理器 {@link org.apache.ibatis.transaction.Transaction})
+     * @param batchMethod 批量操作方法
+     * @return 批处理结果
+     */
     public List<BatchResult> execute(boolean autoCommit, BatchMethod<T> batchMethod) {
-        try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, autoCommit)) {
-            for (T data : dataList) {
-                ParameterConvert<T> parameterConvert = batchMethod.getParameterConvert();
-                sqlSession.update(batchMethod.getStatementId(), toParameter(parameterConvert, data));
-            }
-            return sqlSession.flushStatements();
-        }
+        return execute(autoCommit, batchMethod.getStatementId(), batchMethod.getParameterConvert());
     }
 
+    /**
+     * 执行批量操作
+     *
+     * @param autoCommit       是否自动提交(这里生效的前提依赖于事务管理器 {@link org.apache.ibatis.transaction.Transaction})
+     * @param statement        执行的 mapper 方法 (示例: com.baomidou.mybatisplus.core.mapper.BaseMapper.insert )
+     * @param parameterConvert 参数转换器
+     * @return 批处理结果
+     */
     public List<BatchResult> execute(boolean autoCommit, String statement, ParameterConvert<T> parameterConvert) {
         try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, autoCommit)) {
             for (T data : dataList) {
-                sqlSession.update(statement, parameterConvert != null ? parameterConvert.convert(data) : data);
+                sqlSession.update(statement, toParameter(parameterConvert, data));
             }
             return sqlSession.flushStatements();
         }
     }
 
+    /**
+     * 批量保存或更新
+     *
+     * @param insertMethod    插入方法
+     * @param insertPredicate 插入条件 (当条件满足时执行插入方法,否则执行更新方法)
+     * @param updateMethod    更新方法
+     * @return 批处理结果
+     */
     public List<BatchResult> saveOrUpdate(BatchMethod<T> insertMethod, BiPredicate<BatchSqlSession, T> insertPredicate, BatchMethod<T> updateMethod) {
         return saveOrUpdate(false, insertMethod, insertPredicate, updateMethod);
     }
 
+    /**
+     * 批量保存或更新
+     *
+     * @param autoCommit      是否自动提交(这里生效的前提依赖于事务管理器 {@link org.apache.ibatis.transaction.Transaction})
+     * @param insertMethod    插入方法
+     * @param insertPredicate 插入条件 (当条件满足时执行插入方法,否则执行更新方法)
+     * @param updateMethod    更新方法
+     * @return 批处理结果
+     */
     public List<BatchResult> saveOrUpdate(boolean autoCommit, BatchMethod<T> insertMethod, BiPredicate<BatchSqlSession, T> insertPredicate, BatchMethod<T> updateMethod) {
         List<BatchResult> resultList = new ArrayList<>();
         try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, autoCommit)) {
@@ -127,14 +181,24 @@ public class MybatisBatch<T> {
             });
         }
 
-        public BatchMethod<T> update(Function<T, Wrapper<T>> wrapperFunction) {
+        public BatchMethod<T> update(Function<T, Wrapper<T>> function) {
             return new BatchMethod<>(namespace + StringPool.DOT + SqlMethod.UPDATE.getMethod(), (entity) -> {
                 Map<String, Object> param = new HashMap<>();
                 param.put(Constants.ENTITY, entity);
-                param.put(Constants.WRAPPER, wrapperFunction.apply(entity));
+                param.put(Constants.WRAPPER, function.apply(entity));
                 return param;
             });
         }
+
+        public <E> BatchMethod<E> deleteById(Function<E, T> function) {
+            return new BatchMethod<>(namespace + StringPool.DOT + SqlMethod.DELETE_BY_ID.getMethod(), function::apply);
+        }
+
+        @SuppressWarnings("TypeParameterHidesVisibleType")
+        public <T> BatchMethod<T> deleteById() {
+            return new BatchMethod<>(namespace + StringPool.DOT + SqlMethod.DELETE_BY_ID.getMethod());
+        }
+
     }
 
 }

+ 2 - 2
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/batch/ParameterConvert.java

@@ -10,9 +10,9 @@ public interface ParameterConvert<T> {
     /**
      * 转换当前实体参数为mapper方法参数
      *
-     * @param entity 实体对象
+     * @param parameter 参数对象
      * @return mapper方法参数.
      */
-    Object convert(T entity);
+    Object convert(T parameter);
 
 }

+ 41 - 9
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/MybatisTest.java

@@ -16,11 +16,13 @@
 package com.baomidou.mybatisplus.test;
 
 import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
+import com.baomidou.mybatisplus.core.batch.MybatisBatch;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler;
 import com.baomidou.mybatisplus.test.h2.entity.H2User;
 import com.baomidou.mybatisplus.test.h2.enums.AgeEnum;
 import com.baomidou.mybatisplus.test.h2.mapper.H2UserMapper;
+import org.apache.ibatis.executor.BatchResult;
 import org.apache.ibatis.io.Resources;
 import org.apache.ibatis.jdbc.ScriptRunner;
 import org.apache.ibatis.session.Configuration;
@@ -29,14 +31,19 @@ import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.type.TypeHandlerRegistry;
 import org.h2.jdbcx.JdbcDataSource;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.context.event.annotation.BeforeTestClass;
 
+import javax.sql.DataSource;
 import java.io.IOException;
 import java.io.Reader;
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
 
 
 /**
@@ -47,16 +54,15 @@ import java.sql.SQLException;
 @ExtendWith(MockitoExtension.class)
 class MybatisTest {
 
-    @Test
-    void test() throws IOException, SQLException {
-        JdbcDataSource dataSource = new JdbcDataSource();
-        dataSource.setUser("sa");
-        dataSource.setPassword("");
-        dataSource.setUrl("jdbc:h2:mem:test;MODE=mysql;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
+    private static SqlSessionFactory sqlSessionFactory;
+
+
+    @BeforeAll
+    public static void init() throws IOException, SQLException {
         Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
-        SqlSessionFactory factory = new MybatisSqlSessionFactoryBuilder().build(reader);
-        SqlSession sqlSession = factory.openSession(dataSource.getConnection());
-        Configuration configuration = factory.getConfiguration();
+        sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(reader);
+        DataSource dataSource = sqlSessionFactory.getConfiguration().getEnvironment().getDataSource();
+        Configuration configuration = sqlSessionFactory.getConfiguration();
         TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
         /*
          *  如果是将defaultEnumTypeHandler设置成MP的处理器,
@@ -66,6 +72,12 @@ class MybatisTest {
         Connection connection = dataSource.getConnection();
         ScriptRunner scriptRunner = new ScriptRunner(connection);
         scriptRunner.runScript(Resources.getResourceAsReader("h2/user.ddl.sql"));
+    }
+
+
+    @Test
+    void test(){
+        SqlSession sqlSession = sqlSessionFactory.openSession(true);
         H2UserMapper mapper = sqlSession.getMapper(H2UserMapper.class);
         Assertions.assertEquals(mapper.myInsertWithNameVersion("test", 2), 1);
         Assertions.assertEquals(mapper.insert(new H2User("test")), 1);
@@ -81,6 +93,26 @@ class MybatisTest {
         Assertions.assertEquals(mapper.updateById(new H2User(66L, "777777")), 1);
         Assertions.assertEquals(mapper.deleteById(66L), 1);
         Assertions.assertNull(mapper.selectById(66L));
+        sqlSession.close();
+
+        System.out.println("------------------批量测试开始-----------------------------");
+        sqlSession = sqlSessionFactory.openSession();
+        mapper = sqlSession.getMapper(H2UserMapper.class);
+        List<H2User> userList = Arrays.asList(new H2User(1000L,"测试"),new H2User(1001L,"测试"));
+        // 基于JdbcTransaction的原生事务管理.
+        // 非自动提交事务时,执行结束后会回滚掉批量插入的数据
+        new MybatisBatch<>(sqlSessionFactory, userList).execute(H2UserMapper.class.getName() + ".insert");
+        for (H2User u : userList) {
+            Assertions.assertNull(mapper.selectById(u.getTestId()));
+        }
+        // 自动提交事务
+        sqlSession = sqlSessionFactory.openSession();
+        mapper = sqlSession.getMapper(H2UserMapper.class);
+        new MybatisBatch<>(sqlSessionFactory, userList).execute(true, H2UserMapper.class.getName() + ".insert");
+        for (H2User u : userList) {
+            Assertions.assertNotNull(mapper.selectById(u.getTestId()));
+        }
+        System.out.println("------------------批量测试结束-----------------------------");
     }
 
 }

+ 99 - 31
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/H2UserMapperTest.java

@@ -15,6 +15,7 @@
  */
 package com.baomidou.mybatisplus.test.h2;
 
+import com.baomidou.mybatisplus.core.batch.BatchMethod;
 import com.baomidou.mybatisplus.core.batch.MybatisBatch;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -33,7 +34,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.support.TransactionCallback;
 import org.springframework.transaction.support.TransactionTemplate;
 
@@ -69,30 +69,24 @@ class H2UserMapperTest extends BaseTest {
 
 
     @Test
-    void testBatchTransaction(){
+    void testBatchTransaction() {
         List<H2User> h2UserList = Arrays.asList(new H2User(1000036L, "测试12323232"), new H2User(10000367L, "测试3323232"));
         try {
-            transactionTemplate.execute(new TransactionCallback<List<BatchResult>>() {
-                @Override
-                public List<BatchResult> doInTransaction(TransactionStatus status) {
-                    MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
-                    // 执行批量插入
-                    new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(mapperMethod.insert());
-                    throw new RuntimeException("出错了");
-                }
+            transactionTemplate.execute((TransactionCallback<List<BatchResult>>) status -> {
+                MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
+                // 执行批量插入
+                new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(mapperMethod.insert());
+                throw new RuntimeException("出错了");
             });
         } catch (Exception exception) {
             for (H2User h2User : h2UserList) {
                 Assertions.assertNull(userMapper.selectById(h2User.getTestId()));
             }
         }
-        transactionTemplate.execute(new TransactionCallback<List<BatchResult>>() {
-            @Override
-            public List<BatchResult> doInTransaction(TransactionStatus status) {
-                MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
-                // 执行批量插入
-                return new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(mapperMethod.insert());
-            }
+        transactionTemplate.execute(status -> {
+            MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
+            // 执行批量插入
+            return new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(mapperMethod.insert());
         });
         for (H2User h2User : h2UserList) {
             Assertions.assertNotNull(userMapper.selectById(h2User.getTestId()));
@@ -116,6 +110,79 @@ class H2UserMapperTest extends BaseTest {
         }
     }
 
+    @Test
+    void testInsertBatchByCustomMethod() {
+        int batchSize = 1000;
+        List<BatchResult> batchResults;
+        int[] updateCounts;
+        List<H2User> h2UserList = new ArrayList<>();
+        for (int i = 0; i < batchSize; i++) {
+            h2UserList.add(new H2User("myInsertWithoutParam" + i));
+        }
+        // 执行批量插入
+        batchResults = new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(H2UserMapper.class.getName() + ".myInsertWithoutParam");
+        updateCounts = batchResults.get(0).getUpdateCounts();
+        Assertions.assertEquals(batchSize, updateCounts.length);
+        for (int updateCount : updateCounts) {
+            Assertions.assertEquals(1, updateCount);
+        }
+
+        h2UserList = new ArrayList<>();
+        for (int i = 0; i < batchSize; i++) {
+            h2UserList.add(new H2User("myInsertWithParam" + i));
+        }
+        // 执行批量插入
+        batchResults = new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(H2UserMapper.class.getName() + ".myInsertWithParam", parameter -> Map.of("user1", parameter));
+        updateCounts = batchResults.get(0).getUpdateCounts();
+        Assertions.assertEquals(batchSize, updateCounts.length);
+        for (int updateCount : updateCounts) {
+            Assertions.assertEquals(1, updateCount);
+        }
+
+        h2UserList = new ArrayList<>();
+        for (int i = 0; i < batchSize; i++) {
+            h2UserList.add(new H2User("myInsertWithParam" + i));
+        }
+        batchResults = new MybatisBatch<>(sqlSessionFactory, h2UserList).execute(new BatchMethod<>(H2UserMapper.class.getName() + ".myInsertWithParam", parameter -> Map.of("user1", parameter)));
+        updateCounts = batchResults.get(0).getUpdateCounts();
+        Assertions.assertEquals(batchSize, updateCounts.length);
+        for (int updateCount : updateCounts) {
+            Assertions.assertEquals(1, updateCount);
+        }
+    }
+
+    @Test
+    void testDeleteByIds() {
+        List<BatchResult> batchResults;
+        int batchSize = 1000;
+        List<Long> ids = new ArrayList<>();
+        for (int i = 0; i < batchSize; i++) {
+            ids.add((long) 7120000 + i);
+        }
+        List<H2User> userList = new ArrayList<>();
+        MybatisBatch.Method<H2User> method = new MybatisBatch.Method<>(H2UserMapper.class);
+        // 转换成实体进行逻辑删除
+        batchResults = new MybatisBatch<>(sqlSessionFactory, ids).execute(method.deleteById(id -> {
+            H2User h2User = H2User.ofId(id);
+            userList.add(h2User);
+            return h2User;
+        }));
+        int[] updateCounts = batchResults.get(0).getUpdateCounts();
+        Assertions.assertEquals(batchSize, updateCounts.length);
+        for (int updateCount : updateCounts) {
+            Assertions.assertEquals(0, updateCount);
+        }
+        for (H2User h2User : userList) {
+            Assertions.assertNotNull(h2User.getLastUpdatedDt());
+        }
+        // 不能走填充
+        batchResults = new MybatisBatch<>(sqlSessionFactory, ids).execute(method.deleteById());
+        updateCounts = batchResults.get(0).getUpdateCounts();
+        for (int updateCount : updateCounts) {
+            Assertions.assertEquals(0, updateCount);
+        }
+    }
+
     @Test
     void testUpdateBatch() {
         int batchSize = 1000;
@@ -134,7 +201,7 @@ class H2UserMapperTest extends BaseTest {
     }
 
     @Test
-    void testSaveOrUpdateBatch1(){
+    void testSaveOrUpdateBatch1() {
         int batchSize = 10;
         List<H2User> h2UserList = new ArrayList<>();
         for (int i = 0; i < batchSize; i++) {
@@ -152,8 +219,9 @@ class H2UserMapperTest extends BaseTest {
             Assertions.assertEquals(1, updateCount);
         }
     }
+
     @Test
-    void testSaveOrUpdateBatch2(){
+    void testSaveOrUpdateBatch2() {
         int batchSize = 10;
         List<H2User> h2UserList = new ArrayList<>();
         for (int i = 0; i < batchSize; i++) {
@@ -162,12 +230,12 @@ class H2UserMapperTest extends BaseTest {
         MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
         List<BatchResult> batchResults = new MybatisBatch<>(sqlSessionFactory, h2UserList).saveOrUpdate(
                 mapperMethod.insert(),
-				((sqlSession, h2User) -> sqlSession.selectList(H2UserMapper.class.getName() + ".selectById", h2User.getTestId()).isEmpty()),
+                ((sqlSession, h2User) -> sqlSession.selectList(H2UserMapper.class.getName() + ".selectById", h2User.getTestId()).isEmpty()),
                 mapperMethod.updateById());
         // 使用共享的sqlSession,等于每次都是刷新了,批次总结果集就等于数据大小了
         Assertions.assertEquals(batchSize, batchResults.size());
         for (BatchResult batchResult : batchResults) {
-            Assertions.assertEquals(batchResult.getUpdateCounts().length,1);
+            Assertions.assertEquals(batchResult.getUpdateCounts().length, 1);
             Assertions.assertEquals(1, batchResult.getUpdateCounts()[0]);
         }
     }
@@ -231,9 +299,9 @@ class H2UserMapperTest extends BaseTest {
         h2User.setAge(AgeEnum.THREE);
         h2User.setDesc(null);
         Assertions.assertTrue(userMapper.update(h2User,
-            new UpdateWrapper<H2User>().lambda()
-                .set(H2User::getDesc, "")
-                .eq(H2User::getName, "Jerry")) > 0);
+                new UpdateWrapper<H2User>().lambda()
+                        .set(H2User::getDesc, "")
+                        .eq(H2User::getName, "Jerry")) > 0);
 
         log(userMapper.selectOne(new QueryWrapper<>(new H2User().setName(NQQ).setAge(AgeEnum.THREE))));
 
@@ -287,7 +355,7 @@ class H2UserMapperTest extends BaseTest {
     @Order(Integer.MAX_VALUE)
     void delete() {
         userMapper.delete(new QueryWrapper<>(new H2User().setAge(AgeEnum.TWO))
-            .eq("name", "Tony"));
+                .eq("name", "Tony"));
     }
 
     @Test
@@ -298,14 +366,14 @@ class H2UserMapperTest extends BaseTest {
         int insertCount = userMapper.insert(new H2User().setName(name).setAge(AgeEnum.ONE));
         Assertions.assertEquals(1, insertCount);
         int updateCount = userMapper.update(new H2User(),
-            new UpdateWrapper<H2User>().comment("updateUserName1").lambda()
-                .set(H2User::getName, nameNew)
-                .eq(H2User::getName, name)
+                new UpdateWrapper<H2User>().comment("updateUserName1").lambda()
+                        .set(H2User::getName, nameNew)
+                        .eq(H2User::getName, name)
         );
         Assertions.assertEquals(1, updateCount);
         H2User h2User = userMapper.selectOne(
-            new QueryWrapper<H2User>().lambda().comment("getUserByUniqueName")
-                .eq(H2User::getName, nameNew)
+                new QueryWrapper<H2User>().lambda().comment("getUserByUniqueName")
+                        .eq(H2User::getName, nameNew)
         );
         Assertions.assertNotNull(h2User);
         LambdaQueryWrapper<H2User> queryWrapper = new QueryWrapper<H2User>().lambda().ge(H2User::getAge, 1);
@@ -324,7 +392,7 @@ class H2UserMapperTest extends BaseTest {
     }
 
     @Test
-    void test(){
+    void test() {
         Page<H2User> page = new Page<>();
         userMapper.testPage1(new H2User(), page);
         userMapper.testPage2(page, new H2User());

+ 6 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/H2User.java

@@ -131,4 +131,10 @@ public class H2User extends SuperEntity {
             "testDate=" + testDate + "," +
             "version=" + version;
     }
+
+    public static H2User ofId(Long id) {
+        H2User h2User = new H2User();
+        h2User.setTestId(id);
+        return h2User;
+    }
 }

+ 11 - 1
mybatis-plus/src/test/resources/mybatis-config.xml

@@ -3,11 +3,21 @@
         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 <configuration>
-
     <settings>
         <setting name="defaultEnumTypeHandler"
                  value="com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler"/>
     </settings>
+    <environments default="test">
+        <environment id="test">
+            <transactionManager type="JDBC"/>
+            <dataSource type="POOLED">
+                <property name="driver" value="org.h2.Driver" />
+                <property name="url" value="jdbc:h2:mem:test;MODE=mysql;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"/>
+                <property name="username" value="sa"/>
+                <property name="password" value=""/>
+            </dataSource>
+        </environment>
+    </environments>
 
     <mappers>
         <mapper class="com.baomidou.mybatisplus.test.h2.mapper.H2UserMapper"/>