第一部分:介绍一下mybatis-plus以及她的一些优点
mybatis-plus官网强烈建议学习的时候可以去官网查,官网讲的也比较仔细这里是我的理解:之前用过jpa也用过mybatis,jpa的特点就是普通的单表操作超级简单,但是多表操作就非常复杂,很难理解,操作的是实体对象,针对的是一个数据表,所以每次返回的都是你操作这个数据库表的实体对象。mybatis的特点就是多表操作比较方便,但是对应的简单curd都需要写sql语句,mapper,就显得比较臃肿,mybatis-plus就像是综合了他们的优点。对于简单的单表操作,自己封装了一套方法,对于多表操作也是和mybatis一样,所以官网这样介绍mybatis-plus:MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。是最受欢迎的后端框架的第二名 因为这是一篇用爱发电的文章,所以就不多介绍他的特点,官网都可以看到,下面就直接讲怎么用吧 第一步:pom文件映入依赖 <dependency> <!--开源项目名字叫baomidou(苞米豆)挺可爱的--> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>第二步:application.yml配置文件
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=CTT username: root password: 123456 #输出日志 logging: level: root: warn mp.dao: trace pattern: console: "%p%m%n" mybatis-plus: # 在classpath前添加星号可以使项目热加载成功 mapper-locations: classpath*:mybatis/**/*Mapper.xml configuration: map-underscore-to-camel-case: true cache-enabled: false # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl配置文件里的都可以去官网查到具体干嘛的,当然还有很多其他的配置,总之mybatis-plus这么受欢迎是有原因的。 第三步:emmmm,没有第三步下面就可以直接查啦
通用 CRUD 先放一个user实体类 package mp.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.util.Date; @Data//之前的博客有讲这个注解 @TableName("user")//指定特定的数据库表,但只要不是差别很大,不用指定也可以 public class User { //主键 @TableId("id")//用来标识实体类的主键,以便插件在生成主键雪花Id的时候找到哪个是主键。 private String userid;//因为指定了id所所以这名字可以任取,不与数据库id名一样 private String name; @TableField("role")//当取名不一样可以用这个注解 private String role; private Date retime; private Integer age; /** * mp排除非表字段的三种方式 * 1:Transient声明的成员变量不参与序列化过程: private Transient String remark; * 2:如果有序列化要求;设置为静态变量 private static String remark;(但要写getset方法) * 3: @TableField(exist=false) */ //数据库中没有这一条字段,这里只是暂时后台调用这条数据 , // private String remark; }这个实体类解释的够详细吧 假设我们已存在一张 User 表,且已有对应的实体类 User,实现 User 表的 CRUD 操作我们需要做什么呢?
/** User 对应的 Mapper 接口 */ public interface UserMapper extends BaseMapper<User> { }对没错,你只需要写一个接口集成BaseMapper这个通用的mapper
// 初始化 User 对象 User user = new User(); // 插入 User (插入成功会自动回写主键到实体类) user.setName("demo"); result = userMapper.insert(user); // 更新 User user.setAge(18); result = userMapper.updateById(user); // 查询 User User exampleUser = userMapper.selectById(user.getId()); // 查询姓名为‘demo’的所有用户记录 List<User> userList = userMapper.selectList( new EntityWrapper<User>().eq("hero", "demo") ); // 删除 User result = userMapper.deleteById(user.getId());是不是出现了一些新的东西了感觉?什么是eq这就需要你们去官网查了,这是mybatis-plus的条件构造器AbstractWrapper,定义了很多的方法,用到什么去看一看就好了
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作 上面的这三种都是mybatis-plus的新特性,lambda调用后面会讲到,支持自动主键生成很强了,有基于facebook的雪花算法也有其他的id类型,这需要你在上面的配置里卖弄配置你想要的id算法,默认好像就是雪花算法,也可以自己设置id。AR模式的话,简单试着用了下,感觉方便还是方便,不过就是一种新的思路理解了。
简单讲一下AR模式吧: 你甚至上面讲的统用mapper都不用实现只需要实体类继承extends Model<>就可以了
package mp.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; @Data @TableName("test")//指定特定的数据库表,但只要不是差别很大,不用指定也可以 public class Test extends Model<Test> { //主键 @TableId(type= IdType.UUID)//用来标识实体类的主键,以便插件在生成主键雪花Id的时候找到哪个是主键。//String类型的id private String id;//因为指定了id所所以这名字可以任取,不与数据库id名一样 private String name; private Integer age; }用测试方法写了curd
package mp; import mp.entity.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest @RunWith(SpringRunner.class) public class ARtest { //这里类名和test注解重名了所以加test 注解的时候需要详细一点 @org.junit.Test public void arinsert() { Test test = new Test(); test.setName("埃及和奶"); test.setAge(90); boolean flag = test.insert();//AR模式下的curd System.out.println(flag); } @org.junit.Test public void selectByid() { Test test = new Test(); Test newTest = test.selectById(123);//返回的是一个新对象 } @org.junit.Test public void selectByid2() { Test test = new Test(); test.setId("123"); Test newTest = test.selectById();//返回的是一个新对象 } @org.junit.Test public void updateByid() { Test test = new Test(); test.setId("123"); test.setName("sdfsdsdf"); test.updateById();//返回的是一个boolean } @org.junit.Test public void deleteByid() { Test test = new Test(); test.setId("123"); test.deleteById();//返回的是一个boolean } }实体类都有了,下面就在代码里面讲Lambda和其他条件数据库操作吧,耐心吧下面的代码看完,你就知道mybatis-plus是怎么操作数据库的了,代码注释很多,你会看懂的
@Autowired private UserMapper userMapper; @Test public void insert(){ User user = new User(); user.setUserid("00");//可以不设置id,会自动生成 user.setName("向不i哦啊的"); user.setRole("dsa12q d"); user.setRetime(new Date()); int rows = userMapper.insert(user);//返回成功数量 } private UserMapper userMapper; 查询多个id,返回对象集合 public void selectids(){ List<String> idsList = Arrays.asList("0","5","9"); List<User> userList = userMapper.selectBatchIds(idsList); userList.forEach(System.out::println); } //根据多个条件,查询返回符合条件的所有对象,list集合//map中的键(key)是数据库中的列名不是实体中的属性名 public void selectByMap(){ //map.put("name","顺丰大概"); //map.put("role","dsa12q d"); //这样就类似于where name = "顺丰大概" and role = "dsa12q d" Map<String,Object> columnMap = new HashMap<>(); columnMap.put("name","顺丰大概"); columnMap.put("role","dsa12q d"); List<User> userList = userMapper.selectByMap(columnMap); userList.forEach(System.out::println); } /** * 条件构造器: *名字中含有三,且角色是员工的 * name like ‘%三%’ and age < 40 * queryWrapper.select("id","name")like("name","三").lt("age",40);//这里返回的是这个对象的固定两个字段,返回的还是对象 */ @Test public void selectByWrapper(){ QueryWrapper<User> queryWrapper = new QueryWrapper<User>();//QueryWrapper继承了AbstraptWrapper // QueryWrapper<User> query = Wrappers.<User>query();和上面一样。 queryWrapper.like("name","三").lt("age",40);//lt()//默认条件是小于 List<User> userList =userMapper.selectList(queryWrapper); userList.forEach(System.out::println); /**名字中含有三,且年龄在20和40之间,角色是不为空的 * name like ‘%三%’ and age between 20 and 40 and role is not null * queryWrapper.like("name","三").between(“age”,20,40).isNotNull(“role”) * * 名字为张姓或者年龄大于等于25,按照年龄降序排序,年龄相同按照id升序排列 * name like “张%” or age >=25 order by age desc,id asc;//默认是and如果是or需要.or(); * queryWrapper.likeRight("name","张").or().ge("age",25).orderByDesc("age").orderByAsc("id"); * * 创建日期是2019年2月11日并且直属上级为名字为王性 * dete_format(create_time,'%y-%m-%d')and manager_id in(select id from user where name like "王%")//子查询就是inSql * queryWrapper.apply("dete_format(create_time,'%y-%m-%d')={0}","2019-02-11").inSql("manager_id","select id from user where name like "王%"")// * 上面查时间也有一个 参数的方法,但有可能sql注入的问题(就是sql语句中不小心写了其他(or true or true)查询结果就不对,产生风险) * * 名字为王性并且(年龄小于40或邮箱不为空) wq->wq是lomoda表达式 * queryWrapper.likeRight("name","王").and(wq->wq.lt("age",40).or().isNotNull("email")); * * 名字为王性或者(年龄小于40并且年龄大于20并且邮箱不为空) * name like '王%' or (age< 40 and age >20 and email is not null) * queryWrapper.likeRight("name","王").or(wq->wq.lt("age",40).gt("age".20).isNotNull("email")) * * (年龄小于40或者邮箱不为空)并且名字为王性//括号和没有括号不一样。or的优先级小于and的优先级 * (age <40 or email is not null)and name like '王%' * queryWrapper.nested(wq->wq.ly("age",40).or().isNotNull(email)).likeRight("name","王") * * 年龄是31,30,35 * age in (31,30,35) * queryWrapper.in(“age”,Arrays.asList(31,30,35)) * * 返回满足条件的一条语句,而不是返回所有满足的结果 * limit 1 * queryWrapper.in(“age”,Arrays.asList(31,30,35)).last("limit 1") * * 条件构造器中condition的使用 * 就是当前端传来两个变量要查询的时候,前端可以只输入一个变量也可以查询,condition作为一个条件,如果true就表示这个语句静茹查询条件 * name like ‘%三%’ and age < 40 //以前是先写个判断语句在查询,现在只用一行,就可以是实现 * queryWrapper.like(StringUtils.isNotEmpty(name),"name","name").like(StringUtils.isNotEmpty(email),"email","email");/ *queryWrapper.like(condition,"name","name")//condition来控制where语句加不加入到sql语句中 * * //实体作为条件构造器构造方法的参数,这样会将user1对象中的所有非空的属性加入sql语句查询,也可以再继续加条件,是互不干扰了,但不要重了 * //当controller中用实体接受前台页面传过来的数据,这样就可以全部或者部分不用写条件,之间对象查找 * QueryWrapper<User> queryWrapper = new QueryWrapper<User>(user1);//QueryWrapper继承了AbstraptWrapper * List<User> userList =userMapper.selectList(queryWrapper); */ } @Test//lambda条件构造器,防止写错数据库中字段名 public void selectLambda() { LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();//QueryWrapper继承了AbstraptWrapper // QueryWrapper<User> query = Wrappers.<User>query();和上面一样。 lambda.like(User::getName, "三").lt(User::getAge, 40);//lt()//默认条件是小于 List<User> userList = userMapper.selectList(lambda); userList.forEach(System.out::println); } //分页查询 @Test public void selectByPage() { QueryWrapper<User> queryWrapper = new QueryWrapper<User>();//QueryWrapper继承了AbstraptWrapper queryWrapper.like("name","三"); Page<User> page = new Page<User>(1,2); // IPage<User> ipage = userMapper.selectPage(page,queryWrapper);//返回实体 IPage<Map<String,Object>> ipage = userMapper.selectMapsPage(page,queryWrapper);//返回map System.out.println("总页数:"+ipage.getPages()); System.out.println("总记录数:"+ipage.getTotal()); List<Map<String,Object>> userList = ipage.getRecords(); userList.forEach(System.out::println); } public void selectAll() { LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();//QueryWrapper继承了AbstraptWrapper lambda.like(User::getName, "三").lt(User::getAge, 40); List<User> userList =userMapper.selectAll(lambda); userList.forEach(System.out::println); public void selectById(){ User user = userMapper.selectById(9); System.out.println(user); } @Test public void deleteById(){ int rows = userMapper.deleteById("0"); System.out.println(rows); } @Test//符合条件都都将会删除 public void deleteByMap(){ Map<String,Object> columnMap = new HashMap<>(); columnMap.put("name","顺丰大概"); columnMap.put("role","dsa12q d"); int rows = userMapper.deleteByMap(columnMap); } @Test//同时删除多个记录 public void deleteByds(){ int rows = userMapper.deleteBatchIds(Arrays.asList("5","9")); System.out.println(rows); } @Test//带条件构造器的删除方法 public void deleteByWrapper(){ LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User>lambdaQuery(); lambdaQuery.eq(User::getAge,33).or().gt(User::getAge,47); int rows = userMapper.delete(lambdaQuery); System.out.println(rows); } }看到这是不是有点疑问,这怎么和mybatis的完全不一样啊,没有xml,没有配置,上面讲的就是mybatis-plus的新特性,新的查询方法,这就是他官网讲的没有改变只是提高,这就是提高的那一部分,原来mybatis的那样的操作也可以使用,就是原来一样, 以上就是博主一天的学习成果啦,看官网的文档很有帮助,还有就是看baseMapper的源码,按住ctrl点击就可以景区看源码啦,这个框架的源码相对来说还是比较简单易懂的。进阶程序员必备技能,理解源码如果感觉有帮助就点赞鼓励下吧,嘿嘿
