【Mybatis-Plus進階學習(八)】SQL注入器


  • 使用SQL注入器就可以自定義例如selectById的默認方法。

    實現步驟
    Step1:創建定義方法的類;
    Step2:創建注入器;
    Step3:在Mapper中加入自定義方法。

    自定義注入器的簡單使用

    第一步:創建定義方法的類

    public class DeleteAllMethod  extends AbstractMethod {
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
            //執行的SQL
            String sql = "delete from " + tableInfo.getTableName();
            //mapper接口方法名
            String method = "deleteAll";
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
            return addDeleteMappedStatement(mapperClass, method, sqlSource);
        }
    }
    

    第二步:創建注入器

    @Component
    public class MySqlInjector extends DefaultSqlInjector {
    
        @Override
        public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
            //MP自定義的SQL語句,如果不添加,MP自定義的語句就不能用了
            List<AbstractMethod> methodList = super.getMethodList(mapperClass);
            methodList.add(new DeleteAllMethod());
            return methodList;
        }
    
    }
    

    DefaultSqlInjector、AbstractSqlInjector、ISqlInjector都能繼承。

    第三步:在UserMapper中加入自定義方法deleteAll

        /**
         * 刪除所有數據
         * @return 影響行數
         */
        int deleteAll();
    

    第四步:測試

        @Test
        public void deleteAll() {
            userMapper.deleteAll();
        }
    

    結果如下:

    這里需要注意:

    1. 不知道大家還記不記得之前邏輯刪除,3.1.2之前的版本配置了一個SQL注入器。自定義SQL注入器不可以和邏輯刪除一起配置,因為不能同時制定兩個sql注入器,所以報錯。有一個辦法就是MySqlinjector不要繼承DefaultSqlInjector直接繼承LogicSqlInjector就可以了,這樣配置這一個sql注入器,就既能使用邏輯刪除又能加入自定義方法了。

    2. 如果報以下錯誤

    當刪除所有數據時,由於有的數據行有外鍵的約束,不允許你進行物理刪除。使用語句刪除外鍵即可,alter table user drop foreign key manager_fk;。或者把外鍵字段原來默認的Restrict改成CASCADE。

    同時附上初始化數據語句,可以多次嘗試

    #初始化數據:
    INSERT INTO user (id, name, age, email, manager_id
    	, create_time)
    VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL
    		, '2019-01-11 14:20:20'),
    	(1088248166370832385, '王天風', 25, 'wtf@baomidou.com', 1087982257332887553
    		, '2019-02-05 11:12:22'),
    	(1088250446457389058, '李藝偉', 28, 'lyw@baomidou.com', 1088248166370832385
    		, '2019-02-14 08:31:16'),
    	(1094590409767661570, '張雨琪', 31, 'zjq@baomidou.com', 1088248166370832385
    		, '2019-01-14 09:15:15'),
    	(1094592041087729666, '劉紅雨', 32, 'lhm@baomidou.com', 1088248166370832385
    		, '2019-01-14 09:48:16');
    

    優化

    如果每張表都需要刪除全部,那我們為每個Mapper都寫一個deleteAll()方法,非常的繁瑣。這時候我們可以自己建立一個MyMapper接口,MyMapper接口繼承BaseMapper,而類似於UserMapper的自定義Mapper全部繼承MyMapper,這樣我們就只需要在MyMapper中編寫一個deleteAll方法,再由UserMpper和其他Mapper繼承就可以實現deleteAll()方法的重用。

    選裝件InsertBatchSomeColumn

    選擇件其實也是自定義SQL注入器,但是是由官方提供的。InsertBatchSomeColumn的主要功能是批量新增數據,自選字段insert。接下來讓我們看看是如何實現的吧。
    第一步:注入器中加入方法

        @Override
        public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
            //MP自定義的SQL語句,如果不添加,MP自定義的語句就不能用了
            List<AbstractMethod> methodList = super.getMethodList(mapperClass);
            methodList.add(new DeleteAllMethod());
            //加入選裝件InsertBatchSomeColumn,同時排除邏輯刪除字段
            methodList.add(new InsertBatchSomeColumn(t->!t.isLogicDelete()));
            return methodList;
        }
    

    第二步:在MyMapper中加入insertBatchSomeColumn方法

    public interface MyMapper<T> extends BaseMapper<T> {
        /**
         * 刪除所有數據
         * @return 影響行數
         */
        int deleteAll();
    
        int insertBatchSomeColumn(List<T> list);
    }
    

    第三步:測試

     @Test
        public void insertBatchSomeColumn() {
    
            User user = new User();
            user.setName("王聚義");
            user.setAge(26);
            user.setEmail("wjy@163.com");
            user.setManagerId(1088248166370832385L);
    
            User user2 = new User();
            user2.setName("王收義");
            user2.setAge(28);
            user2.setEmail("wsy@163.com");
            user2.setManagerId(1088248166370832385L);
    
            List<User> list = new ArrayList<>();
            list.add(user);
            list.add(user2);
    
            userMapper.insertBatchSomeColumn(list);
        }
    

    可以看出批量插入成功。

    需要注意的是,User對象中為Null的值會覆蓋沒有被排除字段的默認值。例如version的默認值為1,但是我們插入的User的version為null,如果version這個字段在注入器組件中沒有被排除,結果數據庫中的值應該為null。

    同時作者在注解中也提示,選裝器只在mysql中測試過,所以慎用。

    選裝件LogicDeleteByIdWithFill

    LogicDeleteByIdWithFill的主要功能是根據id邏輯刪除數據並帶字段填充功能。例如在刪除的時候需要添加操作人。

    第一步:注入器中加入方法

     methodList.add(new LogicDeleteByIdWithFill());
    

    第二步:在MyMapper中加入方法

        int deleteByIdWithFill(T entity);
    

    第三步:測試

     @Test
        public void deleteByIdWithFill() {
            User user = new User();
            user.setId(1346432120618147841L);
            user.setUpdateTime(LocalDateTime.now());
            userMapper.deleteByIdWithFill(user);
        }
    

    注意,如果想在刪除的同時修改數據,被修改的數據必須有自動填充標識,不然無法完成更新。結果如下:

    選裝件AlwaysUpdateSomeColumnById

    AlwaysUpdateSomeColumnById的主要功能是根據id更新固定的某些字段。

    第一步:注入器中加入方法

            methodList.add(new AlwaysUpdateSomeColumnById(t->!t.getColumn().equals("name")));
    

    第二步:在MyMapper中加入方法

     int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);
    

    第三步:測試

        @Test
        public void alwaysUpdateSomeColumnById() {
            User user = new User();
            user.setId(1346432120618147841L);
            user.setName("王地風");
            user.setAge(16);
            userMapper.alwaysUpdateSomeColumnById(user);
        }
    

    結果如下:

  • 相關閱讀:

  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM