引入依赖
<dependencies>
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.13</version>
</dependency>
</dependencies>
配置application.yml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://192.168.60.100/mybatisplus?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mysql 5.0以上版本驱动需要配置为 com.mysql.cj.jdbc.Driver
mysql 5.7以上url配置:jdbc:m ysql://192.168.60.100/mydb?characterEncoding=UTF-8&useSSL=false
mysql 8.0 url需要配置时区:jdbc:m ysql://192.168.60.100/mydb?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl为mybatisplus自带的日志,可以在控制台输出sql和执行结果
1 BaseMapper
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
1.1 创建继承BaseMapper的实现类
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
1.2 在启动类添加@MapperScan扫描mapper
@SpringBootApplication
@MapperScan
public class MybatisplusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisplusApplication.class, args);
}
}
1.3 创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
private Long id;
private String name;
private String email;
private Integer age;
}
如果不使用t_user则对应表名为类名首字母小写 即user
1.4 测试
@SpringBootTest
class MybatisplusApplicationTests {
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
1.5 新增 insert
User user = new User();
user.setName("ryuu");
user.setAge(25);
user.setEmail("[email protected]");
userMapper.insert(user);
log.info("id" + user.getId());
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5a82ebf8] will be managed by Spring
==> Preparing: INSERT INTO t_user ( id, name, email, age ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1582699157263532033(Long), ryuu(String), [email protected](String), 25(Integer)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f096f37]
2022-10-19 19:44:18.924 INFO 20208 --- [ main] com.hikaru.MybatisplusApplicationTests : id1582699157263532033
mybatisplus的新增是能够获取到自增长的主键的:: id 15826991572635
这个值是由雪花算法生成的
这里还测试出了个有意思的地方,在测试类上开启声明式事务@Transactional测试结束之后会自动回滚。。想了半天数据库为啥没有新增,然后看到控制台打印如下:
Rolled back transaction for test: [DefaultTestContext@550dbc7a testClass = MybatisplusApplicationTests, testInstance = com.hikaru.MybatisplusApplicationTests@4f80542f, testMethod = contextLoads@MybatisplusApplicationTests, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@21282ed8 testClass = MybatisplusApplicationTests, locations = '{}', classes = '{class com.hikaru.MybatisplusApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@6ac13091, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@75329a49, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1534f01b, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@2473d930, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@7382f612], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
1.6 删除
① deleteById
userMapper.deleteById(1582701639167422466L);
② deleteByMap
Map<String, Object> map = new HashMap<>();
map.put("name", "zhangsan");
map.put("age", 23);
userMapper.deleteByMap(map);
deleteByMap会按照map进行删除,其中map存放的是删除的条件的键值对,条件之间为且的关系
==> Preparing: DELETE FROM t_user WHERE name = ? AND age = ?
==> Parameters: zhangsan(String), 23(Integer)
<== Updates: 0
③ deleteBatchIds 批量删除
@Test
void contextLoads() {
List<Long> idList = Arrays.asList(1L, 2L, 3L);
userMapper.deleteBatchIds(idList);
}
deleteBatchIds采用的是in的批量删除
==> Preparing: DELETE FROM t_user WHERE id IN ( ? , ? , ? )
==> Parameters: 1(Long), 2(Long), 3(Long)
<== Updates: 0
1.7 修改
updateById(Entity)
@Test
void contextLoads() {
User user = new User();
//user.setId(1L);
user.setEmail("[email protected]");
user.setName("zhangsan");
userMapper.updateById(user);
}
updateById会根据参数实体的id去按照条件修改
==> Preparing: UPDATE t_user SET name=?, email=? WHERE id=?
==> Parameters: zhangsan(String), [email protected](String), null
<== Updates: 0
可以看到这里没有设置age字段就不会出现在sql语句的条件里面,
没有设置id则id为null
1.8 查询
① selectById
② selectBatchIds
③ selectByMaps
④ selectList()
条件查询,如果选择器为null则查询所有数据
1.9 自定义查询
① 在application.yml配置mapper.xml文件位置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://192.168.60.100/mybatisplus?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:/mapper/**/*.xml
这里mapper-locations的值即为默认值
② 创建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.hikaru.mapper.UserMapper">
<select id="selectMapById" resultType="map">
select *
from t_user
where id = #{id}
</select>
</mapper>
③ 创建UserMapper接口的方法
@Mapper
public interface UserMapper extends BaseMapper<User> {
public Map<String, Object> selectMapById(@Param("id") long id);
}
这里可能出现@MapKey is required 的错误警告,无视就好,mybatisplus会自动将字段名和值对应key-value
2 IService
2.1 创建service
public interface UserService extends IService<User> {
}
2.2 创建ServiceImpl
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
注意泛型对应
2.3 查询总记录数 count
@Autowired
UserService userService;
@Test
void contextLoads() {
userService.count();
}
2.6 批量添加
@Test
void contextLoads() {
List<User> list = new ArrayList<>();
for(int i = 0; i < 10; i++) {
User user = new User();
user.setName("ryuu" + i);
user.setAge(20 + i);
user.setEmail("[email protected]");
list.add(user);
}
boolean b = userService.saveBatch(list);
log.info(Boolean.toString(b));
}
因为mapper的insert只有单个添加,这是因为批量添加会导致sql语句过长,这也是有service层的原因,而上面service的本质也是多次调用了mapper:
==> Preparing: INSERT INTO t_user ( id, name, email, age ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1582722877105381377(Long), ryuu0(String), [email protected](String), 20(Integer)
==> Parameters: 1582722877289930754(Long), ryuu1(String), [email protected](String), 21(Integer)
==> Parameters: 1582722877289930755(Long), ryuu2(String), [email protected](String), 22(Integer)
==> Parameters: 1582722877289930756(Long), ryuu3(String), [email protected](String), 23(Integer)
==> Parameters: 1582722877289930757(Long), ryuu4(String), [email protected](String), 24(Integer)
==> Parameters: 1582722877348651010(Long), ryuu5(String), [email protected](String), 25(Integer)
==> Parameters: 1582722877348651011(Long), ryuu6(String), [email protected](String), 26(Integer)
==> Parameters: 1582722877348651012(Long), ryuu7(String), [email protected](String), 27(Integer)
==> Parameters: 1582722877348651013(Long), ryuu8(String), [email protected](String), 28(Integer)
==> Parameters: 1582722877348651014(Long), ryuu9(String), [email protected](String), 29(Integer)
3 MybatisPlus常用注解
3.1 @TableName
在实体类上添加用于指定实体类对应的数据库表名,不添加则默认为首字母小写的类名
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
private Long id;
private String name;
private String email;
private Integer age;
}
3.2 @TableId
在实体类属性上添加@TableId将属性对应的字段指定为主键,如果不添加则默认主键为id并且会使用雪花算法进行生成。即当表的主键不是id则需要使用该注解。
属性对应的字段作为主键,是因为mp的框架结构需要先扫描实体类,然后抽取属性对字段进行操作的
而注解的value属性则适用于实体类属性名和字段名不同的情况,不写则与属性相同。
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId("uid")
private Long id;
private String name;
private String email;
private Integer age;
}
TableId的type属性
type属性用于指定主键的生成策略,默认为雪花算法,即使数据库使用了自动递增也是雪花算法。 而如果想要使用自动递增,还需要设置type:
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId(value = "uid", type = IdType.AUTO)
private Long id;
private String name;
private String email;
private Integer age;
}
其中IdType为一个枚举类,常用的主键生成策略主要有两种:
AUTO(0):自动递增
ASSIGN_ID(3):雪花算法(id为空的时候默认的策略)
public enum IdType {
AUTO(0),
NONE(1),
INPUT(2),
ASSIGN_ID(3),
ASSIGN_UUID(4),
/** @deprecated */
@Deprecated
ID_WORKER(3),
/** @deprecated */
@Deprecated
ID_WORKER_STR(3),
/** @deprecated */
@Deprecated
UUID(4);
private final int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
通过全局配置主键生成策略和表前缀
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
table-prefix: t_
4 雪花算法
数据库扩展的方式主要包括:
业务分库
:
主从复制
:即在保证数据一致的前提下,主服务器和从服务器实现表的读写分离。
数据库分表
:分为水平和垂直分表。
雪花算法是Twitter公布的一种分布式主键生成算法,它能够保证不同表的主键的不重复性和相同表的主键的有序性。
5 MBP常用注解
5.1 @TableFiled 设置属性对应普通字段名
MBP默认的规则是下划线字段名对应实体的驼峰写法,除此之外不一致的情况需要使用@TableFiled:
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId(value = "uid")
private Long id;
@TableField("user_name")
private String name;
private String email;
private Integer age;
}
@TableField(exist = false)
注解表明该属性不是数据库表的字段
5.2 @TableLogic 逻辑删除
-
物理删除:真实删除,将数据从数据库表中删除,之后查询不到此条被删除的数据
-
逻辑删除:假删除,只是将数据库中该数据设置为删除状态,之后仍然能从数据库中看到
-
使用场景:数据恢复
① 首先在逻辑删除属性上添加注解
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId(value = "uid")
private Long id;
@TableField("user_name")
private String name;
private String email;
private Integer age;
@TableLogic
private Integer isDelete;
}
② 进行删除操作
@Autowired
UserService userService;
@Test
void contextLoads() {
userService.removeById(1);
}
③ 观察这时候的sql语句,删除被替换为了更新:
==> Preparing: UPDATE t_user SET is_delete=1 WHERE uid=? AND is_delete=0
==> Parameters: 1(Integer)
<== Updates: 0
如果进行数据恢复,只需要将isDelete恢复为0即可
6 条件构造器 wrapper
-
Wrapper:条件构造器的抽象类,最顶端的父类
-
AbstractWrapper:用于查询条件封装,生成sql的where条件
-
QueryWrapper:查询条件封装
-
UpdateWrapper:Update条件封装
-
AbstractLambdaWrapper:使用Lambda语法
-
LambdaQueryWrapper:Lambda查询封装
-
LambdaUpdateWrapper:Lambda update封装
-
-
-
updateWrapper不但需要封装修改的条件还需要封装修改的字段,而删除是不需要提供字段只需要条件,因此查询和删除都使用QueryMapper做条件封装。
6.1 组装查询条件
@Test
void contextLoads() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("user_name", 2)
.between("age", 20, 25)
.isNotNull("email");
System.out.println(userService.list(queryWrapper));
}
对应的SQL
==> Preparing: SELECT uid AS id,user_name AS name,email,age,is_delete FROM t_user WHERE is_delete=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
==> Parameters: %2%(String), 20(Integer), 25(Integer)
<== Columns: id, name, email, age, is_delete
<== Row: 3, ryuu2, [email protected], 22, 0
<== Row: 13, ryuu2, [email protected], 22, 0
<== Total: 2
6.2 组装排序条件
@Test
void contextLoads() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age").orderByAsc("uid");
System.out.println(userService.list(queryWrapper));
}
对应SQL
==> Preparing: SEECT uid AS id,user_name AS name,email,age,is_delete
FROM t_user WHERE is_delete=0
ORDER BY age DESC,uid ASC
6.3 组装删除条件
@Test
void contextLoads() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNull("email");
System.out.println(userMapper.delete(queryWrapper));
}
对应sql
==> Preparing: UPDATE t_user SET is_delete=1 WHERE is_delete=0 AND (email IS NULL)
==> Parameters:
<== Updates: 1
6.4 组装修改功能
① 使用queryWrapper实现修改
@Test
void contextLoads() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("uid", 1)
.between("age", 20, 25)
.isNotNull("email");
User user = new User();
user.setName("小明");
user.setEmail("[email protected]");
userMapper.update(user, queryWrapper);
}
对应SQL
==> Preparing: UPDATE t_user SET user_name=?, email=?
WHERE is_delete=0 AND (uid LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
==> Parameters: 小明(String), [email protected](String), %1%(String), 20(Integer), 25(Integer)
② 使用UpdateWrapper实现修改
@Test
void contextLoads() {
// 将用户名中含有a 并且 (年龄大于20 或者 邮箱为null)的用户信息进行修改
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.like("user_name", "a")
.and(i -> i.gt("age", 20)
.or()
.isNotNull("email")
);
updateWrapper.set("user_name", "小黑");
int update = userMapper.update(null, updateWrapper);
log.info(String.valueOf(update));
}
对应SQL
==> Preparing: UPDATE t_user SET user_name=?
WHERE is_delete=0
AND (user_name LIKE ? AND (age > ? OR email IS NOT NULL))
==> Parameters: 小黑(String), %a%(String), 20(Integer)
6.5 组装select语句 实现查询指定字段
@Test
void contextLoads() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("user_name", "age");
List<Map<String, Object>> list = userMapper.selectMaps(queryWrapper);
System.out.println(list);
}
注意需要使用selectMaps接收
6.6 组装子查询
@Test
void contextLoads() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("uid", "select uid from t_user where age > 25");
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}
对应SQL
==> Preparing: SELECT uid AS id,user_name AS name,email,age,is_delete
FROM t_user WHERE is_delete=0
AND (uid IN (select uid from t_user where age > 25))
==> Parameters:
<== Columns: id, name, email, age, is_delete
6.7 模拟开发中的条件组装
@Test
void contextLoads() {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
String userName = "r";
Integer ageBegin =20;
Integer ageEnd =25;
if(StringUtils.isBlank(userName)) {
updateWrapper.like("user_name", "a");
}
if(ageBegin != null) {
updateWrapper.gt("age", ageBegin);
}
if(ageEnd != null) {
updateWrapper.lt("age", ageEnd);
}
updateWrapper.set("user_name", "小黑");
int update = userMapper.update(null, updateWrapper);
log.info(String.valueOf(update));
}
StringUtils.isBlank 判断字符串
① 不为空串
② 不为null
③ 不为空白符
==> Preparing: UPDATE t_user SET user_name=? WHERE is_delete=0 AND (age > ? AND age < ?)
==> Parameters: 小黑(String), 20(Integer), 25(Integer)
<== Updates: 8
6.8 使用condition进行条件判断
上面的写法需要用户传入条件后对每个条件进行编写判断,变得十分复杂
7 Lambda表达式优先执行实现条件优先级
考虑下面两条sql的条件优先级:
// 将用户名包含r 并且 年龄大于20 或者 邮箱为null的用户信息进行修改
// 将用户名包含r 并且 (年龄大于20 或者 邮箱为null)的用户信息进行修改
@Test
void contextLoads() {
// 将用户名包含r 并且 年龄大于20 或者 邮箱为null的用户信息进行修改
// 将用户名包含r 并且 (年龄大于20 或者 邮箱为null)的用户信息进行修改
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("user_name", "r")
.and(i -> i.gt("age", 20)
.or()
.isNull("email")
);
User user = new User();
user.setName("小Li");
user.setEmail("[email protected]");
userMapper.update(user, queryWrapper);
}
利用Lambda表达式优先执行实现条件的优先级
对应SQL
==> Preparing: UPDATE t_user SET user_name=?, email=? WHERE is_delete=0
AND (user_name LIKE ? AND (age > ? OR email IS NULL))
==> Parameters: 小Li(String), [email protected](String), %r%(String), 20(Integer)
<== Updates: 13
8 LambdaQueryWraper
上面的代码中充斥着大量的字段名魔法值,为了防止字段写错,使用Lambda表达式来获取属性对应的字段名
@Test
public void lambadaQueryMapperTest() {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
String userName = "8";
queryWrapper.like(StringUtils.isNotBlank(userName), User::getName, userName)
.ge(User::getAge, 20)
.le(User::getAge, 21);
List<User> users = userMapper.selectList(queryWrapper);
System.out.println(users);
}
对应SQL
==> Preparing: SELECT uid AS id,user_name AS name,email,age,is_delete FROM t_user WHERE is_delete=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)
==> Parameters: %8%(String), 20(Integer), 21(Integer)
<== Total: 0
9 LambdaUpdateWraper
@Test
void contextLoads() {
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
String userName = "r";
Integer ageBegin =20;
Integer ageEnd =25;
updateWrapper.like(StringUtils.isNotBlank(userName), User::getName, userName)
.gt(ageBegin!=null, User::getAge, ageBegin)
.lt(ageEnd!=null, User::getAge, ageEnd);
updateWrapper.set(User::getName, "小黑");
int update = userMapper.update(null, updateWrapper);
log.info(String.valueOf(update));
}
对应SQL
==> Preparing: UPDATE t_user SET user_name=? WHERE is_delete=0 AND (user_name LIKE ? AND age > ? AND age < ?)
==> Parameters: 小黑(String), %r%(String), 20(Integer), 25(Integer)
<== Updates: 0
10 MybatisPlus插件
Mybatis自带分页插件,只需要简单的配置就可实现分页功能
配置插件
@Configuration
@MapperScan("com.hikaru.mapper.UserMapper")
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
插件使用
@Test
public void testPage() {
Page<User> page = new Page<>(2, 3);
userMapper.selectPage(page, null);
System.out.println(page.getRecords());
}
对应SQL:
Preparing: SELECT uid AS id,user_name AS name,email,age,is_delete FROM t_user WHERE is_delete=0 LIMIT ?,?
自定义分页功能
① 在mapper.xml中编写SQL
<mapper namespace="com.hikaru.mapper.UserMapper">
<select id="selectMapById" resultType="map">
select *
from t_user
where id = #{id}
</select>
<select id="selectUserVOPage" resultType="User">
select * from t_user where age > #{age}
</select>
</mapper>
这里能够直接在resultType中写User是因为使用了类型别名(为不区分大小写的类名),类型别名的包在配置文件中配置:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
table-prefix: t_
id-type: auto
type-aliases-package: com.hikaru.entity
② 在Mapper接口中定义对应的方法
Page<User> selectUserVOPage(@Param("page") Page<User> page,
@Param("age") int age);
注意这里第一个参数必须为对应泛型型的page,返回值类型也必须为对应泛型型的Page
乐观锁与悲观锁
剩下的内容等以后再看吧。。
标签:name,age,Plus,user,Mybatis,Integer,id,String From: https://www.cnblogs.com/tod4/p/16818411.html