mybatis-pluse使用
开发环境
IDE:idea 2019.2JDK:JDK8+构建工具:maven 3.5.4MySQL版本:MySQL 5.7MyBatis-Plus:3.5.1
新建库和表
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER
SET utf8mb4 */;
USE `mybatis_plus`;
CREATE TABLE `user` (
`id` BIGINT ( 20 ) NOT NULL COMMENT '主键ID',
`name` VARCHAR ( 30 ) DEFAULT NULL COMMENT '姓名',
`age` INT ( 11 ) DEFAULT NULL COMMENT '年龄',
`email` VARCHAR ( 50 ) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8;
添加数据
INSERT INTO USER ( id, NAME, age, email )
VALUES( 1, 'Jone', 18, 'test1@baomidou.com' ),( 2, 'Jack', 20, 'test2@baomidou.com' ),( 3, 'Tom', 28, 'test3@baomidou.com' ),( 4, 'Sandy', 21, 'test4@baomidou.com' ),( 5, 'Billie', 24, 'test5@baomidou.com' );
添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mybatis-plus启动器--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!--lombok用于简化实体类开发--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>
idea中安装lombok插件
配置application.yml
1.驱动类driver-class-namespring boot 2.0(内置jdbc5驱动),驱动类使用:driver-class-name: com.mysql.jdbc.Driverspring boot 2.1及以上(内置jdbc8驱动),驱动类使用:driver-class-name: com.mysql.cj.jdbc.Driver2.连接地址urlMySQL5.7版本的url:jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=falseMySQL8.0版本的url:jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false否则运行测试用例报告如下错误:java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized orrepresents more
spring:# 配置数据源信息datasource:# 配置数据源类型type: com.zaxxer.hikari.HikariDataSource# 配置连接数据库的各个信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=falseusername: rootpassword: 123456
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 设置MyBatis-Plus的全局配置global-config:db-config:# 设置实体类所对应的表的统一前缀table-prefix: t_# 设置统一的主键生成策略id-type: auto# 配置类型别名所对应的包type-aliases-package: com.atguigu.mybatisplus.pojo# 扫描通用枚举的包type-enums-package: com.atguigu.mybatisplus.enums
启动类
在Spring Boot启动类中添加@MapperScan注解,扫描mapper包
@SpringBootApplication
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MybatisPlusDatasourceApplication {public static void main(String[] args) {SpringApplication.run(MybatisPlusDatasourceApplication.class, args);}}
添加实体
@Data
public class User {//将属性所对应的字段指定为主键//@TableId注解的value属性用于指定主键的字段//@TableId注解的type属性设置主键生成策略//@TableId(value = "uid", type = IdType.AUTO)@TableId("uid")private Long id;//指定属性所对应的字段名@TableField("user_name")private String name;private Integer age;private String email;private SexEnum sex;
添加mapper
1.BaseMapper是MyBatis-Plus提供的模板mapper,其中包含了基本的CRUD方法,泛型为操作的 实体类型
public interface UserMapper extends BaseMapper<User> { }
测试
@SpringBootTest
public class MyBatisPlusTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectList(){//通过条件构造器查询一个list集合,若没有条件,则可以设置null为参数List<User> list = userMapper.selectList(null);list.forEach(System.out::println);} }
添加日志
1.在application.yml中配置日志输出
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
父类的方法说明
/** Copyright (c) 2011-2022, baomidou (jobob@qq.com).** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.baomidou.mybatisplus.core.mapper;import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import org.apache.ibatis.annotations.Param;import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;/*** Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能* <p>这个 Mapper 支持 id 泛型</p>** @author hubin* @since 2016-01-23*/
public interface BaseMapper<T> extends Mapper<T> {/*** 插入一条记录** @param entity 实体对象*/int insert(T entity);/*** 根据 ID 删除** @param id 主键ID*/int deleteById(Serializable id);/*** 根据实体(ID)删除** @param entity 实体对象* @since 3.4.4*/int deleteById(T entity);/*** 根据 columnMap 条件,删除记录** @param columnMap 表字段 map 对象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,删除记录** @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 删除(根据ID或实体 批量删除)** @param idList 主键ID列表或实体列表(不能为 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<?> idList);/*** 根据 ID 修改** @param entity 实体对象*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根据 whereEntity 条件,更新记录** @param entity 实体对象 (set 条件值,可以为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);/*** 根据 ID 查询** @param id 主键ID*/T selectById(Serializable id);/*** 查询(根据ID 批量查询)** @param idList 主键ID列表(不能为 null 以及 empty)*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 查询(根据 columnMap 条件)** @param columnMap 表字段 map 对象*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件,查询一条记录* <p>查询一条记录,例如 qw.last("limit 1") 限制取一条记录, 注意:多条数据会报异常</p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {List<T> ts = this.selectList(queryWrapper);if (CollectionUtils.isNotEmpty(ts)) {if (ts.size() != 1) {throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");}return ts.get(0);}return null;}/*** 根据 Wrapper 条件,判断是否存在记录** @param queryWrapper 实体对象封装操作类* @return*/default boolean exists(Wrapper<T> queryWrapper) {Long count = this.selectCount(queryWrapper);return null != count && count > 0;}/*** 根据 Wrapper 条件,查询总记录数** @param queryWrapper 实体对象封装操作类(可以为 null)*/Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录* <p>注意: 只返回第一个字段的值</p>** @param queryWrapper 实体对象封装操作类(可以为 null)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件,查询全部记录(并翻页)** @param page 分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null)*/<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件,查询全部记录(并翻页)** @param page 分页查询条件* @param queryWrapper 实体对象封装操作类*/<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
插入
最终执行的结果,所获取的id为1475754982694199298这是因为MyBatis-Plus在实现插入数据时,会默认基于雪花算法的策略生成id
@Testpublic void testInsert(){//实现新增用户信息//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )User user = new User();//user.setId(100L);user.setName("张三");user.setAge(23);user.setEmail("zhangsan@atguigu.com");int result = userMapper.insert(user);System.out.println("result:"+result);System.out.println("id:"+user.getId());}
删除
//通过id删除用户信息//DELETE FROM user WHERE id=?int result = userMapper.deleteById(1492767055210991617L);System.out.println("result:"+result);------------------------------------------------------//根据map集合中所设置的条件删除用户信息//DELETE FROM user WHERE name = ? AND age = ?Map<String, Object> map = new HashMap<>();map.put("name", "张三");map.put("age", 23);int result = userMapper.deleteByMap(map);System.out.println("result:"+result); //------------------------------------------//通过多个id实现批量删除//DELETE FROM user WHERE id IN ( ? , ? , ? )List<Long> list = Arrays.asList(1L, 2L, 3L);int result = userMapper.deleteBatchIds(list);System.out.println("result:"+result);
修改
@Testpublic void testUpdate(){//修改用户信息//UPDATE user SET name=?, email=? WHERE id=?User user = new User();user.setId(4L);user.setName("李四");user.setEmail("lisi@atguigu.com");int result = userMapper.updateById(user);System.out.println("result:"+result);}
查询
通过观察BaseMapper中的方法,大多方法中都有Wrapper类型的形参,此为条件构造器,可针对于SQL语句设置不同的条件,若没有条件,则可以为该形参赋值null,即查询(删除/修改)所有数据
/*** 通过id查询用户信息*/ @Testpublic void testSelect() {//SELECT id,name,age,email FROM user WHERE id=?User user = userMapper.selectById(1L);System.out.println(user);}@Testpublic void testSelectids() {//根据多个id查询多个用户信息//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )List<Long> list = Arrays.asList(1L, 2L, 3L);List<User> users = userMapper.selectBatchIds(list);users.forEach(System.out::println);}@Testpublic void testSelectuser() {//根据map集合中的条件查询用户信息//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?Map<String, Object> map = new HashMap<>();map.put("name", "Jack");map.put("age", 20);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println);}@Testpublic void testSelectall() {//查询所有数据//SELECT id,name,age,email FROM userList<User> users = userMapper.selectList(null);users.forEach(System.out::println);}
通用Service
通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,泛型 T 为任意实体对象建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承Mybatis-Plus 提供的基类
IService
MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑详情查看源码IService和ServiceImpl
/*** UserService继承IService模板提供的基础功能 */
public interface UserService extends IService<User> {
}
/*** ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,
并在实现类中实现 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
测试查询记录数
@Autowiredprivate UserService userService;@Testpublic void testGetCount(){//查询总记录数//SELECT COUNT( * ) FROM userlong count = userService.count();System.out.println("总记录数:"+count);}
批量添加
@Testpublic void testInsertMore(){
// SQL长度有限制,海量数据插入单条SQL无法实行,
// 因此MP将批量插入放在了通用Service中实现,而不是通用Mapper//批量添加//INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )List<User> list = new ArrayList<>();for (int i = 1; i <= 10; i++) {User user = new User();user.setName("ybc"+i);user.setAge(20+i);list.add(user);}boolean b = userService.saveBatch(list);System.out.println(b);}
@TableName
经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在 Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表由此得出结论,MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决定,且默认操作的表名和实体类型的类名一致通过@TableName解决类名和具体的表名不一致的问题,通过@TableName设置查询时候使用的具体表名称
//设置实体类所对应的表名@TableName("t_user")
public class User {}
全局配置默认前缀
1.可以使用MyBatis-Plus提供的全局配置,为实体类所对应的表名设置默认的前缀,那么就
不需要在每个实体类上通过@TableName标识实体类对应的表2.配置主键生成策略
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 设置MyBatis-Plus的全局配置global-config:db-config:# 设置实体类所对应的表的统一前缀table-prefix: t_# 设置统一的主键生成策略id-type: auto
主键生成策略
public enum IdType {/*** 数据库ID自增* <p>该类型请确保数据库设置了 ID自增 否则无效</p>*/AUTO(0),/*** 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)*/NONE(1),/*** 用户输入ID(insert前自行set主键值)* <p>该类型可以通过自己注册自动填充插件进行填充</p>*/INPUT(2),/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 *//*** 分配ID (主键类型为number或string),* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)** @since 3.3.0*/ASSIGN_ID(3),/*** 分配UUID (主键类型为 string)* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))*/ASSIGN_UUID(4);private final int key;IdType(int key) {this.key = key;}
}
数据库的扩展方式
1.业务分库、主从复制,数据库分表
垂直分表垂直分表适合将表中某些不常用且占了大量空间的列拆分出去。例如,前面示意图中的 nickname 和 description 字段,假设我们是一个婚恋网站,用户在筛选其他用户的时候,主要是用 age 和 sex 两个字段进行查询,而 nickname 和 description 两个字段主要用于展示,一般不会在业务查询中用到。description 本身又比较长,因此我们可以将这两个字段独立到另外一张表中,这样在查询 age 和 sex 时,就能带来一定的性能提升水平分表水平分表适合表行数特别大的表,有的公司要求单表行数超过 5000 万就必须进行分表,这个数字可以作为参考,但并不是绝对标准,关键还是要看表的访问性能。对于一些比较复杂的表,可能超过 1000万就要分表了;而对于一些简单的表,即使存储数据超过 1 亿行,也可以不分表。但不管怎样,当看到表的数据量达到千万级别时,作为架构师就要警觉起来,因为这很可能是架构的性能瓶颈或者隐患。水平分表相比垂直分表,会引入更多的复杂性,例如要求全局唯一的数据id该如何处理
@TableField
属性名和字段名不一致的情况
1.若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格
例如实体类属性userName,表中字段user_name此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格相当于在MyBatis中配置2.若实体类中的属性和表中的字段不满足情况1例如实体类属性name,表中字段username此时需要在实体类属性上使用@TableField("username")设置属性所对应的字段名
//指定属性所对应的字段名@TableField("user_name")private String name;
@TableLogic
逻辑删除
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录使用场景:可以进行数据恢复实现逻辑删除step1:数据库中创建逻辑删除状态列,设置默认值为0
@TableLogicprivate Integer isDeleted;
真正执行的操作是更新
wapper介绍
QueryWrapper 组装查询条件
@Autowiredprivate UserMapper userMapper;@Testpublic void test01(){//查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("user_name", "a").between("age", 20, 30).isNotNull("email");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
QueryWrapper 组装排序条件
@Testpublic void test02(){//查询用户信息,按照年龄的降序排序,若年龄相同,则按照id升序排序//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASCQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age").orderByAsc("uid");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
QueryWrapper 组装删除条件
@Testpublic void test03(){//删除邮箱地址为null的用户信息//UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email");int result = userMapper.delete(queryWrapper);System.out.println("result:"+result);}
@Testpublic void test04(){//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改//UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.gt("age", 20).like("user_name", "a").or().isNull("email");User user = new User();user.setName("小明");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("result:"+result);}
@Testpublic void test05(){//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改//lambda中的条件优先执行//UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("user_name", "a").and(i->i.gt("age",20).or().isNull("email"));User user = new User();user.setName("小红");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("result:"+result);}
QueryWrapper 组装select子句
@Testpublic void test06(){//查询用户的用户名、年龄、邮箱信息//SELECT user_name,age,email FROM t_user WHERE is_deleted=0QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("user_name", "age", "email");List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}
QueryWrapper 实现子查询
@Testpublic void test07(){//查询id小于等于100的用户信息//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid <= 100))QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.inSql("uid", "select uid from t_user where uid <= 100");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
UpdateWrapper
@Testpublic void test08(){//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.like("user_name", "a").and(i -> i.gt("age", 20).or().isNull("email"));updateWrapper.set("user_name", "小黑").set("email","abc@atguigu.com");int result = userMapper.update(null, updateWrapper);System.out.println("result:"+result);}
condition
在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若没有选择则一定不能组装,以免影响SQL执行的结果
@Testpublic void test09(){//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)String username = "a";Integer ageBegin = null;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();if(StringUtils.isNotBlank(username)){//isNotBlank判断某个字符创是否不为空字符串、不为null、不为空白符queryWrapper.like("user_name", username);}if(ageBegin != null){queryWrapper.ge("age", ageBegin);}if(ageEnd != null){queryWrapper.le("age", ageEnd);}List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
@Testpublic void test10(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(username), "user_name", username).ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
分页插件
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
@Configuration
//扫描mapper接口所在的包
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}}
分页测试
@Testpublic void testPage() {Page<User> page = new Page<>(2, 3);userMapper.selectPage(page, null);System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示的条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("总页数:" + page.getPages());System.out.println("是否有上一页:" + page.hasPrevious());System.out.println("是否有下一页:" + page.hasNext());}
xml自定义分页
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatisplus.mapper.UserMapper"><!--Map<String, Object> selectMapById(Long id);--><select id="selectMapById" resultType="map">select id,name,age,email from user where id = #{id}</select><!--Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);--><select id="selectPageVo" resultType="User">select uid,user_name,age,email from t_user where age > #{age}</select></mapper>
@Repository
public interface UserMapper extends BaseMapper<User> {/*** 根据id查询用户信息为map集合* @param id* @return*/Map<String, Object> selectMapById(Long id);/*** 通过年龄查询用户信息并分页* @param page MyBatis-Plus所提供的分页对象,必须位于第一个参数的位置* @param age* @return*/Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);}
测试
@Testpublic void testPageVo() {Page<User> page = new Page<>(1, 3);userMapper.selectPageVo(page, 20);System.out.println(page.getRecords());System.out.println(page.getPages());System.out.println(page.getTotal());System.out.println(page.hasNext());System.out.println(page.hasPrevious());}
Mybatis-Plus实现乐观锁
1.设置version
2.配置
3.更新失败,重新查询再更新
@Data
public class Product {private Long id;private String name;private Integer price;@Version //标识乐观锁版本号字段private Integer version;
}
@Configuration
//扫描mapper接口所在的包
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}}
@Testpublic void testProduct01() {//小李查询商品价格Product productLi = productMapper.selectById(1);System.out.println("小李查询的商品价格:" + productLi.getPrice());//小王查询商品价格Product productWang = productMapper.selectById(1);System.out.println("小王查询的商品价格:" + productWang.getPrice());//小李将商品价格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王将商品价格-30productWang.setPrice(productWang.getPrice() - 30);int result = productMapper.updateById(productWang);if (result == 0) {//操作失败,重新获取version并更新Product productNew = productMapper.selectById(1);productNew.setPrice(productNew.getPrice() - 30);productMapper.updateById(productNew);}//老板查询商品价格Product productLaoban = productMapper.selectById(1);System.out.println("老板查询的商品价格:" + productLaoban.getPrice());}
通用枚举-数据库添加字段
@Getter
public enum SexEnum {MALE(1, "男"),FEMALE(2, "女");@EnumValue //将注解所标识的属性的值存储到数据库中private Integer sex;private String sexName;SexEnum(Integer sex, String sexName) {this.sex = sex;this.sexName = sexName;}
}
通用枚举- 配置扫描
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 设置MyBatis-Plus的全局配置global-config:db-config:# 设置实体类所对应的表的统一前缀
# table-prefix: t_# 设置统一的主键生成策略id-type: auto# 配置类型别名所对应的包type-aliases-package: com.atguigu.mybatisplus.pojo# 扫描通用枚举的包type-enums-package: com.atguigu.mybatisplus.enums
@Testpublic void test(){User user = new User();user.setName("admin");user.setAge(33);user.setSex(SexEnum.MALE);int result = userMapper.insert(user);System.out.println("result:"+result);}
代码生成器-引入依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>
代码生成器-代码生成
public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "123456").globalConfig(builder -> {builder.author("atguigu") // 设置作者//.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件.outputDir("D://mybatis_plus"); // 指定输出目录}).packageConfig(builder -> {builder.parent("com.atguigu") // 设置父包名.moduleName("mybatisplus") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径}).strategyConfig(builder -> {builder.addInclude("t_user") // 设置需要生成的表名.addTablePrefix("t_", "c_"); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
多数据源
适用于多种场景:纯粹多库、 读写分离、 一主多从、 混合模式等目前我们就来模拟一个纯粹多库的一个场景,其他场景类似场景说明:我们创建两个库,分别为:mybatis_plus(以前的库不动)与mybatis_plus_1(新建),将mybatis_plus库的product表移动到mybatis_plus_1库,这样每个库一张表,通过一个测试用例分别获取用户数据与商品数据,如果获取到说明多库模拟成功
多数据源-引入依赖
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.0</version></dependency>
多数据源-配置
spring:# 配置数据源信息datasource:dynamic:# 设置默认的数据源或者数据源组,默认值即为masterprimary: master# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源strict: falsedatasource:master:url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456slave_1:url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456
多数据源-创建用户service
public interface ProductService extends IService<Product> {
}@Service
@DS("slave_1")
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}//----------------------------------------
public interface UserService extends IService<User> {
}@Service
@DS("master")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
多数据源-测试
@Testvoid contextLoads() {}@Autowiredprivate UserService userService;@Autowiredprivate ProductService productService;@Testpublic void test(){System.out.println(userService.getById(1));System.out.println(productService.getById(1));}
都能顺利获取对象,则测试成功2、如果我们实现读写分离,将写操作方法加上主库数据源,读操作方法加上从库数据源,自动切换,是不是就能实现读写分离
mybatis-pluse使用相关推荐
- 2020年开发踩坑记录
20200207 mybatis plus 自带insert插入异常 sql injection violation 解决方法: 使用逆向工程脚本时,生成的映射实体类在下面的注解会多table: 删除 ...
- 日常踩坑记录-汇总版
开发踩坑记录,不定时更新 心得 RTFM 严谨的去思考问题,处理问题 严格要求自己的代码编写习惯与风格 注意 单词拼写 20200207 mybatis plus 自带insert插入异常 sql i ...
- mybatis查询报错:com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from string
mybatis查询报错: com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from strin ...
- MyBatis的插入后获得主键的方式
需求: 使用MyBatis往MySQL数据库中插入一条记录后,需要返回该条记录的自增主键值. 方法: 在mapper中指定keyProperty属性,示例如下: <insert id=" ...
- mybatis使用注解开发
mybatis使用注解开发 面向接口编程 在之前我们是通过面向对象编程,但是在真正开发的时候我们会选择面向接口编程. 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的 ...
- mybatis ResultMap
ResultMap 解决属性名和字段的名称不一致的问题. 查询为null的问题 创建java实体类: public class User {private int id; //idprivate St ...
- mybatis配置文件解析
mybatis配置文件解析 mybatis核心配置文件`mybatis-config.xml文件. mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息. 能配置的内容: con ...
- mybatis CRUD操作
mybatis CRUD操作 select select标签是mybatis最常用的标签之一. select语句有很多属性可以详细的配置每一天sql语句. id 命名空间唯一的标识. 接口中的方法名与 ...
- java mybatis基础
java mybatis基础 1.1 什么是mybatis? mybatis是一个优秀的持久层框架. 避免几乎所有的JDBC代码和手动设置参数以及获取结果集的过程. 可以使用简单的xml或者注解来配置 ...
- mybatis的资源过滤错误及xml文件编码错误
mybatis 解决maven项目内资源过滤的问题 写的配置文件无法被导出或者生效的问题. 解决方案: <build><resources><resource>&l ...
最新文章
- 详解javascript: void(0);
- php 复选框默认选中的值,PHP复选框默认值是什么 - php
- 文档知多少---走出软件作坊:三五个人十来条枪 如何成为开发正规军(二十五)[转]...
- 2.1.1进程的概念 组成和特征
- 好用的wordpress主题
- 外媒:为何说中国对美国科技行业的影响与日俱增
- IdnentiyServer-使用客户端凭据访问API
- java 时间戳转换成时间_java 10位时间戳 转成时间
- LeetCode: Single Number I II
- C++编程教程教你如何从零学起(免费高速下载)TXT文档分享
- [分享]屏幕取色工具
- linux 安装onos 记录
- 安卓游戏服务器修改,【httpcather/Thor】课程二,用抓包工具修改微信小游戏,还能保存到服务器...
- 闪迪MicroSD卡无法格式化修复经验(不一定管用)
- 插入目录后 正文页码重新怎么从1开始
- Android 车机系统 One Binary 适配白天黑夜的一个方案
- JAVA 九大排序算法
- 邮箱验证(正则表达式)
- 如何建立简易Rss源
- 记一次关于App页面响应时间的测试
热门文章
- 【苹果相册推iMessage】软件NSSet setWithArray:product
- #yyds干货盘点# 如何在 Kubernete 中运行 DaemonSet 守护进程?(13)
- windows安装java
- HCIA笔记-----ACL访问控制列表
- 计算机网络性能指标:速率,带宽,吞吐量
- 常见数学符号字母拼音输入方法
- win10系统右下角调节声音的小喇叭不见了解决方法
- AP3160 高性能异步升压 LED 驱动器 兼容 OB3353 宽范围工作电压:9 V ~ 35 V 宽范围 PWM 调光 (1 kHz~200 kHz)
- 文件(图片)强制下载
- 全国首例区块链公证书亮相,背后公司深安科技已获数千万元天使融资...