搭建环境
创建表
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) AUTO_INCREMENT PRIMARY KEY,
`phone` varchar(11) UNIQUE NOT NULL,
`user_name` varchar(20),
`age` int(2),
`is_deleted` int(11) NULL DEFAULT 0
)
创建SpringBoot工程,然后引入依赖
SpringBoot版本是2.7.5。
<dependencies>
<!-- SpringBoot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 小辣椒 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mybatis-plus依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
</dependencies>
配置application.properties文件
server.port=8081
# 数据库的配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/db_csdn?SSL=false&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=123456
spring.datasource.username=root
# 日志输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
添加实体类
下面注解会在后面给大家说,这里不必追究。
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId(value = "id") // 人只有一个value属性,则默认是省略的。
private Integer id;
@TableField("user_name")
private String userName;
private String phone;
@TableLogic
private Integer isDeleted;
}
Mapper类
public interface UserMapper extends BaseMapper<User> {
}
测试搭建的环境
@Test
public void testInsert(){
User user = new User();
user.setUserName("老刘");
user.setPhone("13423458945");
userMapper.insert(user);
}
常用注解
@TableName
描述:表名注解,标识实体类对应的表。
使用位置:实体类。
代码实现:
@TableName("t_user")
public class User {
}
@TableId
描述:主键注解。
使用位置:实体类的主键字段。
注意:如果主键名与实体类对应的属性名不一致,则必须要有value属性,如果只有value一个属性,则可以省略不写。
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 主键字段名 |
type | Enum | 否 | IdType.NONE | 指定主键类型 |
IdType类型有以下
值 | 描述 |
---|---|
AUTO | 数据库 ID 自增,使用前数据库的id必须是自增的 |
ASSIGN_ID | 分配ID,默认是雪花算法生成id,与数据库的id是否自增无关 |
INPUT | insert 前自行 set 主键值 |
ASSIGN_UUID | 分配 UUID |
代码实现:
@TableName("t_user")
public class User {
@TableId(value = "id",type = IdType.AUTO) // 人只有一个value属性,则默认是省略的。
private Integer id;
}
@TableField
描述:字段注解(非主键)。
使用位置:实体类的非主键字段。
注意:
-
如果属性名与实体类对应的属性名不一致,则必须要有value属性,如果只有value一个属性,则可以省略不写。
-
如果实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格,那么Mybatis-plus会自动将下划线命名风格转换为驼峰命名风格。
代码实现:
@TableName("t_user")
public class User {
@TableId(value = "id",type = IdType.AUTO) // 人只有一个value属性,则默认是省略的。
private Integer id;
@TableField(value = "user_name",exist = true) // 如果exist的属性为false,则意思是不是数据库中的字段
private String userName;
}
@TableLogic
描述:表字段逻辑处理注解(逻辑删除)。
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 逻辑未删除值 |
delval | String | 否 | “” | 逻辑删除值 |
逻辑删除和物理删除的概念:
逻辑删除:假删除,将对应数据中代表是否被删除字段(is_deleted)的状态修改为被删除状态(值为1),但是在数据库中仍然能看到此条记录。
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据。
使用场景:可以进行数据的恢复。
使用全局配置解决表名前缀和主键策略
# 配置MyBatis-Plus的主键策略
mybatis-plus.global-config.db-config.id-type=assign_id
# 配置MyBatis-Plus操作表的默认前缀
mybatis-plus.global-config.db-config.table-prefix=t_
CRUD接口
Mapper CRUD接口
BaseMapper接口为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器。其中泛型 T
为任意实体对象。
方法如下:
BaseMapper的源码
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.COLL) 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.COLL) 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);
}
插入
插入一条数据
@Resource
private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setUserName("老黑");
user.setPhone("13523458945");
userMapper.insert(user);
System.out.println("获取的id" + user.getId());
}
结果:我们发现在插入数据时,是基于雪花算法的策略生成id。并且它会将主键id存到实体类中。
生成的sql语句
INSERT INTO t_user ( user_name, phone ) VALUES ( ?, ? )
删除
通过id删除
@Resource
private UserMapper userMapper;
@Test
public void testDeleteById(){
int result = userMapper.deleteById(2140147718);
System.out.println("受影响行数:" + result);
}
生成的sql语句:
UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0
通过id批量删除
@Resource
private UserMapper userMapper;
@Test
public void testDeleteById(){
List<Integer> list = Arrays.asList(1, 2, 3);
int result = userMapper.deleteBatchIds(list);
System.out.println("受影响行数:" + result);
}
生成的sql语句:
UPDATE t_user SET is_deleted=1 WHERE id IN ( ? , ? , ? ) AND is_deleted=0
通过Map条件删除
@Resource
private UserMapper userMapper;
@Test
public void testDeleteMap(){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("phone","15623458945");
hashMap.put("user_name","李四");
int result = userMapper.deleteByMap(hashMap);
System.out.println("受影响行数:" + result);
}
生成的sql语句:
UPDATE t_user SET is_deleted=1 WHERE phone = ? AND user_name = ? AND is_deleted=0
修改
通过id修改信息
@Resource
private UserMapper userMapper;
@Test
public void testUpdateById(){
User user = new User();
user.setId(110100482);
user.setUserName("李四");
user.setPhone("18954687536");
int result = userMapper.updateById(user);
System.out.println("受影响行数:" + result);
}
生成的sql语句:
UPDATE t_user SET user_name=?, phone=? WHERE id=? AND is_deleted=0
查询
根据id查询用户信息
@Resource
private UserMapper userMapper;
@Test
public void testSelectById(){
User user = userMapper.selectById(1);
System.out.println(user);
}
生成的sql语句:
SELECT id,user_name,phone,is_deleted FROM t_user WHERE id=? AND is_deleted=0
根据多个id查询多个用户信息
@Resource
private UserMapper userMapper;
@Test
public void testSelectMoreId(){
List<Integer> list = Arrays.asList(1, 2, 3);
List<User> userList = userMapper.selectBatchIds(list);
for (User user : userList) {
System.out.println(user);
}
}
生成的sql语句:
SELECT id,user_name,phone,is_deleted FROM t_user WHERE id IN ( ? , ? , ? ) AND is_deleted=0
根据Map条件查询用户信息
@Resource
private UserMapper userMapper;
@Test
public void testSelectByMap(){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("phone","15586264781");
hashMap.put("name","王五");
List<User> userList = userMapper.selectByMap(hashMap);
for (User user : userList) {
System.out.println(user);
}
}
生成的sql语句:
SELECT id,user_name,phone,is_deleted FROM t_user WHERE phone = ? AND user_name = ? AND is_deleted=0
查询所有用户信息
@Resource
private UserMapper userMapper;
@Test
public void testSelectList(){
// 这里的参数是Wrapper类型,即为条件构造器,这个是针对Sql语句设置不同的条件,如果没有条件,可以设为null。后面会说的。
List<User> userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
生成的sql语句:
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0
Service CRUD接口
通用 Service CRUD 封装IService
接口和其实现类ServiceImpl
,其中T为任意的实体对象。
IService部分方法如下所示,由于方法太多了,这里只列举一部分,剩余的可以自己看源码。
ServiceImpl方法如下所示:
注意: ServiceImpl实现了IService,提供了IService中基础功能的实现。当然,也可以自定义相应的业务方法完成需求。
由于通用Service中CRUD的方法与通用Mapper中CRUD方法类似,这里只列举不同的。
批量添加
@Resource
private UserService userService;
@Test
public void testSaveBatch(){
ArrayList<User> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setPhone("1594561234" + i);
user.setUserName("张三" + i);
list.add(user);
}
userService.saveBatch(list);
}
生成的sql语句
INSERT INTO t_user ( user_name, phone ) VALUES ( ?, ? )
查询总记录数
@Resource
private UserService userService;
@Test
public void testCount(){
long count = userService.count();
System.out.println("总记录数:" + count);
}
生成的sql语句
SELECT COUNT( * ) FROM t_user WHERE is_deleted=0
条件构造器
AbstractWrapper中的部分方法以及QueryMapper的使用
提示:有的方法会有 boolean condition
,也就是表示该条件是否加入最后生成的sql中。默认为true。
allEq
boolean null2IsNull
参数:默认为true。若为true,则在map的value为null时调用isNull方法;若为false,则忽略value为null的。
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper1(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("phone","15623458964");
hashMap.put("user_name",null);
wrapper.allEq(hashMap,false); // SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (phone = ?)
//wrapper.allEq(false,hashMap,false); // SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0
List<User> list = userMapper.selectList(wrapper);
for (User user : list) {
System.out.println(user);
}
}
生成的sql语句看后面的注释
eq 和 ne
eq
:等于 =
ne
:不等于 <>
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper2(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("phone","15623458964")..ne("user_name","张三");
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (phone = ? AND user_name <> ?)
gt 和 lt
gt
:大于 >
lt
: 小于 <
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper3(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("id","110100481").lt("id","227540995");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (id > ? AND id < ?)
ge 和 le
ge
:大于等于 >=
le
: 小于等于 <=
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper4(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("id","110100481").le("id","227540995");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (id >= ? AND id <= ?)
between 和 notBetween
between
:BETWEEN 值1 AND 值2
notBetween
:NOT BETWEEN 值1 AND 值2
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("id","110100481","227540995")
.notBetween("phone","1695567000","1995567000");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (id BETWEEN ? AND ? AND phone NOT BETWEEN ? AND ?)
like 和 notLike
LIKE
:%值%
notLike
:NOT LIKE ‘%值%’
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper6(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("user_name","张")
.notLike("phone","169");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND phone NOT LIKE ?)
likeLeft 和 likeRight
likeLeft :LIKE '%值'
likeRight`:LIKE ‘值%’
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper7(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.likeLeft("user_name","张")
.likeRight("phone","134");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND phone LIKE ?)
isNull 和 isNotNull
isNull
:字段 IS NULL
isNotNull
:字段 IS NOT NULL
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper8(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNull("user_name").isNotNull("phone");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name IS NULL AND phone IS NOT NULL)
in 和notIn
in
:字段 IN
notIn
:字段 NOT IN
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper9(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.in("phone", Arrays.asList("15945612354","15945612355","15945612356"))
.notIn("user_name","张三","李四");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (phone IN (?,?,?) AND user_name NOT IN (?,?))
groupBy
groupBy
:分组:GROUP BY 字段
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper10(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.groupBy("user_name");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 GROUP BY user_name
orderByAsc 和 orderByDesc
orderByAsc
:排序:ORDER BY 字段, … ASC
orderByDesc
:排序:ORDER BY 字段, … DESC
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper11(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("id").orderByDesc("phone");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY id ASC,phone DESC
orderBy
orderBy
:排序:ORDER BY 字段,
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper12(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderBy(true,true,"id");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY id ASC
having
having
:HAVING ( sql语句 )
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper13(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.groupBy("phone").having("phone > 15945612342");
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 GROUP BY phone HAVING phone > 15945612342
or 和 and
or
:OR 嵌套
and
:AND 嵌套
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper14(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name","张三").or().isNull("phone")
.and(wrappers -> {
wrappers.eq("phone","15945612342");
}); List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name = ? OR phone IS NULL AND (phone = ?))
inSql 和 notInSql
inSql
:字段 IN ( sql语句 )
notInSql
:字段 NOT IN ( sql语句 )
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper14(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notInSql("id","select id from t_user where id <= 2123419651")
.inSql("phone","select phone from t_user where phone <= 15245612344"); List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (id NOT IN (select id from t_user where id <= 2123419651) AND phone IN (select phone from t_user where phone <= 15245612344))
select方法
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper15(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("user_name");
// selectMaps返回Map集合列表,通常配合select使用,可以省去没有查询到的列值。
List<Map<String, Object>> users = userMapper.selectMaps(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT user_name FROM t_user WHERE is_deleted=0
UpdateWrapper的使用
代码实现:
@Resource
private UserMapper userMapper;
@Test
public void testUpdateWrapper16(){
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.set("phone","15478965231").eq("id","110100482");
int result = userMapper.update(null, updateWrapper);
System.out.println(result);
}
生成的sql语句
UPDATE t_user SET phone=? WHERE is_deleted=0 AND (id = ?)
LambdaQueryWrapper
@Resource
private UserMapper userMapper;
@Test
public void testSelectWrapper17(){
User user = new User();
user.setPhone("159");
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getPhone,user.getPhone());
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
生成的sql语句
SELECT id,user_name,phone,is_deleted FROM t_user WHERE is_deleted=0 AND (phone LIKE ?)
LambdaUpdateWrapper
@Resource
private UserMapper userMapper;
@Test
public void testUpdateWrapper18(){
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.set(User::getUserName,"李四").eq(User::getId,"227540993");
int result = userMapper.update(null, wrapper);
System.out.println(result);
}
生成的sql语句
UPDATE t_user SET user_name=? WHERE is_deleted=0 AND (id = ?)
分页插件
使用Mybatis-Plus自带的分页
①:添加分页的配置类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
②:进行测试
@Test
public void testPage(){
Page<User> page = new Page<>(1,5);
userMapper.selectPage(page,null);
List<User> records = page.getRecords();
System.out.println("第一页的所有记录:");
records.forEach(System.out::println);
System.out.println("总页数" + page.getPages());
System.out.println("总记录数" + page.getTotal());
System.out.println("每页显示的条数" + page.getSize());
System.out.println("当前页" + page.getCurrent());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}
使用mapper.xml文件自定义分页
①:添加分页的配置类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
②:UserMapper接口
public interface UserMapper extends BaseMapper<User> {
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("name") String name);
}
③:UserMapper.xml文件
<?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="com.zhang.mapper.UserMapper">
<select id="selectPageVo" resultType="User">
select * from t_user where user_name = #{name}
</select>
</mapper>
④:在application.properties文件中配置Mybatis-Plus的相关配置
# 配置别名
mybatis-plus.type-aliases-package=com.zhang.pojo
# 配置mapper文件
mybatis-plus.mapper-locations=classpath:/mapper/**.xml
⑤:进行测试
@Test
public void testPage(){
Page<User> page = new Page<>(1,5);
userMapper.selectPageVo(page,"张三");
List<User> records = page.getRecords();
System.out.println("第一页的所有记录:");
records.forEach(System.out::println);
System.out.println("总页数" + page.getPages());
System.out.println("总记录数" + page.getTotal());
System.out.println("每页显示的条数" + page.getSize());
System.out.println("当前页" + page.getCurrent());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}
乐观锁插件
乐观锁和悲观锁的概念:
乐观锁
:指别人不会同时修改数据,默认是不会上锁的,只是在执行的时候会判断别人在此刻是否修改了数据,如果修改了数据,则放弃操作,否则执行操作。悲观锁
:指别人会同时修改数据,默认是在操作数据时是上锁的,直到操作完成后才会释放所,在上锁期间其他人不能操作数据。
实现流程
3. 取出记录时,会获取到当前的version。
4. 更新记录时,会带上这个version。
5. 执行更新时,会将version的版本+1。如果version版本不对,则更新失败。
实现步骤:
首先在数据库中添加version字段。
①:在实体类的 version 属性上加上 @Version注解。
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId(value = "id",type = IdType.AUTO) // 人只有一个value属性,则默认是省略的。
private Integer id;
@TableField(value = "user_name",exist = true) // 如果exist的属性为false,则意思是不是数据库中的字段
private String userName;
private String phone;
private SexEnum sex;
@TableLogic
private Integer isDeleted;
@Version
private Integer version;
}
②:基于注解配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
案例:这里有A、B、C三个人,其中C刚开始想让A帮他修改手机号,然后A说等一会在去。过了一会想换一个手机号,于是C就让B去帮他换新手机号。此时,A和B同时帮C修改手机号,那么原本C最终想要的是B帮忙修改的手机号,结果在B改完后,A又改了,那么此时就造成了结果误差,此时A就把B的操作覆盖了。我们将会使用乐观锁的插件来解决。
代码实现
将@Version注解与注解配置都配置好后,进行下述测试。
@Resource
private UserMapper userMapper;
@Test
public void testLock(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// A
User a = userMapper.selectOne(wrapper.eq("user_name", "C"));
System.out.println("此时A查到C的手机号" + a.getPhone());
// B
User b = userMapper.selectOne(wrapper.eq("user_name", "C"));
System.out.println("此时B查到C的手机号" + a.getPhone());
// 此时B修改手机号
b.setPhone("15978651234");
int resultB = userMapper.updateById(b); // 1
System.out.println("B修改手机号的结果:" + resultB);
// 此时A修改手机号
a.setPhone("19878651234");
int resultA = userMapper.updateById(a); // 0
System.out.println("A修改手机号的结果:" + resultA);
// 最后的结果
User c = userMapper.selectOne(wrapper.eq("user_name", "C"));
System.out.println("C最终的手机号:" + c.getPhone());
}
通用枚举
表中的有些字段值是固定的,例如性别(男或女),例如我们可以使用Mybatis-Plus的通用枚举来实现。
注意:从 3.5.2 版本开始只需完成 声明通用枚举属性
即可使用。
①:给数据库表添加字段sex
②:创建通用枚举类型
public enum SexEnum {
MALE(1,"男"),
FEMALE(2,"女");
@EnumValue
private Integer sex;
@JsonValue // 标记响应json值
private String sexName;
SexEnum(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
public String getSexName() {
return sexName;
}
}
测试
@Resource
private UserMapper userMapper;
@Test
public void testSexNum(){
User user = new User();
user.setSex(SexEnum.MALE);
user.setPhone("14536586953");
userMapper.insert(user);
System.out.println(userMapper.selectById(user.getId()).getSex().getSexName());
}
代码生成器
这里需要重新创建一个SpringBoot工程。
①:添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
②:快速生成的代码
public class TestFastAutoGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/db_csdn?SSL=false&serverTimezone=UTC","root","123456")
.globalConfig(builder -> {
builder.author("zhang") // 设置作者
.enableSwagger() // 开启swagger模式
.fileOverride() // 覆盖已生成文件
.disableOpenDir() // 禁止打开输出目录
.outputDir("E:\\代码\\Mybatis-plus\\csdn"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("src.main.java.com.zhang") // 设置父包名
//.moduleName("") // 设置父包模块名
.entity("entity") // 设置包名
.service("service") // 设置Service包名
.serviceImpl("service.impl") // 设置serviceImpl包名
.controller("controller") // 设置controller包名
.xml("mapper.xml")
.pathInfo(Collections.singletonMap(OutputFile.xml,"E:\\代码\\Mybatis-plus\\csdn\\src\\main\\java\\com\\zhang\\mapper"))// 设置mapper.xml文件生成路径
.pathInfo(Collections.singletonMap(OutputFile.mapper,"E:\\代码\\Mybatis-plus\\csdn\\src\\main\\java\\com\\zhang\\mapper")) // 设置mapper文件生成路径
.pathInfo(Collections.singletonMap(OutputFile.controller,"E:\\代码\\Mybatis-plus\\csdn\\src\\main\\java\\com\\zhang\\controller")) // 设置controller文件生成路径
.pathInfo(Collections.singletonMap(OutputFile.service,"E:\\代码\\Mybatis-plus\\csdn\\src\\main\\java\\com\\zhang\\service")) // 设置service文件生成路径
.pathInfo(Collections.singletonMap(OutputFile.serviceImpl,"E:\\代码\\Mybatis-plus\\csdn\\src\\main\\java\\com\\zhang\\service\\impl")) // 设置serviceImpl文件生成路径
.pathInfo(Collections.singletonMap(OutputFile.entity,"E:\\代码\\Mybatis-plus\\csdn\\src\\main\\java\\com\\zhang\\entity")); // 设置entity文件生成路径
})
.strategyConfig(builder -> {
builder.addInclude("t_user") // 设置需要生成的表名
.addTablePrefix("t_","c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()).execute(); // 使用Freemarker引擎模板,默认是Velocity引擎模板
}
}
③:生成的目录如下: