mybatisplus学习笔记
准备工作
参考网址
- https://blog.csdn.net/qq_45397131/article/details/124364292
- http://www.45fan.com/article.php?aid=1CUibMFNhW1yQWQ9
Mybatis中#{}和${}的区别
{}是预编译处理,${}是字符串替换。
-
在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
-
在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
准备数据
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` bigint NOT NULL,
`price` int NULL DEFAULT NULL,
`remark` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_id` int NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
`create_time` timestamp NULL DEFAULT NULL,
`version` int NULL DEFAULT 1,
`del_flag` int NULL DEFAULT 0,
`create_by` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES (1, 57, '广东', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (2, 38, '新疆', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'linda', 'linda');
INSERT INTO `orders` VALUES (3, 45, '中国', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (4, 79, '四川', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (5, 198, '山东', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
INSERT INTO `orders` VALUES (6, 22, '云南', 1, '2022-10-03 12:24:54', '2022-10-03 12:24:54', 1, 0, 'simon', 'linda');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`age` int NULL DEFAULT NULL,
`address` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'simon', '111111', '张三', 48, '盛大花园38-04-502');
INSERT INTO `user` VALUES (2, 'linda', '111111', '李四', 48, NULL);
INSERT INTO `user` VALUES (3, 'doudou', '111111', '王五', 99, NULL);
INSERT INTO `user` VALUES (6, 'lisi', '111111', NULL, 99, NULL);
SET FOREIGN_KEY_CHECKS = 1;
idea插件
推荐两个插件:
Free MyBatis Tool
该插件可以通过idea中的数据库连接界面中集中生成mapper、entity、xml等。
Mybatis Generator
该插件可以在没有xml的情况下,先编写接口,然后通过接口及方法生成xml文件,并且在xml文件中生成方法片段。
新建springboot工程
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.simon</groupId>
<artifactId>mybatisplustest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatisplustest</name>
<description>mybatisplustest</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: root
mybatis-plus:
# global-config:
# db-config:
# table-prefix: sys_
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
mapper-locations: classpath*:/mapper/**/*.xml
pojo准备
user
@Data
@NoArgsConstructor
@AllArgsConstructor
//@TableName("sys_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
@TableField("address")
private String address;
}
orders
@Data
public class Orders implements Serializable {
private Long id;
private Integer price;
private String remark;
private Integer userId;
private Date updateTime;
private Date createTime;
private Integer version;
private Integer delFlag;
private String createBy;
private String updateBy;
private static final long serialVersionUID = 1L;
}
扫描类路径配置
@SpringBootApplication
@MapperScan("com.simon.app.mapper")
public class Test {
public static void main(String[] args) {
SpringApplication.run(Test.class,args);
}
}
在启动类中添加@MapperScan注解,内容为mapper类存放的包名。
基本操作
mapper类
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.simon.app.domain.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper extends BaseMapper<User> {
}
增删改查
@SpringBootTest
class MybatisPlusTests {
@Autowired
private UserMapper userMapper;
@Test
public void testQueryList(){
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
/**
* 自增主键,表要设为自增主键
* id属性要设置@TableId(type = IdType.AUTO)
*/
@Test
public void testIdAutoIncrementInsert(){
User user=new User();
user.setUserName("wangwu");
user.setPassword("111111");
int insert = userMapper.insert(user);
System.out.println(insert);
}
@Test
public void testDeleteById(){
userMapper.deleteById(4);
}
@Test
public void testDeleteByMap(){
Map map = new HashMap();
map.put("user_name","wangwu");
userMapper.deleteByMap(map);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(6L);
user.setUserName("lisi");
userMapper.updateById(user);
}
}
- 当mapper继承自BaseMapper后,就具备了基本的增删改查操作。
- 要编写junit测试类,该测试类要所在包要和application主启动类在相同包下
Wrapper-条件构造器
AbstractWrapper通用方法
- eq:等于 = 例: eq("name", "老王")--->name = '老王'
- ne:不等于<> 例: ne("name", "老王")--->name <> '老王'
- gt:大于> 例: gt("age", 18)--->age > 18
- ge:大于等于>= 例: ge("age", 18)--->age >= 18
- lt:小于< 例:lt("age", 18)--->age < 18
- le:小于等于<= 例:le("age", 18)--->age <= 18
- between:BETWEEN 值1 AND 值2 例: between("age", 18, 30)--->age between 18 and 30
- notBetween:NOT BETWEEN 值1 AND 值2 例: notBetween("age", 18, 30)--->age not between 18 and 30
- like:LIKE '%值%' 例: like("name", "王")--->name like '%王%'
- notLike:NOT LIKE '%值%' 例: notLike("name", "王")--->name not like '%王%'
- likeLeft:LIKE '%值' 例: likeLeft("name", "王")--->name like '%王'
- likeRight:LIKE '值%' 例: likeRight("name", "王")--->name like '王%'
- isNull:字段 IS NULL 例: isNull("name")--->name is null
- isNotNull:字段 IS NOT NULL 例: isNotNull("name")--->name is not null
- in:字段 IN (value.get(0), value.get(1), ...) 例: in("age",{1,2,3})--->age in (1,2,3)
- notIn:字段 NOT IN (value.get(0), value.get(1), ...) 例: notIn("age",{1,2,3})--->age not in (1,2,3)
- inSql:字段 IN ( sql语句 ) 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6) 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3)
- notSql:字段 NOT IN ( sql语句 ) 例: notInSql("age", "1,2,3,4,5,6")--->age not in (1,2,3,4,5,6) 例: notInSql("id", "select id from table where id < 3")--->id not in (select id from table where id < 3)
- groupBy:分组:GROUP BY 字段, ... 例: groupBy("id", "name")--->group by id,name
- orderByAse:排序:ORDER BY 字段, ... ASC 例: orderByAsc("id", "name")--->order by id ASC,name ASC
- orderByDesc:排序:ORDER BY 字段, ... DESC 例: orderByDesc("id", "name")--->order by id DESC,name DESC
- orderBy:排序:ORDER BY 字段, ... 例: orderBy(true, true, "id", "name")--->order by id ASC,name ASC
- having:HAVING ( sql语句 ) 例: having("sum(age) > 10")--->having sum(age) > 10 例: having("sum(age) > {0}", 11)--->having sum(age) > 11
QueryWrapper
常规QueryWrapper
@Test
public void testQueryList(){
QueryWrapper wrapper = new QueryWrapper();
wrapper.gt("age",30);
wrapper.eq("user_name","simon");
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
@Test
public void testIn(){
QueryWrapper wrapper = new QueryWrapper();
wrapper.in("id",1,2,3);
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
字段过滤
@Test
public void test1(){
QueryWrapper wrapper = new QueryWrapper();
wrapper.select(User.class, new Predicate<TableFieldInfo>() {
@Override
public boolean test(TableFieldInfo tableFieldInfo) {
return "user_name".equals(tableFieldInfo.getColumn());
}
});
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
@Test
public void test2(){
QueryWrapper<User> wrapper = new QueryWrapper<>(new User());
wrapper.select(tableFieldInfo -> !"address".equals(tableFieldInfo.getColumn()));
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
Predicate的test会循环遍历所有字段名称,并返回boolean,如果为true,则相应的字段就会追加到select列表中。
Lambda表达式
@Test
public void testLambda2(){
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(new User());
wrapper.eq(User::getName,"simon");
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}
User::getName的用法是不需要直接指定物理字段名称,用属性名代替。
UpdateWrapper
直接使用wrapper通过set设定某个字段的值来更新
@Test
public void testUpdateWrapper(){
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id",2);
wrapper.set("age",99);
userMapper.update(null,wrapper);
}
通过pojo赋值进行更新
@Test
public void testUpdateWrapper1(){
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id",2);
User user=new User();
user.setAge(1000);
userMapper.update(user,wrapper);
}
Lambda表达式
@Test
public void testUpdateLambda(){
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getId,3);
User user=new User();
user.setAge(48);
userMapper.update(user,wrapper);
}
UpdateWrapper的作用是拼接where条件语句
另一种方法
LambdaUpdateWrapper<Orders> wrapper=new LambdaUpdateWrapper<Orders>();
wrapper.set(Orders::getRemark,"贵州");
wrapper.eq(Orders::getId,7L);
ordersMapper.update(null,wrapper);
链式表达
LambdaUpdateWrapper<Orders> wrapper = new LambdaUpdateWrapper<Orders>()
.set(Orders::getRemark,"贵州")
.eq(Orders::getId , 7L);
ordersMapper.update(null,wrapper);
自定义方法
如果我们想在自定义方法中使用条件构造器,可按照如下顺序操作
定义mapper方法
public interface UserMapper extends BaseMapper<User> {
public User findByWrapper(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}
此处Constants.WRAPPER代表传入xml方法的参数名前缀,该值为:String WRAPPER = "ew";也可以自定义。
自定义sql
<select id="findByWrapper" resultType="com.simon.app.domain.User">
select * from user ${ew.customSqlSegment}
</select>
使用
@Test
public void testWrapper(){
LambdaQueryWrapper<User> wr = new LambdaQueryWrapper<>();
wr.eq(User::getId,1L);
User user = userMapper.findByWrapper(wr);
System.out.println(user);
}
使用@select注解
也可以不在xml中定义sql,而直接使用@select注解
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.simon.app.domain.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface UserMapper extends BaseMapper<User> {
@Select("SELECT * FROM user ${ew.customSqlSegment}")
public User findUserByAnnotation(@Param(Constants.WRAPPER) Wrapper wrapper);
}
测试
@Test
public void testSelectAnnotation(){
LambdaQueryWrapper<User> wr = new LambdaQueryWrapper<>();
wr.eq(User::getId,1L);
User user = userMapper.findUserByAnnotation(wr);
System.out.println(user);
}
分页
准备
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
@Configuration
public class MyBatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
此处PaginationInnerInterceptor的参数指定数据库类型。
使用
使用内置方法分页
@Test
public void getPage(){
IPage<User> page=new Page<User>();
page.setSize(10);
page.setCurrent(1);
userMapper.selectPage(page, null);
System.out.println(page.getRecords());
System.out.println(page.getTotal());
}
通过内置拦截器分页
加入我们要查询orders表,并且要知道每个order对应人的真实姓名,按以下步骤操作
扩展pojo
在原有Orders类上增加一个userName属性,也可新建一个OrderVo类添加该属性。
@Data
public class OrdersVo implements Serializable {
private Long id;
private Integer price;
private String remark;
private Integer userId;
private Date updateTime;
private Date createTime;
private Integer version;
private Integer delFlag;
private String createBy;
private String updateBy;
private String userName;
private static final long serialVersionUID = 1L;
}
mapper接口定义
public interface OrdersMapper extends BaseMapper<Orders> {
public IPage<OrdersVo> findAllOrdersByPage(Page<OrdersVo> page);
}
此处必须要传入Page参数,用于保存每一页记录数及页码,返回类型为IPage。
定义接口方法
<select id="findAllOrdersByPage" resultType="com.simon.app.domain.OrdersVo">
select o.*,u.user_name from orders o join user as u on o.user_id=u.id
</select>
测试
@Test
public void getOrdersByPage(){
Page<OrdersVo> page = new Page<>();
page.setSize(2);
page.setCurrent(2);
IPage<OrdersVo> pages = ordersMapper.findAllOrdersByPage(page);
System.out.println(pages.getRecords());
System.out.println(pages.getTotal());
}
service接口
基本使用
service接口定义
import com.baomidou.mybatisplus.extension.service.IService;
import com.simon.app.domain.User;
public interface UserService extends IService<User> {
}
service接口实现定义
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.simon.app.domain.User;
import com.simon.app.mapper.UserMapper;
import com.simon.app.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
测试
@Test
public void testList(){
List<User> list = userService.list();
System.out.println(list);
}
lambda表达式
这个是方法返回结果不止一条则会抛出异常。
@Test
public void getOne() {
User one = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getAge, 48),false);
System.out.println(one);
}
/**
* lombda查询
*/
@Test
public void lambdaQuery(){
List<User> list = userService.lambdaQuery().eq(User::getAge, 18).list();
list.forEach(System.out::println);
}
/**
* lombda修改
*/
@Test
public void lambdaUpdate(){
boolean update = userService.lambdaUpdate().eq(User::getAge, 18).set(User::getAge, 31).update();
System.out.println(update);
}
/**
* lombda删除
*/
@Test
public void lambdaRemove(){
boolean remove = userService.lambdaUpdate().eq(User::getAge, 18).remove();
System.out.println(remove);
}
自定义方法
如果IService中通用的方法无法满足要求,就需要在service中定义方法,并在serviceimpl实现。
service中自定义方法
public interface UserService extends IService<User> {
public User userCheck();
}
service接口实现
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.simon.app.domain.OrdersVo;
import com.simon.app.domain.User;
import com.simon.app.mapper.OrdersMapper;
import com.simon.app.mapper.UserMapper;
import com.simon.app.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private OrdersMapper ordersMapper;
@Override
public User userCheck() {
UserMapper userMapper = getBaseMapper();
List<User> users = userMapper.selectList(null);
List<OrdersVo> allOrders = ordersMapper.findAllOrders();
return users.get(0);
}
}
有两点需要注意:
- 调用userMapper不需要通过@Autowired来声明userMapper,只需要通过getBaseMapper()方法即可得到userMapper
- 要使用其他mapper需要通过@Autowired来绑定。
代码生成器
引入包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
<scope>compile</scope>
</dependency>
生成器类
package com.simon.app.generator;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import lombok.Data;
import java.util.Collections;
/**
* 3.5.x 新版生成器 可连远程数据库 ,旧版远程报错
* new MyBatisGenerate.Builder()
* .setDbName("universal_portal")
* .setModule("")
* .setPrefix(new String[]{""})
* .setParentPackage("generate")
* .setDbHostAndPort("localhost:3306")
* .setDbUserName("root")
* .setDbPsw("123456")
* .setTables(new String[]{"user"})
* .build()
* .generate();
*
* @author bufei
* @email 。。。
* @date 2022/3/22 15:22
*/
@Data
public class MyBatisGenerate {
/**
* 数据库名称
*/
private String dbName;
/**
* 模块名称
*/
private String module;
/**
* 去除表前缀如t_ tb_
*/
private String[] prefix;
/**
* 父级包名称如appenv
*/
private String parentPackage;
/**
* 数据库host和端口
*/
private String dbHostAndPort;
/**
* 数据库用户名
*/
private String dbUserName;
/**
* 数据库密码
*/
private String dbPsw;
/**
* 表名称 ,string数组
*/
private String[] tables;
private MyBatisGenerate(String dbName, String module, String[] prefix, String parentPackage, String dbHostAndPort, String dbUserName, String dbPsw, String[] tables) {
this.dbName = dbName;
this.module = module;
this.prefix = prefix;
this.parentPackage = parentPackage;
this.dbHostAndPort = dbHostAndPort;
this.dbUserName = dbUserName;
this.dbPsw = dbPsw;
this.tables = tables;
}
/**
* 代码生成
*/
public void generate() {
// 数据源配置
String url = "jdbc:mysql://" + dbHostAndPort + "/" + dbName + "?characterEncoding=utf8&useSSL=true&serverTimezone=Hongkong&strictUpdates=false&autoReconnect=true";
DataSourceConfig dsb = new DataSourceConfig.Builder(url, dbUserName, dbPsw)
.dbQuery(new MySqlQuery())
// 库名
.schema(dbName)
.typeConvert(new MySqlTypeConvert())
.keyWordsHandler(new MySqlKeyWordsHandler()).build();
// 获取当前项目路径
String projectPath = System.getProperty("user.dir");
// 全局配置
GlobalConfig gc = new GlobalConfig.Builder()
// 输出目录
.outputDir(projectPath + "/src/main/java")
// 覆盖已生成文件
.fileOverride()
// 作者
.author("bufei")
// 启用swagger
.enableSwagger()
.dateType(DateType.TIME_PACK)
.commentDate("yyyy-MM-dd HH:mm:ss")
.build();
// 包配置
PackageConfig pc = new PackageConfig.Builder()
.parent(parentPackage)
// 设置父包模块名
.moduleName(module)
// 设置实体包
.entity("com.simon.app.model")
// 服务类
.service("com.simon.app.service")
// 服务类实现
.serviceImpl("com.simon.app.service.impl")
.mapper("com.simon.app.mapper")
.xml("mapper.xml")
.controller("com.simon.app.controller")
// 路径信息
.pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mybatis/mapper/"))
.build();
// 模板配置 不配无法生成
TemplateConfig tc = new TemplateConfig.Builder()
.disable(TemplateType.ENTITY)
.entity("/templates/entity.java")
.service("/templates/service.java")
.serviceImpl("/templates/serviceImpl.java")
.mapper("/templates/mapper.java")
.xml("/templates/mapper.xml")
.controller("/templates/controller.java")
.build();
// 注入配置
InjectionConfig ic = new InjectionConfig.Builder()
.beforeOutputFile((tableInfo, objectMap) -> {
System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
})
// 没有自定义配置map对象
// 没有模板文件
.build();
// 策略配置
StrategyConfig sc = new StrategyConfig.Builder()
// 策略 开启大写命名
.enableCapitalMode()
.enableSkipView()
// 禁用SQL过滤
.disableSqlFilter()
// 表名
.addInclude(tables)
// 要移除的表前缀
.addTablePrefix(prefix)
// 配置实体策略
.entityBuilder()
// 父类
.superClass(Model.class)
// 禁用序列化
.disableSerialVersionUID()
// 启用链式编程
.enableChainModel()
//启用Lombok
.enableLombok()
// 启用表字段注解
.enableTableFieldAnnotation()
// 乐观锁
.versionColumnName("version")
.versionPropertyName("version")
// 逻辑删除
.logicDeleteColumnName("del_flag")
.logicDeletePropertyName("delFlag")
// 表名驼峰
.naming(NamingStrategy.underline_to_camel)
// 列名驼峰命名
.columnNaming(NamingStrategy.underline_to_camel)
.idType(IdType.AUTO)
// 格式化文件名称
.formatFileName("%sModel")
// 配置controller 策略
.controllerBuilder()
// 设置父类,没有,不配
// .superClass(BaseController.class)
// RestController
.enableRestStyle()
.formatFileName("%sController")
// 配置serveice 策略
.serviceBuilder()
// BaseRepository impl
// .superServiceClass(BaseRepository.class)
// .superServiceImplClass(BaseRepositoryImpl.class)
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
// 配置mapper策略
.mapperBuilder()
// // 父类
// .superClass(SuperMapper.class)
// 启用mapper注解
.enableMapperAnnotation()
// 启用 BaseResultMap
.enableBaseResultMap()
.enableBaseColumnList()
.formatMapperFileName("%sMapper")
.formatXmlFileName("%sMapper")
.build();
// 执行生成
new AutoGenerator(dsb)
// 全局配置
.global(gc)
.packageInfo(pc)
.injection(ic)
.strategy(sc)
.template(tc)
// 默认VelocityTemplateEngine引擎,改为freemark引擎
.execute(new FreemarkerTemplateEngine());
}
public static class Builder {
public Builder() {
}
private String dbName;
private String module;
private String[] prefix;
private String parentPackage;
private String dbHostAndPort;
private String dbUserName;
private String dbPsw;
private String[] tables;
/**
* 设置数据库名称
*
* @param dbName 数据库名称
* @return
*/
public Builder setDbName(String dbName) {
this.dbName = dbName;
return this;
}
/**
* 设置模块名称
*
* @param module 模块名称如 app-env
* @return
*/
public Builder setModule(String module) {
this.module = module;
return this;
}
/**
* 设置要去除的表前缀
*
* @param prefix 要去除的表前缀 如t_;tbl_
* @return
*/
public Builder setPrefix(String[] prefix) {
this.prefix = prefix;
return this;
}
/**
* 设置父级包名称
*
* @param parentPackage 父级包名称 如 appenv
* @return
*/
public Builder setParentPackage(String parentPackage) {
this.parentPackage = parentPackage;
return this;
}
/**
* 设置数据库host:port
*
* @param dbHostAndPort 数据库host:port
* @return
*/
public Builder setDbHostAndPort(String dbHostAndPort) {
this.dbHostAndPort = dbHostAndPort;
return this;
}
/**
* 设置数据库用户名
*
* @param dbUserName 数据库用户名
* @return
*/
public Builder setDbUserName(String dbUserName) {
this.dbUserName = dbUserName;
return this;
}
/**
* 设置数据库密码
*
* @param dbPsw 数据库密码
* @return
*/
public Builder setDbPsw(String dbPsw) {
this.dbPsw = dbPsw;
return this;
}
/**
* 设置表名称
*
* @param tables 数据库表名称数组
* @return
*/
public Builder setTables(String[] tables) {
this.tables = tables;
return this;
}
public MyBatisGenerate build() {
return new MyBatisGenerate(dbName, module, prefix, parentPackage, dbHostAndPort, dbUserName, dbPsw, tables);
}
}
}
执行生成器类
public class Test {
public static void main(String[] args) {
new MyBatisGenerate.Builder()
.setDbName("mybatis")
.setModule("")//没有分模块
.setPrefix(new String[]{""})//没有需要移除的前缀
.setParentPackage("generate")//当前项目的包名
.setDbHostAndPort("localhost:3306")
.setDbUserName("root")
.setDbPsw("root")
.setTables(new String[]{"orders","user"})
.build()
.generate();
}
}
自动填充
为pojo添加注解 @TableField
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
实现接口 MetaObjectHandler
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);
//MP添加时执行
@Override
public void insertFill(MetaObject metaObject) {
LOGGER.info("start insert fill ....");
//根据名称设置属性值
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//MP修改时执行
@Override
public void updateFill(MetaObject metaObject) {
LOGGER.info("start update fill ....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
测试
新增
@Test
public void testInsertByHandler(){
Orders order=new Orders();
order.setId(7L);
order.setPrice(188);
order.setRemark("新疆");
order.setUserId(1);
ordersMapper.insert(order);
}
修改
@Test
public void testUpdateByHandler(){
LambdaUpdateWrapper<Orders> wrapper=new LambdaUpdateWrapper<Orders>();
wrapper.set(Orders::getRemark,"贵州");
wrapper.eq(Orders::getId,7L);
ordersMapper.update(new Orders(),wrapper);
}
- update(T t,Wrapper updateWrapper)时t不能为空,否则自动填充失效
逻辑删除
什么是逻辑删除
逻辑删除是名义上的删除,就是对要删除的数据打上一个删除标记,在逻辑上数据是被删除的,但数据本身依然存在,可通过修改删除标记来恢复数据。
特别说明
只对自动注入的 sql 起效,自己在mapper.xml中写的sql不生效:
插入: 不作限制
查找: 追加 where 条件过滤掉已删除数据
更新: 追加 where 条件防止更新到已删除数据
删除: 转变为更新
yml配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: delFlag # 全局逻辑删除的实体字段名,在mybatisplus3.3.0之前还必须在实体类字段上加上@TableLogic注解
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
测试
@Test
public void testDelflag(){
LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Orders::getId,7L);
ordersMapper.delete(wrapper);
//ordersMapper.deleteById(7L);
}
事务
https://www.cnblogs.com/konglxblog/p/16456782.html
-
在
springboot
中使用事务就很简单了,首先引入依赖spring-tx
,但是mybatis-plus
的依赖中已经引入,因此又少了一步 -
开启事务,在
Springboot
的启动类,或者某个@Configuration
的类上加上@EnableTransactionManagement
开启事务。因为这是数据库相关,所以我加在了mybatis-plus
的配置类上@Configuration @EnableTransactionManagement @MapperScan("com.simon.app.mapper") public class MyBatisPlusConfig { }
-
只要在需要使用事务的方法上加上
@Transactional
就可以开启事务了,当然也可以加到service类上。
注意点:
-
@Transactional
默认回滚的是RuntimeException
也就是说如果抛出的不是RuntimeException
的异常,数据库是不会回滚的。但是所幸的是,在spring框架下,所有的异常都被org.springframework
重写为RuntimeException
,因此不需要太担心@Transactional public void buy() throws Exception { 1. 扣钱 throw new 非RuntimeException异常("发生异常"); 2. 扣库存 } // 有一种处理方法是指定回滚的异常 @Transactional(rollbackFor = Exception.class) public void buy() throws Exception { 1. 扣钱 throw new 非RuntimeException异常("发生异常"); 2. 扣库存 }
-
如果在异常发生时,程序员自己手动捕获处理了,异常也不会回滚
@Transactional public void buy() throws Exception { try{ 1. 扣钱 } catch (Exception e) { catch了自己处理,也就是异常被自己吞了,外层并不知道,此时也不会回滚 } 3. 扣库存 }
其他
假如在查询的时候不想查询该字段,可以在字段上加上 @TableField(select = false)注解