1.了解Mybatis-plus 1.1代码及文档 文档地址:https://mybatis.plus/guide/
源码地址:https://github.com/baomidou/mybatis-plus
1.2特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响
损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作
强大的CRUD操作:内置通用Mapper、通用Service,仅仅通过少量配置即可实现单表大部分CURD操作,更有强大的构造器,满足各类使用需求
支持Lamba形式调用:通过Lambda表达式,方便的编写各类查询条件,无需再担心字段写错
支持多种数据库:支持MySQL、MarlaDB、Orcale、DB、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer等多种数据库
支持主键自动生成:支持多达4种主键策略(内含分布式唯一ID生成器:Sequence),可自由配置,完美解决主键问题
支持XML热加载:Mapper对应的XML支持热加载,对于简单的CURD操作,甚至可以无XML启动
支持ActiveRecord模式:支持ActiveRecord形式调用,实体类只需继承Model类即可进行强大的CURD操作
支持自定义全局通用操作:支持全局通用方法注入(Write once,use anywhere)
支持关键词自动转义:支持数据库关键词(order、key…)自动转义,还可自定义关键词
内置代码生成器:采用代码或者Maven插件可快速生成Mapper、Model、Service、Controller层代码,支持模板引擎,更有超多自定义配置
内置分页插件:基于MyBatis物理分页,开发者无需关心具体操作,配置好插件后,写分页等同于普通List查询
内置性能分析插件:可输出Sql语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表delete、update操作智能分析阻断,也可自定义拦截规则,预防误操作
内置Sql注入剥离器:支持Sql注入剥离,有效放置Sql注入攻击
1.3架构
2.快速开始 对于MyBatis整合MP常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+MP、SpringBooMybatis+MP
2.1新建数据库 2.2创建工程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > cn.itcast.mp</groupId > <artifactId > itcast-mybatis-plus</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > pom</packaging > <dependencies > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus</artifactId > <version > 3.1.1</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.28</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > 1.1.10</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > <version > 1.18.4</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > 1.7.7</version > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <configuration > <source > 1,8</source > <target > 1.8</target > </configuration > </plugin > </plugins > </build > <properties > <maven.compiler.source > 8</maven.compiler.source > <maven.compiler.target > 8</maven.compiler.target > </properties > </project >
2.3Mybaris + MP 2.3.1创建子Module log4j配置文件
1 2 3 4 5 log4j.rootLogger =DEBUG,A1 log4j.appender.A1 =org.apache.log4j.ConsoleAppender log4j.appender.A1.layout =org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern =[%t] [%c]-[%p] %m%n
2.3.2Mybatis实现查询User 第一步,编写mybatis-config.xml文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <properties resource ="jdbc.properties" > </properties > <environments default ="developement" > <environment id ="developement" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="UserMapper.xml" /> </mappers > </configuration >
第二步,编写User实体对象:(这里使用lombok进行了优化bean操作)
lombok省略了getter和setter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package cn.itcast.mp.simple.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @NoArgsConstructor @AllArgsConstructor public class User { private Long id; private String userName; private String password; private String name; private Integer age; private String email; }
第三步,编写UserMapper接口
1 2 3 4 5 6 7 8 9 package cn.itcast.mp.simple.mapper;import cn.itcast.mp.simple.pojo.User;import java.util.List;public interface UserMapper { List<User> findAll () ; }
第四步,编写UserMapper.xml文件
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="cn.itcast.mp.simple.mapper.UserMapper" > <select id ="findAll" resultType ="cn.itcast.mp.simple.pojo.User" > select * from tb_user </select > </mapper >
第五步,编写测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package cn.itcast.mp.simple;import cn.itcast.mp.simple.mapper.UserMapper;import cn.itcast.mp.simple.pojo.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.util.List;public class TestMybatis { @Test public void testFindAll () throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.findAll(); for (User user : userList) { System.out.println(user); } } }
2.3.3Mybatis+MP实现查询User 第一步,将UserMapper继承BaseMapper,将拥有了BaseMapper中的所有方法:
1 2 3 4 5 6 7 8 9 10 package cn.itcast.mp.simple.mapper;import cn.itcast.mp.simple.pojo.User;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import java.util.List;public interface UserMapper extends BaseMapper <User > { List<User> findAll () ; }
第二步,使用MP中的MybatisSqlSessionFactoryBuilder进程创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package cn.itcast.mp.simple;import cn.itcast.mp.simple.mapper.UserMapper;import cn.itcast.mp.simple.pojo.User;import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.util.List;public class TestMybatisPlus { @Test public void testFindAll () throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.selectList(null ); for (User user : userList) { System.out.println(user); } } }
注意:记得在User类中添加注释 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package cn.itcast.mp.simple.pojo;import com.baomidou.mybatisplus.annotation.TableName;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") public class User { private Long id; private String userName; private String password; private String name; private Integer age; private String email; }
2.4Spring + Mybatis + MP 引入了Spring框架、数据源、构建等工作就交给了Spring管理
2.4.1创建子Module 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <parent > <artifactId > itcast-mybatis-plus</artifactId > <groupId > cn.itcast.mp</groupId > <version > 1.0-SNAPSHOT</version > </parent > <modelVersion > 4.0.0</modelVersion > <artifactId > itcast-mybatis-plus-spring</artifactId > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > ${spring.version}</version > </dependency > </dependencies > <properties > <maven.compiler.source > 8</maven.compiler.source > <maven.compiler.target > 8</maven.compiler.target > <spring.version > 5.0.5.RELEASE</spring.version > </properties > </project >
2.4.2实现查询User 第一步,编写jdbc.properties
1 2 3 4 jdbc.driver =com.mysql.cj.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/mp?characterEncoding=UTF8 jdbc.username =root jdbc.password =root
第二步,编写applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation = "http: //www.springframework.org /schema /beans http: //www.springframework.org /schema /beans /spring-beans.xsd http: //www.springframework.org /schema /context http: //www.springframework.org /schema /context /spring-context.xsd "> <context:property-placeholder location ="classpath:*.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" destroy-method ="close" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> <property name ="maxActive" value ="10" /> <property name ="minIdle" value ="5" /> </bean > <bean id ="sqlSessionFactory" class ="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="cn.itcast.mp.simple.mapper" /> </bean > </beans >
第三步,编写User对象以及UserMapper接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package cn.itcast.mp.simple.pojo;import com.baomidou.mybatisplus.annotation.TableName;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") public class User { private Long id; private String userName; private String password; private String name; private Integer age; private String email; }
2.4.3测试用例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package cn.itcast.mp.simple;import cn.itcast.mp.simple.mapper.UserMapper;import cn.itcast.mp.simple.pojo.User;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class TestMybatisSpring { @Autowired private UserMapper userMapper; @Test public void testSelectList () { List<User> userList = this .userMapper.selectList(null ); for (User user : userList) { System.out.println(user); } } }
注意:期间可能会报错 Invalid bean definition with name ‘dataSource’ defined in class path resource [applicationContext.xml]: Could not resolve placeholder ‘jdbc.driver’ in value “${jdbc.driver}”; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘jdbc.driver’ in value “${jdbc.driver}”
两种解决方法
1.将${}里的内容写死
2.在Test文件夹下创建一个resource文件夹,将文件复制到这里(记得将resource文件夹声明为资源文件夹)
2.5SpringBoot + Mybatis + MP 使用SpringBoot将进一步的简化MP的整合,需要注意的是,由于使用SpringBoot需要继承parent,所以需要重新创建工程,而不是创建子Module
3.通用CRUD 3.1插入操作 测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package cn.itcast.mp.simple;import cn.itcast.mp.simple.mapper.UserMapper;import cn.itcast.mp.simple.pojo.User;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class TestUserMapper { @Autowired private UserMapper userMapper; @Test public void testInsert () { User user = new User(); user.setEmail("itcast.cn" ); user.setAge(78 ); user.setUserName("caocao" ); user.setName("曹操" ); user.setPassword("123" ); int result = this .userMapper.insert(user); System.out.println("result=>" + result); System.out.println("id=>" + user.getId()); } }
User类设置表主键,并设置自增
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package cn.itcast.mp.simple.pojo;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.annotation.TableName;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") public class User { @TableId(type = IdType.AUTO) private Long id; private String userName; private String password; private String name; private Integer age; private String email; }
@TableField 在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有两个:
1.对象中的属性名和字段名不一致的问题(非驼峰)
2.对象中的属性字段在表中不存在的问题
字段名不一致 1 2 @TableField(value = "email") private String mail;
表中不存在 1 2 @TableField(exist = false) private String address;
查询时不返回该字段的值 1 2 @TableField(select = false) private String password;
3.2更新操作 在MP中,更新操作有两种,另一种是根据条件更新
3.2.1根据id更新 1 2 3 4 5 6 7 8 9 10 @Test public void testUpdateById () { User user = new User(); user.setId(1L ); user.setAge(19 ); user.setPassword("333" ); int result = this .userMapper.updateById(user); System.out.println(result); }
3.2.2根据条件更新 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public void testUpdate () { User user = new User(); user.setAge(20 ); user.setPassword("888" ); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_name" ,"张三" ); int result = this .userMapper.update(user,wrapper); } @Test public void testUpdate2 () { UpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.set("age" ,21 ).set("password" ,123123 ) .eq("user_name" ,"caocao" ); int result = this .userMapper.update(null ,wrapper); }
3.3删除操作 3.3.1deleteById 1 2 3 4 5 @Test public void testDeleteById () { int result = this .userMapper.deleteById(2 ); }
3.3.2deleteByMap 方法定义:
1 int deleteByMap (@param(Constants.COLUMN_MAP) Map<String, Object> columnMap) ;
测试类:
1 2 3 4 5 6 7 8 9 @Test public void testDeleteByMap () { Map<String,Object> map = new HashMap<>(); map.put("user_name" ,"张三" ); map.put("password" ,"333" ); int result = this .userMapper.deleteByMap(map); System.out.println(result); }
3.3.3delete 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test public void testDelete () { User user = new User(); user.setUserName("caocao" ); user.setPassword("123456" ); QueryWrapper<User> wrapper = new QueryWrapper<>(user); int result = this .userMapper.delete(wrapper); System.out.println("result=>" + result); }
3.3.4deleteBatchIds 方法定义:
1 int deleteBatchIds (@Param(Constants.COLLECTION) Collection<? extends Serializable> idList)
测试类:
1 2 3 4 5 6 @Test public void testDeleteBatchIds () { int result = this .userMapper.deleteBatchIds(Arrays.asList(10L , 11L )); System.out.println(result); }
3.4查询操作 MP提供了多种查询操作,包括根据id查询、批量查询、查询单挑数据、查询列表、分页查询等操作
3.4.1selectById 3.4.2selectBatchIds 方法定义:
1 List<T> selectBatchIds (@Param(Constants.COLLECTION) Collection<? extends Serializable> idList)
测试类:
1 2 3 4 5 6 7 8 @Test public void testSelectBatchIds () { List<User> userList = this .userMapper.selectBatchIds(Arrays.asList(2L ,3L ,100L )); for (User user : userList) { System.out.println(user); } }
3.4.3selectOne 方法定义:
1 T selectOne (@Param(Constants.Wrapper<T> queryWrapper) ) ;
测试用例:
1 2 3 4 5 6 7 8 @Test public void testSelectOne () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_name" ,"张三" ); User user = this .userMapper.selectOne(wrapper); System.out.println(user); }
3.4.4selectCount 方法定义:
1 Integer selectCount (@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) ;
测试用例:
1 2 3 4 5 6 7 8 @Test public void testSelectCount () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.gt("age" ,20 ); Integer count = this .userMapper.selectCount(wrapper); System.out.println(count); }
3.4.5selectList 方法定义:
1 List<T> selectList (@Param(Constants.WRAPPER) Wrapper<T> queryWrapper)
3.4.6selectPage 方法定义:
1 2 3 4 5 6 IPage<T> selectPage (IPage<T> page,@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) ;
配置分页插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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") public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor () { return new PaginationInterceptor(); } }
测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void testSelectPage () { Page<User> page = new Page<>(1 ,1 ); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like("email" ,"itcast" ); IPage<User> iPage = this .userMapper.selectPage(page, wrapper); System.out.println("数据总条数" + iPage.getTotal()); System.out.println("数据总页数" + iPage.getPages()); System.out.println("当前页数" + iPage.getCurrent()); List<User> records = iPage.getRecords(); for (User record : records) { System.out.println(record); } }
3.5SQL注入原理 前面我们已经知道,MP在启动后会将BaseMapper中的一系列的方法注册到MappedStatement中,那么究竟如何注入?
在MP中,ISqlInjector负责SQL的注入工作,它是一个接口,AbstractSqlInjector是它的实现类
在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的
在实现方法中,methodList.forEach(m->m.inject(builderAssistant,mapperClass,modelClass,tableInfo));是关键,循环遍历方法,进行注入。
最终调用抽象方法injectMappedStatement进行真正的注入,生成了SqlSource对象,再将SQL通过addSelectMappedStatement方法添加到mappedStatements中
4.配置 在MP中有大量的配置,其中有一部分是Mybatis原生的配置,另一部分是MP的配置,详情:https://mybatis.plus/config/
4.1基本配置 4.1.1configLocation Mybatis配置文件位置,如果你有单独的Mybatis配置,请将其路径配置到configLocation中,MybatisConfiguration的具体内容请参考Mybatis官方文档
SpringBoot:
1 mybatis-plus.config-location = classpath:mybatis-config.xml
SpringMVC:
1 2 3 <bean id ="sqlSessionFactory" class ="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" > <property name ="configLocation" value ="classpath:mybatis-config.xml" > </property > </bean >
4.1.2mapperLocations Mybatis Mapper 所对应的XML文件位置,如果您在Mapper中有自定义方法(XML中有自定义实现),需要进行该配置,告诉Mapper所对应的XML文件位置
SpringBoot:
1 mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
SpringMVC:
1 2 3 <bean id ="sqlSessionFactory" class ="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" > <property name ="mapperLocations" value ="classpath*:mybatis/*.xml" > </property > </bean >
Maven多模块项目的扫描路径需以classpath*:开头(即加载多个jar包下的XML文件)
测试
UserMapper.xml:
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="cn.itcast.mp.mapper.UserMapper" > <select id ="findById" resultType ="cn.itcast.mp.pojo.User" > select * from tb_user where id = #{id} </select > </mapper >
1 2 3 4 5 6 7 8 package cn.itcast.mp.simple.mapper;import cn.itcast.mp.simple.pojo.User;import com.baomidou.mybatisplus.core.mapper.BaseMapper;public interface UserMapper extends BaseMapper <User > { User findById (long id) ; }
测试用例:
跟上面的没啥区别,偷懒省略了
4.1.3typeAliasesPackage Mybatis别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在Mapper对应的XML文件中可以直接使用类名,而不使用全限定的类名(即XML中调用的时候不用包含包名)
SpringBoot:
1 mybatis-plus.type-aliases-package = cn.itcast.mp.pojo
SpringMVC:
1 2 3 <bean id ="sqlSessionFactory" class ="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" > <property name ="typeAliasesPackage" value ="com.baomidou.mybatisplus.samples.quickstart.entity" /> </bean >
4.2进阶配置 本部分(Configuration)的配置大都为Mybatis原生支持的配置,这意味着你可以通过Mybatis XML配置文件的形式进行配置
4.2.1mapUnderscoreToCamelCase
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名A_COLUMN(下划线命名)到经典Java属性名aColumn(驼峰命名)的类似映射
注意: 此属性在Mybatis中原默认值为false,在Mybatis-plus中,此属性也将用于生成最终的SQL的select body
如果你的数据库命名符合规则无需使用@TableField注解指定数据库字段名
示例(SpringBoot):
1 2 mybatis-plus.configuration.map-underscore-to-camel-case =false
4.2.2cacheEnabled
全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为true
示例:
1 mybatis-plus.configuration.cache-enabled =false
4.3DB策略 4.3.1idType
类型:com.baomidou.mybatisplus.annotation.IdType
默认值:ID_WORKER
全局默认主键类型,设置后,既可省略实体对象中的@TableId(type = IdType.AUTO)配置
示例:
SpringBoot:
1 mybatis-plus.global-config.db-config.id-type =auto
SpringMVC:
1 2 3 4 5 6 7 8 9 10 11 12 <bean id ="sqlSessionFactory" class ="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="globalConfig" > <bean class ="com.baomidou.mybatisplus.core.config.GlobalConfig" > <property name ="dbConfig" > <bean class ="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig" > <property name ="idType" value ="AUTO" /> </bean > </property > </bean > </property > </bean >
4.3.2tablePrefix
表明前缀,全局配置后可以省略@TableName()配置
SpringBoot:
1 2 mybatis-plus.global-config.db-config.table-prefix =tb_
SpringMVC:
1 2 3 4 5 6 7 8 9 10 11 12 13 <bean id ="sqlSessionFactory" class ="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="globalConfig" > <bean class ="com.baomidou.mybatisplus.core.config.GlobalConfig" > <property name ="dbConfig" > <bean class ="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig" > <property name ="idType" value ="AUTO" /> <property name ="tablePrefix" value ="tb_" /> </bean > </property > </bean > </property > </bean >
5.条件构造器 在MP中,Wrapper接口的实现类关系如下:
可以看到,AbstractWrapper和AbstractChainWrapper是重点实现,接下来我们重点学习AbstractWrapper以及其子类
说明:
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper)的父类
用于生成sql的where条件,entity属性也用于生成sql的where条件
注意:entity生成的where条件与使用各个api生成的where条件没有任何关联行为 官网文档地址:https://mybatis.plus/guide/wrapper.html
5.1allEq 5.1.1说明 1 2 3 allEq(Map<R,V> params) allEq(Map<R,V> params,boolean null2IsNull) allEq(boolean condition,Map<R,V> params, boolean null2IsNull)
个别参数说明:
params:key为数据库字段名,value为字段值
null2IsNull:为true则在map的value为null时调用isNull方法,为false时刻忽略value为null的
例1:allEq({id:1,name:”老王”,age:null})->id = 1 and name = ‘老王’ and age is null
例2:allEq({id:1,name:”老王”,age:null}, false)->id = 1 and name = ‘老王’
1 2 3 allEq(BiPredicate<R,V> filter, Map<R,V> params) allEq(BiPredicate<R,V> filter,Map<R,V> params,boolean null2IsNull) allEq(boolean condition,BiPredicate<R,V> filter,Map<R,V> params, boolean null2IsNull)
个别参数说明:
filter:过滤函数,是否允许字段传入对比条件中
params与null2IsNull:同上
例1:allEq(k,v) -> k.indexOf(“a”) > 0, ({id:1,name:”老王”,age:null}) -> name = ‘老王’ and age is null
例2:allEq(k,v) -> k.indexOf(“a”) > 0, ({id:1,name:”老王”,age:null}, false)->name = ‘老王’
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Test public void testAllEq () { Map<String,Object> params = new HashMap<>(); params.put("name" ,"李四" ); params.put("age" ,"20" ); params.put("password" ,null ); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.allEq((k,v)->(k.equals("age" ) || k.equals("id" )),params); List<User> userList = this .userMapper.selectList(wrapper); for (User user : userList) { System.out.println(user); } }
5.2基本操作
eq
ne
gt
ge
lt
le
between
notBetween
in
字段 IN(value.get(0),value.get(1),…)
notIn
测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void testEq () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("password" ,"123456" ) .ge("age" ,20 ) .in("name" ,"张三" ,"李四" ); List<User> userList = this .userMapper.selectList(wrapper); for (User user : userList) { System.out.println(user); } }
5.3模糊查询
like
LIKE ‘%值%’
例:like(“name”,”王”) —> name like ‘%王%’
notLike
likeLeft
likeRight
LIKE ‘值%’
例:likeRight(“name”,”王”) —> name like ‘王%’
5.4排序
order by
排序:ORDER BY 字段,…
例:orderBy(true,true,”id”,”name”) —> order by id ASC, name ASC
orderByAsc
排序:ORDER BY 字段,…ASC
例:orderByAsc(“id”,”name) —> order by id ASC,name ASC
orderByDesc
排序:ORDER BY 字段, … DESC
例:orderByDesc(“id”,”name”) —> order by id DECS ,name DESC
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void testOrderByAgeDesc () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.orderByDesc("age" ); List<User> userList = this .userMapper.selectList(wrapper); for (User user : userList) { System.out.println(user); } }
5.5逻辑查询
or
拼接OR
主动调用or表示紧接着下一个办法不是用and连接!(不调用or则默认为使用and连接)
and
AND嵌套
例:and(i -> i.eq(“name”,”李白”).ne(“status”,”活着”)) —> and(name = ‘李白’ and status = ‘活着’)
1 2 3 4 5 6 7 8 9 10 11 @Test public void testOr () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name" ,"曹操1" ).or().eq("name" ,20 ); List<User> userList = this .userMapper.selectList(wrapper); for (User user : userList) { System.out.println(user); } }
5.6select 在MP查询中,默认查询所有字段,如果有需要也可以通过select方法进行指定字段
1 2 3 4 5 6 7 8 9 10 11 @Test public void testSelect () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name" ,"曹操1" ).or().eq("name" ,20 ).select("id" ,"name" ,"age" ); List<User> userList = this .userMapper.selectList(wrapper); for (User user : userList) { System.out.println(user); } }
6.ActiveRecord ActiveRecord(简称AR)一直广受动态语言(PHP、Ruby等)的喜爱,而java作为标准静态语言,对于ActiveRecord往往只能赞叹其优雅
什么是ActiveRecord? ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。
AcitveRecord的主要思想是:
每个数据库表对应创建一个类,类的每一个对象实例对应于数据库表中表的一行记录;通常表的每个字段在类中都有相应的Field;
ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;
ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑
6.1开启AR之旅 在MP中,开启AR非常简单,只要将实体类继承Model即可
1 public class User extends Model <User > {}
6.2根据主键查询 测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package cn.itcast.mp.simple;import cn.itcast.mp.simple.pojo.User;import org.junit.Test;import org.junit.internal.runners.JUnit4ClassRunner;import org.junit.runner.RunWith;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class TestUserMapper2 { @Test public void selectById () { User user = new User(); user.setId(1L ); User user1 = user.selectById(); System.out.println(user1); } }
6.3新增数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void testInsert () { User user = new User(); user.setUserName("刘备" ); user.setPassword("123456" ); user.setAge(30 ); user.setName("刘备呗" ); user.setMail("liubei@qq.com" ); boolean insert = user.insert(); System.out.println(insert); }
6.4更新操作 1 2 3 4 5 6 7 8 9 10 @Test public void testUpdate () { User user = new User(); user.setId(7L ); user.setAge(31 ); boolean result = user.updateById(); System.out.println(result); }
6.5 删除操作 1 2 3 4 5 6 7 8 @Test public void testDelete () { User user = new User(); user.setId(6L ); boolean result = user.deleteById(); System.out.println(result); }
6.6根据条件查询 1 2 3 4 5 6 7 8 9 10 11 @Test public void testSelect () { User user = new User(); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.gt("age" ,30 ); List<User> userList = user.selectList(wrapper); for (User user1 : userList) { System.out.println(user1); } }
7.插件 7.1 mybatis的插件机制 Mybatis允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,Mybatis允许使用插件来拦截的方法调用包括:
1.Exceutor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)
2.ParameterHandler(getParameterObject,setParameters)
3.ResultSetHandler(handleResultSets,handleOutputParameters)
4.StatementHandler(prepare,parameterize,batch,update,query)
我们看到了可以拦截Exceutor接口的部分方法,比如update,query,commit,rollback等方法,还有其他接口的一些方法等。
总体概括为:
1.拦截执行器的方法
2.拦截参数的处理
3.拦截结果集的处理
4.拦截Sql语法构建的处理
具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package cn.itcast.mp.plugins;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.*;import java.lang.reflect.Executable;import java.util.Properties;@Intercepts({@Signature( type = Executor.class,// 指定拦截类型 method = "update", // 指定拦截器中的update方法 args = {MappedStatement.class,Object.class} )}) public class MyInterceptor implements Interceptor { @Override public Object intercept (Invocation invocation) throws Throwable { return invocation.proceed(); } @Override public Object plugin (Object target) { return Plugin.wrap(target,this ); } @Override public void setProperties (Properties properties) { } }
注入到Spring容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package cn.itcast.mp;import cn.itcast.mp.plugins.MyInterceptor;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") public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor () { return new PaginationInterceptor(); } @Bean public MyInterceptor myInterceptor () { return new MyInterceptor(); } }
7.2执行分析插件 在MP中提供了对SQL执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅使用于开发环境,不适用于生产环境
SpringBoot配置: