Mybatis-Plus最优化持久层开发

Mybatis-plus:最优化持久层开发

一:Mybatis-plus快速入门:

1.1:简介:

Mybatis-plus(简称MP)是一个Mybatis的增强工具,在mybatis的基础上只做增强不做改变; 提高效率;自动生成单表的CRUD功能;
提供了丰富的条件拼接方式;
全自动ORM类型持久层框架;(不仅提供数据库操作的方法,还会提供sql语句的实现)

1.2:Mybatis-plus快速入门:

!!!!!!!!!!!!!!!!!!!!!!!!!!!
如果我们想要对User表的数据进行单表CRUD:我们使用Mybatis-plus之后:我们只需要:1.创建mapper接口2.继承 BaseMapper<User> (<>:要操作的表/实体类):我们就会拥有CRUD方法+CURD的sql语句注意:继承的BaseMapper(它里面有单表的增删改查方法),就不用写mapper.xml文件了,之后就可以直接使用mapper对象调用相应的CRUD方法即可进行数据库的操作了!!!

Mapper接口

public interface UserMapper extends BaseMapper<User>{/*原来Mybatis中:我们需要在mapper中自定义方法,然后在mapper.xml中使用sql实现方法但是使用了Mybatis-plus之后,我们直接继承 “BaseMapper<>”:它里面有单表的增删改查各种方法以及实现我们继承它以后就拥有了这些方法,就不用写mapper.xml文件了;*/
}

SpringBoot测试类

@SpringBootTest  //这个注解:就会自动完成ioc容器初始化,我们想要谁直接拿即可!!!!!!!!!!!!!!!!!
public class SpringBootMybatisPlusTest {@Autowiredprivate UserMapper userMapper; //拿到对象!!!public void test(){List<User> users = userMapper.selectList(null); //不传参数:直接写null:代表查询全部数据;直接调用baseMapper接口中相应的方法即可}
}

二:Mybatis-plus的核心功能

Mybatis-plus是如何增强的

Mybatis-plus可以对三层架构的两层进行增强:
1.MapperC层:只要继承,就拥有了crud方法
2.Service层:继承

原理:!!!!!!!!
mapper接口只要继承BaseMapper<实体类> 接口:接下来我们就能使用通过mapper对象和BaseMapper接口中提供的CRUD方法来对  实体类表 进行操作;

2.1:基于Mapper接口的CRUD

