目录
    • 1.4 @tablefield
    • 3.1 deletebyid
    • 3.2 deletebymap
    • 3.4 deletebatchids
    • 4.1 selectbyid
    • 4.2 selectbatchids
    • 4.3 selectone
    • 4.4 selectcount
    • 4.5 selectlist
    • 4.6 selectpage
  • 5 sql注入的原理

    通过前面的学习,我们了解到通过继承basemapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这些
    操作。

    1、插入操作

     1.1 方法定义

    /*** 
    插入一条记录 *
    @param entity 实体对象 
    */ 
    int insert(t entity);

    1.2 测试用例

    @runwith(springrunner.class)
    @springboottest
    public class testusermapper {
    
        @autowired
        private usermapper usermapper;
    
        @test
        public void testinsert(){
            user user=new user();
            user.setage(12);
            user.setname("曹操");
            user.setpassword("123");
            user.setmail("caocao@qq.com");
            user.setusername("曹操");
            user.setaddress("北京");
            //result数据库受影响的行数
            int result = usermapper.insert(user);
            system.out.println("result=>"+result);
            //获取自增长后的id值
            system.out.println(user.getid());//自增后的id会回填到对象中
        }
    }    

    1.3 测试

    可以看到,数据已经写入到了数据库,但是,id的值不正确,我们期望的是数据库自增长,实际是mp生成了id的值
    写入到了数据库。

    如何设置id的生成策略呢?

    mp支持的id策略

    package com.baomidou.mybatisplus.annotation;
    
    import lombok.getter;
    
    /**
     * 生成id类型枚举类
     *
     * @author hubin
     * @since 2015-11-10
     */
    @getter
    public enum idtype {
        /**
         * 数据库id自增
         */
        auto(0),
        /**
         * 该类型为未设置主键类型
         */
        none(1),
        /**
         * 用户输入id
         * <p>该类型可以通过自己注册自动填充插件进行填充</p>
         */
        input(2),
    
        /* 以下3种类型、只有当插入对象id 为空,才自动填充。 */
        /**
         * 全局唯一id (idworker)
         */
        id_worker(3),
        /**
         * 全局唯一id (uuid)
         */
        uuid(4),
        /**
         * 字符串全局唯一id (idworker 的字符串表示)
         */
        id_worker_str(5);
    
        private final int key;
    
        idtype(int key) {
            this.key = key;
        }
    }

    修改user对象:

    @data
    @noargsconstructor
    @allargsconstructor
    @tablename("tb_user")
    public class user {
        @tableid(value="id",type= idtype.auto)//设置id字段为自增长
        private long id;
        private string username;
        private string password;
        private string name;
        private integer age;
        private string email;
    }

    数据插入成功:

    1.4 @tablefield

    在mp中通过@tablefield注解可以指定字段的一些属性,常常解决的问题有2个:

    1、对象中的属性名和字段名不一致的问题(非驼峰)

    2、对象中的属性字段在表中不存在的问题

    使用:

    其他用法,如密碼字段不加入查询字段:

    效果:

    .

    2、更新操作

    在mp中,更新操作有2种,一种是根据id更新,另一种是根据条件更新。

    2.1 根据id更新

    方法定义:

    /*** 根据 id 修改
     ** @param entity 实体对象
      */ 
    int updatebyid(@param(constants.entity) t entity);

    测试:

    @runwith(springrunner.class) 
    @springboottest 
    public class usermappertest { 
    
    @autowired private usermapper usermapper; 
    
    @test 
    public void testupdatebyid() { 
    	user user = new user(); user.setid(6l); //主键 
    	user.setage(21); //更新的字段 
    	//根据id更新,更新不为null的字段 
    	this.usermapper.updatebyid(user); 
    } 
    
    }

    结果:

    2.2 根据条件更新

    方法定义:

    /*** 
    根据 whereentity 条件,更新记录 
    **
     @param entity 实体对象 (set 条件值,可以为 null) * 
     @param updatewrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) 
     */ 
     int update(@param(constants.entity) t entity, @param(constants.wrapper) wrapper<t> updatewrapper); 

    测试用例:

    @test public void testupdate() {
    	user user = new user(); user.setage(22); //更新的字段 
    	//更新的条件 
    	querywrapper<user> wrapper = new querywrapper<>(); 
    	wrapper.eq("id", 6); 
    	//执行更新操作 
    	int result = this.usermapper.update(user, wrapper); 
    	system.out.println("result = " + result); 
    }

    或者,通过updatewrapper进行更新:

    @test public void testupdate() { 
    	//更新的条件以及字段 
    	updatewrapper<user> wrapper = new updatewrapper<>(); 
    	wrapper.eq("id", 6).set("age", 23); 
    	//执行更新操作 
    	int result = this.usermapper.update(null, wrapper); 
    	system.out.println("result = " + result); 
    }

    测试结果:

    均可达到更新的效果。

    关于wrapper更多的用法后面会详细讲解。

    3、删除操作

    3.1 deletebyid

    方法定义:

    /*** 根据 id 删除 ** 
    @param id 主键id */ 
    int deletebyid(serializable id);

    测试用例:

    @test 
    public void testdeletebyid() { 
    	//执行删除操作 
    	int result = this.usermapper.deletebyid(6l); 
    	system.out.println("result = " + result); 
    }

    数据被删除。

    3.2 deletebymap

    方法定义:

    /*** 根据 columnmap 条件,删除记录 ** 
    @param columnmap 表字段 map 对象
     */ 
    int deletebymap(@param(constants.column_map) map<string, object> columnmap);

    测试用例:

    @test 
    public void testdeletebymap() { 
    	map<string, object> columnmap = new hashmap<>(); 
    	columnmap.put("age",20); columnmap.put("name","张三"); 
    	
    	//将columnmap中的元素设置为删除的条件,多个之间为and关系 
    	int result = this.usermapper.deletebymap(columnmap); 
    	system.out.println("result = " + result); 
    }

    3.3 delete

    方法定义:

    /*** 
    根据 entity 条件,删除记录 ** @param wrapper 实体对象封装操作类(可以为 null)
     */ 
     int delete(@param(constants.wrapper) wrapper<t> wrapper);

    测试用例:

    @test public void testdeletebymap() { 
    	user user = new user(); 
    	user.setage(20); 
    	user.setname("张三"); 
    	
    	//将实体对象进行包装,包装为操作条件 
    	querywrapper<user> wrapper = new querywrapper<>(user); 
    	int result = this.usermapper.delete(wrapper); 
    	system.out.println("result = " + result); 
    }

    结果:

    3.4 deletebatchids

    方法定义:

    /*** 
    删除(根据id 批量删除) ** 
    @param idlist 主键id列表(不能为 null 以及 empty) */ 
    int deletebatchids(@param(constants.collection) collection<? extends serializable> idlist);

    测试用例:

    @test 
    public void testdeletebymap() { 
    	//根据id集合批量删除 
    	int result = this.usermapper.deletebatchids(arrays.aslist(1l,10l,20l)); 
    	system.out.println("result = " + result); 
    }

    结果:

    4、查询操作

    mp提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作。

    4.1 selectbyid

    方法定义:

    /*** 
    根据 id 查询 ** @param id 主键id 
    */ 
    t selectbyid(serializable id);

    测试用例:

    @test 
    public void testselectbyid() { 
    	//根据id查询数据 
    	user user = this.usermapper.selectbyid(2l); 
    	system.out.println("result = " + user); 
    }

    结果:

    4.2 selectbatchids

    方法定义:

    /*** 
    查询(根据id 批量查询) 
    ** @param idlist 主键id列表(不能为 null 以及 empty) 
    */ 
    list<t> selectbatchids(@param(constants.collection) collection<? extends serializable> idlist);

    测试用例:

    @test 
    public void testselectbatchids() { 
    	//根据id集合批量查询 
    	list<user> users = this.usermapper.selectbatchids(arrays.aslist(2l, 3l, 10l)); 
    	for (user user : users) { 
    	system.out.println(user); 
    	} 
    }

    4.3 selectone

    方法定义:

    /*** 
    根据 entity 条件,查询一条记录 ** @param querywrapper 实体对象封装操作类(可以为 null) 
    */ 
    t selectone(@param(constants.wrapper) wrapper<t> querywrapper);

    测试用例:

    @test public void testselectone() { 
    	querywrapper<user> wrapper = new querywrapper<user>(); 
    	wrapper.eq("name", "李四"); 
    	//根据条件查询一条数据,如果结果超过一条会报错 
    	user user = this.usermapper.selectone(wrapper);
    	system.out.println(user); 
    }

    结果:

    4.4 selectcount

    方法定义:

    /*** 
    根据 wrapper 条件,查询总记录数 ** 
    @param querywrapper 实体对象封装操作类(可以为 null) 
    */ 
    integer selectcount(@param(constants.wrapper) wrapper<t> querywrapper);

    测试用例:

    @test 
    public void testselectcount() { 
    	querywrapper<user> wrapper = new querywrapper<user>(); 
    	wrapper.gt("age", 23); //年龄大于23岁 
    	
    	//根据条件查询数据条数
    	integer count = this.usermapper.selectcount(wrapper); 
    	system.out.println("count = " + count); 
    }

    4.5 selectlist

    方法定义:

    /*** 
    根据 entity 条件,查询全部记录 ** 
    @param querywrapper 实体对象封装操作类(可以为 null) */ 
    list<t> selectlist(@param(constants.wrapper) wrapper<t> querywrapper);

    测试用例:

    @test 
    public void testselectlist() { 
    	querywrapper<user> wrapper = new querywrapper<user>(); 
    	wrapper.gt("age", 23); //年龄大于23岁
    	
    	//根据条件查询数据 
    	list<user> users = this.usermapper.selectlist(wrapper); 
    	for (user user : users) { 
    		system.out.println("user = " + user); 
    	} 
    }

    4.6 selectpage

    方法定义:

    /*** 根据 entity 条件,查询全部记录(并翻页) 
    ** @param page 分页查询条件(可以为 rowbounds.default) 
    * @param querywrapper 实体对象封装操作类(可以为 null) 
    */ 
    ipage<t> selectpage(ipage<t> page, @param(constants.wrapper) wrapper<t> querywrapper);

    配置分页插件:

    package cn.itcast.mp; 
    import com.baomidou.mybatisplus.extension.plugins.paginationinterceptor; 
    import org.mybatis.spring.annotation.mapperscan; 
    import org.springframework.context.annotation.bean; 
    import org.springframework.context.annotation.configuration; 
    
    @configuration 
    @mapperscan("cn.itcast.mp.mapper") //设置mapper接口的扫描包 
    public class mybatisplusconfig { 
    	/*** 分页插件 */ 
    	@bean 
    	public paginationinterceptor paginationinterceptor() {
    		return new paginationinterceptor(); 
    	} 
    }

    测试用例:

    @test 
    public void testselectpage() { 
    	querywrapper<user> wrapper = new querywrapper<user>(); 
    	wrapper.gt("age", 20); //年龄大于20岁 
    	page<user> page = new page<>(1,1); 
    	
    	//根据条件查询数据 
    	ipage<user> ipage = this.usermapper.selectpage(page, wrapper); 
    	system.out.println("数据总条数:" + ipage.gettotal()); 
    	system.out.println("总页数:" + ipage.getpages()); 
    	
    	list<user> users = ipage.getrecords(); 
    	for (user user : users) { 
    		system.out.println("user = " + user); 
    	} 
    }

    结果:

    5 sql注入的原理

    前面我们已经知道,mp在启动后会将basemapper中的一系列的方法注册到mappedstatements中,那么究竟是如
    何注入的呢?流程又是怎么样的?下面我们将一起来分析下。

    在mp中,isqlinjector负责sql的注入工作,它是一个接口,abstractsqlinjector是它的实现类,实现关系如下:

    在abstractsqlinjector中,主要是由inspectinject()方法进行注入的,如下:

     @override
        public void inspectinject(mapperbuilderassistant builderassistant, class<?> mapperclass) {
            class<?> modelclass = extractmodelclass(mapperclass);
            if (modelclass != null) {
                string classname = mapperclass.tostring();
                set<string> mapperregistrycache = globalconfigutils.getmapperregistrycache(builderassistant.getconfiguration());
                if (!mapperregistrycache.contains(classname)) {
                    list<abstractmethod> methodlist = this.getmethodlist();
                    if (collectionutils.isnotempty(methodlist)) {
                        tableinfo tableinfo = tableinfohelper.inittableinfo(builderassistant, modelclass);
                        // 循环注入自定义方法
                        methodlist.foreach(m -> m.inject(builderassistant, mapperclass, modelclass, tableinfo));
                    } else {
                        logger.debug(mapperclass.tostring() + ", no effective injection method was found.");
                    }
                    mapperregistrycache.add(classname);
                }
            }
        }

    在实现方法中, methodlist.foreach(m -> m.inject(builderassistant, mapperclass, modelclass, tableinfo)); 是关键,循环遍历方法,进行注入。

    最终调用抽象方法injectmappedstatement进行真正的注入:

     /**
         * 注入自定义 mappedstatement
         *
         * @param mapperclass mapper 接口
         * @param modelclass  mapper 泛型
         * @param tableinfo   数据库表反射信息
         * @return mappedstatement
         */
        public abstract mappedstatement injectmappedstatement(class<?> mapperclass, class<?> modelclass, tableinfo tableinfo);

    查看该方法的实现:

    以selectbyid为例查看:

    可以看到,生成了sqlsource对象,再将sql通过addselectmappedstatement方法添加到mappedstatements中。

    到此这篇关于mybatis-plus 通用crud的文章就介绍到这了,更多相关mybatis-plus 通用crud内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!