各种各样的sql需要写,什么分页啊,条件查询啊,真的太难了,之后发现有个mp,自动帮我们写sql,挺好用的,可能其他人喜欢jpa,可以都去了解一下。
官网https://mp.baomidou.com/
# 配置日志 默认控制台
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置逻辑删除
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.mapper-locations=classpath:mybatis/mapper/*Mapper.xml
#是否使用 驼峰 默认使用
# mybatis-plus.configuration.map-underscore-to-camel-case=false
# 取别名
mybatis-plus.type-aliases-package=com.myh.pojo
java类 mysql数据库
java.lang.Byte byte TINYINT
java.lang.Short short SMALLINT
java.lang.Integer integer INGEGER
java.lang.Long long BIGINT
java.lang.Float float FLOAT
java.lang.Double double DOUBLE
java.lang.BigDecimal big_decimal NUMERIC
java.lang.Boolean boolean BIT
java.lang.String string VARCHAR
java.lang.Boolean yes_no CHAR(1)('Y'或'N')
java.lang.Boolean true_false CHAR(1)(‘Y’或'N')
java.uitl.Date date DATE
java.sql.Date date DATE
java.sql.Time time TIME
java.sql.Timestamp timestamp TIMESTAMP
java.uitl.Calendar celendar TIMESTAMP
java.uitl.Calendar calendar TIMESTAMP
java.io.Serializable serializable VARBINARY/BLOB
java.sql.Clob clob CLOB
java.sql.Blob blob BLOB
java.lang.Class class VARCHAR
java.uitl.Locale locale VARCHAR
java.uitl.TimeZone timezone VARCHAR
java.uitl.Currency currency VARCHAR
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
@Retention:注解的保留位置
RetentionPolicy.SOURCE:这种类型的Annotations
只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,
在class文件中存在,但JVM将会忽略,运行时无法获得。
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,
所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
创建springboot的链接 eclipse有时候超时 可以用下面这个
https://start.aliyun.com/
1.创建数据库
create database mybats_plus charactor set utf8
2.创建user表
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
//真实开发
//version 乐观锁
//delete 逻辑删除
//gmt_create
//gmt_modified
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.0.5version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
mybatis和mybatisplus不要同时导入 会有依赖版本问题 导入mybatisplus就行了
配置文件
5和8有区别 8需要时区 5驱动不同
server.port=8080
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?
serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
传统方式pojo -dao(连接mybatispuls ,配置mapper.xml文件) -service -controller
现在方式:pojo mapper 使用
@Repository
@Mapper //在启动类中取扫描
public interface UserMapper extends BaseMapper<User> {
//所有的crud操作都已经完成编写了
//你不需要像以前配置一大堆文件了
}
Test
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//参数是一个wapper 条件构造器
//查询全部用户
List<User> list= userMapper.selectList(null);
list.forEach(System.out::println);
}
}
在mybatis-plus中,默认开启驼峰命名
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "user")
public class User {
//对应数据库的主件 uuid 自增id 雪花算法 redis zookeeper
//默认 全局唯一id ID_WORKER
//自增AUTO 数据库也有变成自增
@TableId(type = IdType.AUTO)
private Long id;
// private String name;
private String userName;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmt_modified;
}
// 如果你的字段类型为userName,那么在数据库查询的时候映射的时候
// 默认映射为user_name 如果此时你的数据库字段为userName就会报错
// 也就是他自动将userName转化为 user_name
// 所以此时你的数据库字段应该为 user_name
// 也就是只在俩种情况会映射成功
//1.字段名和数据库一样 映射成功
//2.驼峰命名规则也会成功
关闭驼峰命名
mybatis-plus:
configuration:
map-underscore-to-camel-case: false
# 是否开启自动驼峰命名规则(camel case)映射,
即从经典数据库列名 A_COLUMN(下划线命名)
到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
spring中
<bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
<property name="idType" value="0"/>
<property name="dbColumnUnderline" value="flase"/>
bean>
# 配置日志 默认控制台
mybatis-plus.configuration.log-impl=
org.apache.ibatis.logging.stdout.StdOutImpl
List<User> list= userMapper.selectList(null);
List<User> list1= userMapper.selectList(null);
//没有缓存
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@655a01d8] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@935599808 wrapping com.mysql.cj.jdbc.ConnectionImpl@35a0e495] will not be managed by Spring
==> Preparing: SELECT id,name,age,email FROM user
==> Parameters:
<== Columns: id, name, age, email
<== Row: 1, Jone, 18, [email protected]
<== Row: 2, Jack, 20, [email protected]
<== Row: 3, Tom, 28, [email protected]
<== Row: 4, Sandy, 21, [email protected]
<== Row: 5, Billie, 24, [email protected]
<== Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@655a01d8]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@770beef5] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1842476600 wrapping com.mysql.cj.jdbc.ConnectionImpl@35a0e495] will not be managed by Spring
==> Preparing: SELECT id,name,age,email FROM user
==> Parameters:
<== Columns: id, name, age, email
<== Row: 1, Jone, 18, [email protected]
<== Row: 2, Jack, 20, [email protected]
<== Row: 3, Tom, 28, [email protected]
<== Row: 4, Sandy, 21, [email protected]
<== Row: 5, Billie, 24, [email protected]
<== Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@770beef5]
User(id=1, name=Jone, age=18, [email protected])
User(id=2, name=Jack, age=20, [email protected])
User(id=3, name=Tom, age=28, [email protected])
User(id=4, name=Sandy, age=21, [email protected])
User(id=5, name=Billie, age=24, [email protected])
开启二级缓存后,MP的baseMapper中提供的一系列Select方法不能命中二级缓存,只有自定义的方法才能命中二级缓存。
官方:我们建议缓存放到 service 层,你可以自定义自己的 BaseServiceImpl 重写注解父类方法,继承自己的实现。
@Test
void contextLoads1() {
//查询全部用户
User user=new User(); //自动生成id
user.setAge(3);
user.setEmail("[email protected]");
user.setName("A");
userMapper.insert(user); //返回会影响的行数 id会自动回填 默认学号算法
}
//Creating a new SqlSession
//SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@c269425] was not registered for //synchronization because synchronization is not active
//JDBC Connection [HikariProxyConnection@1818236857 wrapping com.mysql.cj.jdbc.ConnectionImpl@4730e0f0] will not be managed by Spring
//==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
//==> Parameters: 1264024876485070849(Long), A(String), 3(Integer), [email protected](String)
//<== Updates: 1
//Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@c269425]
主键生成策略
@TableId(type = IdType.AUTO)
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
* 该类型可以通过自己注册自动填充插件进行填充
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
private int key;
IdType(int key) {
this.key = key;
}
}
默认 ID_WORKER 全局唯一id
分布式系统唯一id生成:https://www.cnblogs.com/haoxinyue/p/5208136.html
雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使
用41bit作为 毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作
为毫秒内的流水号(意味 着每个节点在每毫秒可以产生 4096 个 ID),后还有一个符号位,
永远是0。可以保证几乎全球唯 一!
主键自增
1、实体类字段上 @TableId(type = IdType.AUTO)
2、数据库字段一定要是自增!不然报错!
3、再次测试插入即可!
@Test
void contextLoads2() {
//参数是一个wapper 条件构造器
//查询全部用户
User user=new User();
user.setId(1L);
user.setAge(30);
user.setEmail("[email protected]");
user.setName("3");
userMapper.updateById(user);
}
// 在插入时 如果对象的字段的属性为null 那么在插入时不会出现在插入语句中
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6614bd4b] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@282812721 wrapping com.mysql.cj.jdbc.ConnectionImpl@6c6017b9] will not be managed by Spring
==> Preparing: UPDATE user SET name=?, age=?, email=? WHERE id=?
==> Parameters: 3(String), 30(Integer), 3@qq.com(String), 1(Long)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6614bd4b]
创建时间 修改时间 !这些操作一遍都是自动化完成的,不希望手动更新
阿里巴巴开发手册:所有的数据库表:gmt_create gmt_modified几乎所有的表都要配置上,查看数据修改时间
新字段
gmt_create
gmt_modified
//CURRENT_TIMESTAMP 默认值 当前时间
@TableField(fill = FieldFill.UPDATE)
private Data gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Data gmtModified;
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
编写处理器
@Component //要把处理器加入到ioc容器中
public class Myhander implements MetaObjectHandler{
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert insertFill");
this.setFieldValByName("gmtCreate", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
// TODO Auto-generated method stub
log.info("start insert updateFill");
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
}
乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题, 再次更新值测试
悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
我们这里主要讲解 乐观锁机制!
乐观锁实现方式:
乐观锁:1、先查询,获得版本号 version = 1
-- A update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1
-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update user set name = "kuangshen", version = version + 1
where id = 2 and version = 1
1、给数据库中增加version字段!
2、我们实体类加对应的字段
//乐观锁
@Version //乐观锁Version注解
private Integer version;
3、注册组件
//扫描我们的 mapper 文件夹
@MapperScan("com.myh.mapper")
@EnableTransactionManagement
//Spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement
// 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可
@Configuration // 配置
public class MyMybatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4、测试一下!
//更新一个用户 测试乐观锁
@Test
void contextLoads3() {
//参数是一个wapper 条件构造器
//查询全部用户
User user = userMapper.selectById(1L);
user.setName("1L");
userMapper.updateById(user);
}
==> Preparing: UPDATE user SET name=?, age=?, email=?, gmt_create=?, gmt_modified=?, version=? WHERE id=? AND version=?
==> Parameters: 1L(String), 301(Integer), 3@qq.com(String), 2020-05-23 19:12:05.0(Timestamp), 2020-06-12 09:53:10.931(Timestamp), 2(Integer), 1(Long), 1(Integer)
<== Updates: 1
失败的
//更新一个用户 测试乐观锁 失败
@Test
void contextLoads4() {
// 线程 1
User user = userMapper.selectById(1L);
user.setName("1L");
// 模拟另外一个线程执行了插队操作
User user2 = userMapper.selectById(1L);
user2.setName("2L");
userMapper.updateById(user2);
userMapper.updateById(user);
}
==> Preparing: UPDATE user SET name=?, age=?, email=?, gmt_create=?, gmt_modified=?, version=? WHERE id=? AND version=?
==> Parameters: 111(String), 301(Integer), 3@qq.com(String), 2020-05-23 19:12:05.0(Timestamp), 2020-06-12 09:56:11.94(Timestamp), 3(Integer), 1(Long), 2(Integer)
<== Updates: 1
==> Preparing: UPDATE user SET name=?, age=?, email=?, gmt_create=?, gmt_modified=?, version=? WHERE id=? AND version=?
==> Parameters: 2L(String), 301(Integer), 3@qq.com(String), 2020-05-23 19:12:05.0(Timestamp), 2020-06-12 09:56:12.032(Timestamp), 3(Integer), 1(Long), 2(Integer)
<== Updates: 0
//查询操作
// 测试查询 查询一个
@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
//==> Preparing: SELECT id,name,age,email,gmt_create,gmt_modified,version FROM user WHERE id=?
//==> Parameters: 1(Long)
//<== Columns: id, name, age, email, gmt_create, gmt_modified, version
//<== Row: 1, 2L1, 301, [email protected], 2020-05-23 11:12:05, 2020-06-12 02:07:07, 6
//<== Total: 1
}
//批量查询
@Test
public void testSelectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
//==> Parameters: 1(Integer), 2(Integer), 3(Integer)
//<== Columns: id, name, age, email, gmt_create, gmt_modified, version
//<== Row: 1, 2L1, 301, [email protected], 2020-05-23 11:12:05, 2020-06-12 02:07:07, 6
//<== Row: 2, 3, 301, [email protected], 2020-05-23 11:12:05, 2020-06-12 01:38:36, 1
//<== Row: 3, Tom, 28, [email protected], 2020-05-23 11:12:05, 2020-05-23 11:12:38, 1
//<== Total: 3
}
// 按条件查询之一使用map操作
@Test
public void testSelectByBatchIds() {
HashMap<String, Object> map = new HashMap<>();// 自定义要查询
map.put("name", "Billie");
map.put("age", 24);
userMapper.selectByMap(map);
//==> Preparing: SELECT id,name,age,email,gmt_create,gmt_modified,version FROM user WHERE name = ? AND age = ?
//==> Parameters: Billie(String), 24(Integer)
//<== Columns: id, name, age, email, gmt_create, gmt_modified, version
//<== Row: 5, Billie, 24, [email protected], 2020-05-23 11:12:05, 2020-05-23 11:12:38, 1
//<== Total: 1
}
1、原始的 limit 进行分页
2、pageHelper 第三方插件
3、MP 其实也内置了分页插件!
如何使用?
1、配置拦截器组件即可
// 分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
// 测试分页查询
// 1.注册插件
// 2.new Page
// 3.开始查询
// 按条件查询之一使用map操作
// 测试分页查询
@Test
public void testPage(){
// 参数一:当前页
// 参数二:页面大小
// 使用了分页插件之后,所有的分页操作也变得简单的!
Page<User> page = new Page<>(2,5);
IPage<User> selectPage = userMapper.selectPage(page,null);
System.out.println(selectPage.getCurrent());
System.out.println(selectPage.getPages());
System.out.println(selectPage.getSize());
System.out.println(selectPage.getTotal());
page.getRecords().forEach(System.out::println);
// System.out.println(page.getTotal());
}
==> Preparing: SELECT COUNT(1) FROM user
==> Parameters:
<== Columns: COUNT(1)
<== Row: 9
==> Preparing: SELECT id,name,age,email,gmt_create,gmt_modified,version FROM user LIMIT 5,5
==> Parameters:
<== Columns: id, name, age, email, gmt_create, gmt_modified, version
<== Row: 1264024876485070849, A, 3, 1@qq.com, 2020-05-23 11:12:05, 2020-05-23 11:12:38, 1
<== Row: 1264024876485070850, A, 3, 1@qq.com, 2020-05-23 11:12:05, 2020-05-23 11:12:38, 1
<== Row: 1264024876485070851, 3, 30, 3@qq.com, 2020-06-10 09:02:20, 2020-05-23 03:33:16, 1
<== Row: 1264024876485070852, 3, 301, 3@qq.com, 2020-05-23 03:33:34, 2020-06-12 01:30:40, 1
<== Total: 4
1、根据 id 删除记录
// 测试删除
@Test
public void testDeleteById(){
int deleteById = userMapper.deleteById(1240620674645544965L);
System.out.println(deleteById);
//==> Preparing: DELETE FROM user WHERE id=?
//==> Parameters: 1240620674645544965(Long)
//<== Updates: 0
}
// 通过id批量删除
@Test
public void testDeleteBatchId(){
int deleteBatchIds = userMapper.deleteBatchIds(Arrays.asList(1264024876485070852L,1240620674645544962L));
System.out.println(deleteBatchIds);
//==> Preparing: DELETE FROM user WHERE id IN ( ? , ? )
//==> Parameters: 1264024876485070852(Long), 1240620674645544962(Long)
//<== Updates: 1
}
// 通过map删除 动态sql
@Test
public void testDeleteMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","1");
map.put("age","1");
userMapper.deleteByMap(map);
}
//==> Preparing: DELETE FROM user WHERE name = ? AND age = ?
//==> Parameters: 1(String), 1(String)
//<== Updates: 0
物理删除 :从数据库中直接移除
逻辑删除 :再数据库中没有被移除,而是通过一个变量来让他失效! deleted = 0 => deleted = 1
1、在数据表中增加一个 deleted 字段
2、实体类中增加属性
@TableLogic //逻辑删除
private Integer deleted;
3、配置插件!
# 配置逻辑删除
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4.注册插件
// 逻辑删除组件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
附件说明:
如: 员工离职,账号被锁定等都应该是一个状态字段,此种场景不应使用逻辑删除。
性能分析拦截器,用于输出每条 SQL 语句及其执行时间
该插件 3.2.0 以上版本移除推荐使用第三方扩展 执行SQL分析打印 功能
我们在平时的开发中,会遇到一些慢sql。测试! druid,
作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间
MP也提供性能分析插件,如果超过这个时间就停止运行!
/** * SQL执行效率插件 */
// 设置 dev test 环境开启,保证我们的效率
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
// ms设置sql执行的最大时间,如果超过了则不 执行1000ms
performanceInterceptor.setMaxTime(10);
// performanceInterceptor.setWriteInLog(true); //是否写入日志
// 是否格式化代码
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
记住,要在SpringBoot中配置环境为dev或者 test 环境!
spring.profiles.active=dev
2、测试使用!
//查询操作
// 测试查询 查询一个
@Test
public void testSelectById(){
Book selectById = bookMapper.selectById(1);
System.out.println(selectById);
}
//Time:66 ms - ID:com.myh.mapper.BookMapper.selectById
自定义sql
1.注解
2.和mybatis一样的配置文件
3.可以将mybatis-plsu 看成mybatis
原因是只在mybatis上面只做增强 不做修改
但是多表还是要自己写sql,虽然自己写 但是模糊和分页已经做好了
test 多表分页条件查询
User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "user")
public class User {
//对应数据库的主件 uuid 自增id 雪花算法 redis zookeeper
//默认 全局唯一id ID_WORKER
//自增AUTO 数据库也有变成自增
@TableId(type = IdType.AUTO)
private Long id;
@TableField(value = "name")
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmt_modified;
private Book book;
//乐观锁
//乐观锁Version注解 需要注册插件
@Version
private Integer version;
@TableLogic //逻辑删除
private Integer deleted;
@TableField(el ="order",exist = false)
private Order order;
@TableField(el ="book",exist = false)
private List<Book> bookList;
}
Book实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "book")
public class Book {
@TableId(value = "id")
private Long id;
@TableField(value = "name")
private String name;
@TableField(value = "u_id")
private Long uid;
}
user接口
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
//所有的crud操作都已经完成编写了
//你不需要像以前配置一大堆文件了
// @Select("select * from `user` u,book b where u.id=b.u_id ")
// public User getUserOne();
public Page<User> findAllAndPage(IPage<User> page,@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
}
usermapper的xml
<resultMap type="com.myh.pojo.User" id="userAll">
<result column="uid" property="id"/>
<association property="book" javaType="com.myh.pojo.Book">
<result column="bid" property="id"/>
</association>
</resultMap>
<select id="findAllAndPage" resultMap="userAll">
select u.id uid,b.id bid fROM user u INNER JOIN book b on u.id=b.u_id ${ew.customSqlSegment}
</select>
我这里简单 ,所有只显示了bid和uid,需要啥就映射啥
//自定义SQL 分页
@Test
public void findAllAndPage() {
Page<User> page=new Page<User>(0, 5);
QueryWrapper<User> qw=new QueryWrapper<User>();
qw.eq("b.id", "1").eq("u.id", 1264024876485070850L);
Page<User> findAllAndPage = userMapper.findAllAndPage(page,qw);
}
==> Parameters: 1(String), 1264024876485070850(Long)
<== Columns: COUNT(1)
<== Row: 1
==> Preparing: select u.id uid,b.id bid fROM user u INNER JOIN book b on u.id=b.u_id WHERE b.id = ? AND u.id = ? LIMIT ?,?
==> Parameters: 1(String), 1264024876485070850(Long), 0(Long), 5(Long)
<== Columns: uid, bid
<== Row: 12640
//为什么有俩条呢?因为分页返回的Ipage,里面有个count,如果不需要级在分页的时候第三个参数变为false就行了
ok到这里分页多和多表和添加查询就ok了。
总结
感想:mp解决的单表大部分操作,对于多表来说就不那么友好,但是,好在解决了其它的麻烦。
比如分页和条件查询,它都帮我们解决了 多表的话建议使用内连接配合条件查询。感兴趣的话也可以去了解jpa。
笔记来源:https://space.bilibili.com/95256449/
我自己也适当的改了一点点。