(1)mapper接口如果我们想要对User表的数据进行单表CRUD:我们使用Mybatis-plus之后:我们只需要:1.创建mapper接口2.继承 BaseMapper<User> (要操作的表/实体类):我们就会拥有CRUD方法+CURD的sql语句*/public interface Use rMapper extends BaseMapper<User> {//继承之后:下面就相当于有了方法}(2)测试类:@SpringBootTest
public class MybatisPlusTest {@Autowiredprivate UserMapper userMapper;//(1)insert:@Testpublic void test(){User user=new User();user.setName("kun");user.setAge(88);user.setEmail("xxx");//baseMapper提供的数据库insert方法int row = userMapper.insert(user);}//(2)delete:@Testpublic void test_delete(){//1.根据id删除:()内装值int rows = userMapper.deleteById(1687124323556002889L);//2.根据id删除:age=20  name=jack; ()内装条件: -->拼接条件Map param=new HashMap();param.put("age",20);     //-->删除age=20 + name=jackparam.put("name","jack");int i = userMapper.deleteByMap(param);System.out.println("i = " + i);//wrapper 条件封装对象,无限封装条件;//userMapper.delete(wrapper)}//(3)Update()@Testpublic void test_update(){//1.将主键userId为1的age改为30:  ()内装值//update user set age=30 where id=1:就等同于下方User user=new User();user.setId(1L);user.setAge(30);int i = userMapper.updateById(user);//2.将所有人age改为20User user1=new User();user1.setAge(20); //int update = userMapper.update(user1, null);// null:代表没条件,该所有System.out.println("update = " + update);/*TODO:update:当属性为null时:代表不修改updateById():实体类的id必须有值update() :实体类可以没有id值*/}//(4)select a:根据主键查询  b:根据主键集合查询public void test_select(){//a:根据id查询User user = userMapper.selectById(1);//b:根据集合查询:eg:根据ids查询List<Long> ids=new ArrayList<>();ids.add(1L);ids.add(2L);List<User> users = userMapper.selectBatchIds(ids); //selectBatchIds:批量idsSystem.out.println("users = " + users);}}

2.2:就Service接口的CRUD

service接口继承:

2.3:分页查询实现:

Mybatis-plus实现分页查询:!!!!使用步骤:1.导入分页插件2.使用分页查询

-04@SpringBootApplication
@MapperScan("com.atguigu.mapper")
/*
启动类也是配置类:所以我们可以声明带@Bean的方法
1.配置一个分页的插件:Mybatis-plus提供的,我们直接加进来使用就行了;在配置类/启动类:中使用@Bean返回*/public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Bean//1.将Mybatis-plus插件加到ioc容器public MybatisPlusInterceptor plusInterceptor(){//a:是所有Mybatis-plus的插件集合:我们想要使用任何插件都可以加到这个集合中去;eg:我们可以将分页插件加到里面;MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();//b:加入分页插件:mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//指定数据库return mybatisPlusInterceptor;}
}/*
测试类:
2.之后就可以使用分页插件了:*/
@SpringBootTest
public class MybatisPlusTest {@Autowiredprivate UserMapper userMapper; //注入UserMapper对象:进行数据库操作@Testpublic void testPage(){//a:创建Page对象: 参数解释:(参数1:页码, 参数2:页容量)Page<User> page=new Page<>(1,3);userMapper.selectPage(page,null); //需要放入Page对象//最后分页的结果也会被封装到page里面:-->所以直接通过page对象获取结果即可long pages = page.getPages();long current = page.getCurrent(); //获取当前页码、List<User> records = page.getRecords(); //获取当前页数据long total = page.getTotal();//获取总条数}}

自定义mapper方法使用分页

上面:我们是使用Mybatis提供的方法:  userMapper.selectPage(page,null);
如果我们自定义的mapper方法想要使用分页查询:1.在mapper接口中定义方法:自定义方法想要分页:在第一个参数加一个IPage对象,返回值也是IPage2.在mapper文件中实现:使用sql语句实现:不要加limit和;3.测试

1.public interface UserMapper extends BaseMapper<User> {//继承BaseMapper接口:里面有单表的方法/*演示:自定义mapper方法实现分页:eg:查询*///1.在mapper接口中定义抽象方法:但是:方法的第一个参数:要传一个IPage,返回值要是IPage,里面写查询集合的泛型即可IPage<User> queryByAge(IPage<User>page, @Param("age") Integer age);
}2.<!--2.使用sql语句实现UserMapper接口的方法:不用在最后加limit,!--><select id="queryByAge" resultType="com.atguigu.pojo.User"> <!--resultType:泛型-->select * from user where age>#{age}</select>3./*3.测试自定义方法分页*/public void test_MyPage(){//a:传一个分页插件的值:Page<User> page=new Page<>(1,3);//b.userMapper.queryByAge(page,1);//c://最后分页的结果也会被封装到page里面:-->所以直接通过page对象获取结果即可long pages = page.getPages();long current = page.getCurrent(); //获取当前页码、List<User> records = page.getRecords(); //获取当前页数据long total = page.getTotal();//获取总条数System.out.println("total:"+total);}}

2.4:条件构造器使用:

2.4.1条件构造器的作用:
warpper对象:动态进行 条件的拼接;
就相当于在sql语句后面加条件,只是使用java代码的格式;
---->:就不用在mapper.xml文件中使用sql语句实现了,直接使用java代码来代替sql语句;!!!!!!!!

warpper对象:动态进行 条件的拼接;
就相当于在sql语句后面加条件,只是使用java代码的格式;
---->:就不用在mapper.xml文件中使用sql语句实现了,直接使用java代码来代替sql语句;!!!!!!!!

2.4.2条件构造器的类结构:
一般使用:第一种: UpdateWrapper(修改)、QueryWrapper(删除、查询、修改)第二种: LambdaUpdateWrapper(修改)、 LambdaQueryWrapper(删除、查询、修改)
  • (1)第一种:基于queryWrapper组装条件:增/删/改

      使用方法:1.在mapper接口中定义方法,并继承base接口(提供了各种方法的实现)2.直接使用java代码实现:不需要在mapper.xml文件中实现了//a:创建QueryWrapperQueryWrapper<实体类>queryWrapper=new QueryWrapper<>();//b:条件拼接:调用queryWrapper方法//c:使用mappper对象:调用CRUD方法,传入对象即可
    

1.mapper接口:public interface UserMapper extends BaseMapper<User> {//继承BaseMapper接口:里面有单表的方法/*演示:自定义mapper方法实现分页:eg:查询*///1.在mapper接口中定义抽象方法:但是:方法的第一个参数:要传一个IPage,返回值要是IPage,里面写查询集合的泛型即可IPage<User> queryByAge(IPage<User>page, @Param("age") Integer age);
}2./*
演示条件构造器使用:进行条件的动态拼接:(1)QueryWrapper测试:*/
@SpringBootTest
public class MybatisPlusQueryWrapper {@Autowiredprivate UserMapper userMapper; //拿到对象:操作数据库@Testpublic void test_01(){//查询用户名包含 a,age在20到30之间的,且邮箱不为空的用户;//分析:查询:返回的是集合List-->selectList//a:创建一个QueryWrapper集合:相当于容器来装条件QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:之后sql语句的条件:直接使用queryWrapper动态调用wrapper的方法来完成动态拼接;queryWrapper.like("name","a"); //条件1:name种包含a的queryWrapper.between("age",20,30); //条件2:age在20-30之间queryWrapper.isNotNull("email"); //第三个条件:email不为nullList<User> users = userMapper.selectList(queryWrapper);  ----->:因为继承了base接口,所以单表直接调用方法即可!//queryWrapper就是sql条件,将它·传进去!!!//之后这个就会变成sql语句; !!!!!!!!!!!//就相当于:select  * from user where name(like %a% and age>=20 and age<=30 and email is not null)/*!!!一个个调用麻烦,可以使用链式调用:!!!!queryWrapper.like("name","a").between("age",20,30).isNotNull("email");*/}
}

(2)queryWrapper实战使用:

	@SpringBootTestpublic class MybatisPlusQueryWrapper {@Autowiredprivate UserMapper userMapper; //拿到对象:操作数据库按照年龄降序查询用户,如果年龄age相同则按id升序排列//(2)queryWrapper:按年龄降序查询用户,如果年龄相同则按id升序排列@Testpublic void test_02(){//a:创建QueryMapper集合:装条件QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:使用条件构造器进行条件的拼接:queryWrapper.orderByDesc("age").orderByAsc("id");//a:条件1:age降序排列; b:条件2:id增序//c:放到queryWrapper中,进行条件拼接; ==order by age desc,id ascList<User> users = userMapper.selectList(queryWrapper);}//(3)删除email为null的用户@Testpublic void test_03(){//a:QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:queryWrapper.isNotNull("email");//c:int delete = userMapper.delete(queryWrapper);}//(4):将age>20且用户名中包含a或email为null的用户信息修改://分析:修改:--update:所以usermapper调用update方法:相应的条件:age>20... 使用queryWrapper封装,然后作为条件放入update方法形参中;!!!!!@Testpublic void test_04(){//a:QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:添加条件:queryWrapper.gt("age",20).like("name","a")                ---------->B:相当于:where ........or().isNotNull("email");//1.条件:age>20 name包含a,--->:条件直接调用时:默认自动使用and进行拼接;!!!!!//queryWrapper.gt("age",20).like("name","a") == where age>20 and ..      //2.如果想要在条件之后追加or关键字:可以使用: “or().条件”;//c:创建User对象,进行update修改User user=new User();user.setAge(88);                ----->A:相当于update user  set name="" age= user.setEmail("hehe");//d:如果要修改:第一位传入要修改的对象userMapper.update(user, queryWrapper); //放入对象 + queryWrapper}//(5):查询用户信息的name和age字段;  --->指定列查询!!!//select name,age from t_user where id>1;public void test_05() {//a:QueryWrapper<User> queryWrapper = new QueryWrapper<>();//b:条件拼接:queryWrapper.gt("age",1);//!!!查询时:默认是查询全部���!!!!!,但可以使用select指定queryWrapper.select("name","age");userMapper.selectList(queryWrapper);}//(6)前端传入两个参数,name,age:---->:动态条件组织判断!!!!// 只要name不为null,就作为条件 来查询符合的//只要age>18作为条件,就作为条件 来查询符合的@Testpublic void test_06(){String name="xx";Integer age=19;//a:QueryWrapper<User>queryWrapper=new QueryWrapper<>();//b:进行条件拼接://b.1:如果name!=null,就使用queryWrapper进行条件拼接if(StringUtils.isNotBlank(name)){  //调用isNotBlank进行判断//动态条件判断:如果name不为null,就进行条件的拼接queryWrapper.eq("name",name); //使用queryWrapper进行拼接}//b.2:如果age>18 进行动态拼接:if (age>18 && age!=null){queryWrapper.eq("age",age);}userMapper.selectList(queryWrapper);/*注意:!!!!!!!!!!!!!!!!Wrapper每个方法都有:一个boolean类型的condition,允许我们第一个参数放一个比较表达式,:如果condition为true-->整个条件为true,就执行下面代码:如果condition为false-->整个条件为false,就失效,不执行下面代码-->condition里面有动态判断,就不用我们在外部写判断了eg:*/queryWrapper.eq(StringUtils.isNotBlank(name),"name",name);queryWrapper.eq(age>18 && age!=null,"age",age);}

updateWrapper:改

进行修改时:使用updateWrapper:!!!!

     //a:UpdateWrapper<User> queryWrapper=new UpdateWrapper<>();//b:queryWrapper.gt("age",20).like("name","a").isNotNull("email").set("email",null).set("age",100);//c:userMapper.update(null,queryWrapper);

在修改时updateWrapper和queryWrapper区别:

(参数1:条件; 参数2:修改的数据)
queryWrapper修改:参数1只能放条件,且列名不能为null
updateWrapper修改:参数1可以放条件, 且列名可以设置为null;且可以直接调用set方法进行修改
  • (2)第二种:

      和第一种用法一样,只是对第一种的增强eg:Lambda:避免列写错的机制:传入的列名可以是” 方法引用的表达式 “:类名::getName -->相当于找方法对应的列名
    

LambdaQueryWrapper:增/删/改

eg:
查询用户名包含 a like,年龄在20-30之间,并且邮箱不为null的用户信息;LambdaQueryWrapper<User>lambdaQueryWrapper=new LambdaQueryWrapper<>();//即只要将原来的列名,变为Lambda方法引用即可,其余不变!!!!!!!!!!lambdaQueryWrapper.like(User::getName,"a").between(User::getAge,20,30).isNotNull(User::getEmail);userMapper.selectList(queryWrapper);

LambdaupdateWrapper:改

eg:LambdaUpdateWrapper<User>lambdaUpdateWrapper=new LambdaUpdateWrapper<>();//即只要将原来的列名,变为Lambda方法引用即可,其余不变!!!!!!!!!!lambdaUpdateWrapper.gt(User::getAge,20).like(User::getName,"a").isNotNull(User::getEmail).set(User::getEmail,null).set(User::getAge,100);userMapper.update(null,lambdaUpdateWrapper);

(3)总结:

Wrapper:里面:完成了动态条件封装
最终推荐使用Lambda;(不用写列名,只需类名::方法即可)如果复杂的sql:qg:嵌套、子查询 不会使用Wrapper怎么办:我们仍然使用原来的:定义mapper如果为单表的话:直接使用mapper对象调用CRUD方法即可;如果为多表的话:在mapper.xml文件中实现;

2.5Mybatis-plus核心注解的使用:

注解的作用:指定实体类和表之间的映射;

1.@TableName
作用:指定数据库表名;(当【BaseMapper<实体类>】 实体类名 和 数据库表名不同时);
使用:@TableName("数据库表名")a:位置:加到实体类上
b:可以不加,不加的话默认使用实体类的名字作为 表名! 忽略大小写;  eg:BaseMapper<User>:默认将实体类名:User,作为表名 来进行操作;c:使用@TableName注解场景:当数据库的表名和实体类名称不同时(忽略大小写),需要使用@TableName来指定 表名:eg:数据库名:t_user;  实体类名:User两个名称不同,此时我们需要在实体类上方使用: ”@TableName("t_user")“ 来指定表名;
d: 如果表名命名规范:eg:都以 "t_"开头,且除了”t_“以外,实体类名=表名我们可以将前缀统一提取到配置文件中(application.yml),这样就不需要每个实体类都加@TableName注解来指定表名了它会自动查找相应的表;mybatis-plus:global-config:db-config:table-prefix: t_ #表名前缀;#加了这个之后,我们就不需要在每个实体类加@TableName注解了,它就会自己根据前缀"t_"进行查找;#前提:数据库的表都是以 “t_”开头的
2.@TableId:
作用:描述主键的一些特性; eg: value:指定表主键名;  type:设置主键type策略
使用:在实体类的主键属性上:+@TableId(value="主键列名",type="主键策略");b:位置:加到实体类的主键属性上
c:使用@TableId的场景:场景1:表 主键的列名 和 实体类的属性名 不一致时,使用这个注解来指定表的列名;!!!eg: 1:如果 实体类属性名:id; 数据库主键列名:x_id; --->两个名称不一样,我们可以在实体类主键的属性上方加@TableId(value="x_id") 场景2:设置表主键增长:type主键策略:

type增长策略:

@SpringBootTestpublic class MybatisPlusTableIdTest {@Autowiredprivate UserMapper userMapper;@Testpublic  void test_01(){//以插入数据举例:User user=new User();user.setName("坤坤");user.setAge(20);user.setEmail("xxx@qq.com");//插入的时候:主键id不要赋值; 主键自增长 或者 type策略 进行赋值!!!!!!!!!!!!/*1.默认主键的type(策略)是:雪花算法;--->:它会生成一个不重复的long类型的数字; eg:123456789雪花算法:a:要求数据库主键是 bigint / varchar(64) 类型;         -->:eg:varchar(64)/bigint money;!!!b:要求实体类相应属性:使用Long/String接值(int接不到)  -->:eg:Long/String  money;!!!c:随机生成一个数字,给予主键值(不重复)2.但我们想要把主键type(策略)变成auto自增长,方式1:直接在实体类的主键上方加:@TableId(type= IdType.AUTO); 前提是mysql数据库必须设置了主键自增长(auto_increment)auto:a:要求mysql数据库的 表主键 必须设置了 自增长b:插入数据就是自增长了方式2:全局设置主键自增长策略:如果每个表都设置为自增长(auto),在配置文件(application.yml)中配置*/userMapper.insert(user); //之间调用BaseMapper中的insert方法;}
}User视图类:public class User(){@TableId(type = IdType.AUTO)private Long id;   }
3.@TableFiled
作用:描述非主键字段
使用:在实体类的非主键字段上:+@TableFiled(value="",exist="")a:使用场景1:value="" (不是必须指定的,String类型):当实体类的属性名 和 列名 不同的时候 使用@TableFiled指定数据库表名;使用场景2:esist=ture/false; (默认为true):eg:@TableFiled(value="name",exist=false):private String name;-->:false代表:认为name没有数据库对应的列,因此在查询等时候不会对他进行操作;

三:Mybatis-plus高级扩展

3.1逻辑删除实现:

(1)逻辑删除概念:
逻辑删除:是 "假删除数据":是将想要删除数据的状态修改为 "被删除状态",但是数据并没有消失,之后在查询时,查询没有 删除状态 的数据,也是一种删除;物理删除:delete from:删除之后就没有了相应的数据;(2)逻辑删除的实现:方式1:单个表逻辑删除的实现:a:在数据库表中 插入一个逻辑删除字段(int类型,有1/0状态字段!):alert table User add deleted int default 1/0; -->: 1/0:逻辑删除的状态字段:1代表:逻辑删除; 0代表:未逻辑删		除;!!!!b:在实体类的对应属性上加:@TableLogiceg:@TableLogic //代表这个属性对应的列是 :逻辑删除状态字段//当我们删除数据时候,自动变成修改此列的属性值(即将deleted变为1);   默认:0是未删除,1是删除//当我们查询数据时候:默认只查询 deleted=0 的列的数据private Integer deleted;方式2:多个表逻辑删除的实现(全局指定):a:同上b:在配置文件(application.yml)中:配置mybatis-plus:global-config:db-config:logic-delete-field: deleted # 全局逻辑删除的实体属性名注意:这种就不需要在类的属性名上 + @TableLogic了但是仍然需要在实体类中创建一个和列名deleted 对应的属性名;

代码演示:

以单个表实现逻辑删除为例:@TableLogicprivate Integer deleted;@SpringBootTest
public class MybatisPlusTableLogicTest {@Autowiredprivate UserMapper userMapper;public void test_01(){//a:之前是物理删除:delete from user where id=5;//b:现在:逻辑删除:相当于:update user set deleted=1 where id=5userMapper.deleteById(5);//eg:userMapper.selectList(null); -->之后在查询时:就只会查询deleted=0的了:!!!!!(自动在条件位置加上where deleted=0)}

3.2乐观锁的实现

1.乐观锁 和悲观锁 都是在 并发编程 中用于处理并发访问和资源竞争的两种不同机制;2.(1)悲观锁:同步锁/互斥锁:线程在访问共享资源之前会获取到锁,在数据访问时只允许一个线程访问资源,只有当前线程访问完成只后,才会释放锁,让其它线程继续操作资源;(2)乐观锁:不需要提前加锁,而是在数据更新阶段进行检测乐观锁和悲观锁是两种解决并发数据问题的思路,不是技术!!3.具体的技术和方案:1.乐观锁实现方案和技术版本号/时间戳CAS无锁数据结构2.悲观锁的实现方案和技术锁机制数据库锁信号量4. 现在主要学习如何使用乐观锁(版本号)解决并发问题!!!!!!!(1)版本号:解决数据并发更新出现错误数据的问题;--->保证数据一致性;(2)乐观锁技术的实现流程:a:每条数据添加一个版本号字段versionb:取出记录时,获取当前versionc:更新时,检查获取版本号是不是数据库当前最新版本号d:如果是(代表没人修改过数据),执行更新:set数据更新,version=version+1e:如果不是(证明已经修改过了),更新失败5.使用mybatis-plus数据使用乐观锁步骤: 1.数据库插入一个version字段:alert table user add version int default 1  (int类型 乐观锁字段)2 实体类创建相应的属性: private Integer version;  + 在属性上方使用@Version注解3.添加拦截器(添加版本号更新插件)之后在更新的时候就会检查版本,检查数据错误的问题;

乐观锁测试:

1.alter  table user add version int default 1;  #int 类型 乐观锁字段2.
public class User {@Versionprivate Integer version; //版本号字段
}//注意:之后在数据修改时都会检查乐观锁;3.在配置类/Main类中加入拦截器public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Beanpublic MybatisPlusInterceptor plusInterceptor(){//拦截器2:乐观锁【版本号插件】 mybatis-plus在每次更新时候,每次帮我们对比版本号字段和增加版本号+1mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;}4.
/*
测试乐观锁实现*/
@SpringBootTest
public class MybatisPlusVersionTest {private UserMapper userMapper;@Testpublic void testById(){//步骤1:先查询,再更新 获取version数据//同时查询两条,但是version唯一,最后更新的失败、User user=new User();  //user 版本号为:1User user1=new User(); //user1 版本号为:1user.setAge(20);user.setAge(30);userMapper.updateById(user); //20-->:此时数据库的version ->2//乐观锁生效:失败userMapper.updateById(user1);//因为user1的版本号为1,但是数据库的版本号为2,证明不是最新数据 -->1!=2,乐观锁生效,更新失败//所以最终age为:20}
}

3.3防止全表更新和删除

在开发中一般不会出现全表的更新/删除:Mybatis-plus提供一种防御插件:一旦检测到是全表的update/delete:就会报异常;实现方法:添加防止全表更新和删除的拦截器:

代码测试:

1.加入拦截器/插件:
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Beanpublic MybatisPlusInterceptor plusInterceptor(){//拦截器3:防止全表删除和更新的拦截器mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return mybatisPlusInterceptor;}2.测试类中:public void test(){@Au..private UserMapper userMapper; //拿到mapper对象,进行数据库操作!!!;//a:全表删除!mapper.delete(null); ----->:null,代表没有写条件,代表:全表删除;//b:全表更新:mapper.update(null); ------>: null,代表没有条件,代表全表更新!----------->:之后就会抛出异常:不允许全表delete/update!!!!!!!}

四:Mybatis-Plus代码生成器(MybatisX插件)!!!

学习目标:1.如何使用MybatisX插件: 逆向工程 生成Mybatis-Plus代码;//逆向工程:根据表自动生成实体类、mapper、service;!!!!!!!!!!!!!!!!!!!!!!2. 使用MybatisX插件 动态生成自定义的sql语句

4.1Mybatis插件逆向工程

//逆向工程:根据表自动生成实体类、mapper、service;!!!!!!!!!!!!!!!!!!!!!!步骤:连接数据库;.....

4.2Mybatis-plus快速生成单表CRUD代码(自定义sql)!!!!!!!!

如果我们需要自己定义一些sql语句:eg:批量查询、根据id查询......//步骤:1.直接在mapper接口中书写相应的 ” 方法名 “ (//按照mybatisX的方法命名规则)eg:批量插入:insertBatch根据条件查询:selectByNameAndAgeAndAge2.然后鼠标放在方法名上,点击MybatisX,--->MybatisX 就会在mapper接口自动写好 且 在mapper.xml文件中自动生成sql语句!!!!!!!!//之后有关单表的CRUD我们就不需要自己写了!!!!!!!!!!//我们可以看mybatisX的官方文档:介绍了如何写

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/45136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国漫推荐11

1.《元龙》 2.《恶魔法则》2023年9月29日 3.《三十六骑》 4.《山河剑心》 5.剑网3侠肝义胆沈剑心 《剑网3侠肝义胆沈剑心》 《剑网3侠肝义胆沈剑心 第二季》 《剑网3侠肝义胆沈剑心之长漂》&#xff08;番外&#xff09; 《剑网3侠肝义胆沈剑心 第三季》 6.《仙逆》东方玄幻…

Uniswap V2和Uniswap V3的区别

Uniswap V2和Uniswap V3是两个不同版本的去中心化交易协议&#xff0c;由Uniswap团队开发和维护。它们之间的主要区别包括以下几点&#xff1a; 资金池模型不同: Uniswap V2: 使用恒定乘积市场模型&#xff0c;也就是 x * y k。这意味着每个资金池中的资产的乘积保持不变&…

Transformer的模型的扩展与应用领域的拓展 - Transformer教程

在如今的人工智能领域&#xff0c;Transformer模型已经成为了众多研究和应用的焦点。从自然语言处理到计算机视觉&#xff0c;Transformer模型的扩展与应用领域的拓展带来了无数的可能性。今天&#xff0c;我们就来聊聊Transformer模型的扩展以及它在不同领域的广泛应用。 首先…

生产管理系统功能全拆解:哪些功能是企业真正需要的?

制造业的伙伴经常听到“生产管理”&#xff0c;但很多人可能只是模糊地知道它与工厂、生产线有关。那么&#xff0c;到底什么是生产管理呢&#xff1f;它的重要性又体现在哪里呢&#xff1f;接下来&#xff0c;我就以轻松的方式&#xff0c;带大家走进生产管理的世界&#xff0…

函数练习·二 基础题

# 【以下功能都使用函数封装】 # 提示: 涉及到要返回的题目,请使用return # 基础题 # 1.封装函数&#xff0c;计算从1到某个数以内所有奇数的和并返回 def fn1(n): return sum([i for i in range(1, n, 2)]) print(fn1(7)) # 2.封装函数&#xff0c;判断某个数是否是偶…

微信闪退怎么回事?实用技巧助你轻松应对

在使用微信的过程中&#xff0c;偶尔会遇到闪退的问题&#xff0c;这不仅影响我们的日常沟通&#xff0c;还可能导致重要信息的丢失。那么&#xff0c;微信闪退怎么回事呢&#xff1f;闪退的原因可能有很多&#xff0c;包括软件问题、手机存储不足、系统不兼容等。本文将详细分…

笔记本电脑数据丢失如何恢复?

在计算机网络日益普及的今天&#xff0c;计算机已波及到人们的生活、工作、学习及消费等广泛领域&#xff0c;其服务和管理也涉及政府、工商、金融及用户等诸多方面。笔记本电脑等电子产品被各行各业的人所喜爱和接受&#xff0c;早已成为人们出差的必备品&#xff0c;可以用来…

keepalived高可用集群

一、keepalived&#xff1a; 1.keepalive是lvs集群中的高可用架构&#xff0c;只是针对调度器的高可用&#xff0c;基于vrrp来实现调度器的主和备&#xff0c;也就是高可用的HA架构&#xff1b;设置一台主调度器和一台备调度器&#xff0c;在主调度器正常工作的时候&#xff0…

OS_同步与互斥

2024-07-04&#xff1a;操作系统同步与互斥学习笔记 第9节 同步与互斥 9.1 同步互斥的基本概念9.1.1 同步关系9.1.2 互斥关系9.1.3 临界资源9.1.4 临界区9.1.5 同步机制应遵循规则 9.2 软件同步机制9.2.1 单标志法9.2.2 双标志先检查法9.2.3 双标志后检查法9.2.4 peterson算法 …

BP神经网络与反向传播算法在深度学习中的应用

BP神经网络与反向传播算法在深度学习中的应用 在神经网络的发展历史中&#xff0c;BP神经网络&#xff08;Backpropagation Neural Network&#xff09;占有重要地位。BP神经网络通过反向传播算法进行训练&#xff0c;这种算法在神经网络中引入了一种高效的学习方式。随着深度…

jstat命令介绍

jstat&#xff1a;查看JVM统计信息 一 基本情况二 基本语法2.1 option参数1. 类装载相关的&#xff1a;2. 垃圾回收相关的-gc&#xff1a;显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息。-gccapacity&#xff1a;显示…

【C++】C++-机房收费管理系统(源码+注释)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

LeetCode之最长回文子串

1.题目链接 5. 最长回文子串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/longest-palindromic-substring/description/ 2.题目解析 对于这道题目我们可以使用动态规划的思路来求解&#xff0c;具体思路是&#xff0c;对于一个长度大于2的子串&…

生成式信息检索(问答系统与信息检索的进步)

文章目录 什么是问答系统&#xff08;Question Answering Systems&#xff09;检索系统的演变经典检索系统“Term” 文档搜素的最小单位倒排索引词嵌入的出现预训练语言模型 用于问答的语言模型设计方案选择&#xff1a;封闭式与开放式问答系统对比方案A&#xff1a;封闭式生成…

【干货】一文带你看懂什么是渠道分销?如何管理渠道分销

在当今竞争激烈的市场环境中&#xff0c;企业想要扩大市场份额、提高产品或服务的可见度&#xff0c;有效的渠道分销策略是关键。 什么是渠道分销&#xff1f; 渠道分销&#xff0c;简而言之&#xff0c;是指企业利用中间商&#xff08;如经销商、代理商、零售商等&#xff0…

springboot解压文件流zip压缩包

springboot解压文件流zip压缩包 原始文件存储的地方&#xff1a; 需要在当前目录下解压该文件&#xff0c;如下图&#xff1a; 代码示例&#xff1a; private Result<String> getLocationGuideLayerName(YbYstbtqTaskResolveParam params, String fishnetLayerName)…

华为od100问持续分享-1

我是一名软件开发培训机构老师&#xff0c;我的学生已经有上百人通过了华为OD机试&#xff0c;学生们每次考完试&#xff0c;会把题目拿出来一起交流分享。 重要&#xff1a;2024年5月份开始&#xff0c;考的都是OD统一考试&#xff08;D卷&#xff09;&#xff0c;题库已经整…

入门PHP就来我这(高级)24 ~ Session判断用户登录

有胆量你就来跟着路老师卷起来&#xff01; -- 纯干货&#xff0c;技术知识分享 路老师给大家分享PHP语言的知识了&#xff0c;旨在想让大家入门PHP&#xff0c;并深入了解PHP语言。 上一篇我们介绍了Session管理部分的概念&#xff0c;本文通过session来改写一些用户登录&…

一致性Hash问题及解决方案

Hash算法的应用场景 请求的负载均衡 Nginx的ip_hash策略可以在客户端ip不发生变化的情况下&#xff0c;将其发出的请求始终路由到同一个目标服务器上&#xff0c;实现会话粘滞&#xff0c;避免处理session共享问题。 如果没有ip_hash策略&#xff0c;可以通过维护一张映射表的…

常用包管理工具(apk、apt、yum)常用命令

apk 包管理工具apk是Alpine Linux中使用广泛的一个工具&#xff0c;用于管理软件包的安装、更新、卸载等操作。以下是一些常用的apk命令及其解释&#xff1a; 1.更新 apk update&#xff1a;从远程镜像源更新本地仓库中的所有软件包索引apk upgrade&#xff1a;升级本地已安装…