Mybatis-plus的使用和学习
推荐官网学习https://baomidou.com/guide/
1、首先准备数据
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)
);
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
2、新建springboot项目,添加依赖
<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>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
3、添加配置
spring.datasource.url=jdbc:mysql://localhost:3306/mytest?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=MyNewPass4!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
4、启动类添加扫描注解
@SpringBootApplication
@MapperScan("com.zhu.one.mapper")
public class OneApplication {
public static void main(String[] args) {
SpringApplication.run(OneApplication.class, args);
}
}
5、添加实体类和mapper接口
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
public interface UserMapper extends BaseMapper<User> {
}
6、添加测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
}
7、输出结果
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
简单搭建成功
配置日志
开启sql日志打印
添加配置
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
JDBC Connection [HikariProxyConnection@1442768482 wrapping com.mysql.cj.jdbc.ConnectionImpl@54089484] will not be managed by Spring
==> Preparing: SELECT id,name,age,email FROM user
==> Parameters:
<== Columns: id, name, age, email
<== Row: 1, Jone, 18, test1@baomidou.com
<== Row: 2, Jack, 20, test2@baomidou.com
<== Row: 3, Tom, 28, test3@baomidou.com
<== Row: 4, Sandy, 21, test4@baomidou.com
<== Row: 5, Billie, 24, test5@baomidou.com
<== Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79e66b2f]
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
测试插入
@Test
void test1() {
System.out.println(("----- 测试插入 ------"));
User user =new User();
user.setAge(22);
user.setEmail("3526837@qq.com");
user.setName("xiaozhu");
userMapper.insert(user);
}
JDBC Connection [HikariProxyConnection@513241240 wrapping com.mysql.cj.jdbc.ConnectionImpl@630390b9] will not be managed by Spring
==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1324614255098048513(Long), xiaozhu(String), 22(Integer), 3526837@qq.com(String)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79e66b2f]
id–雪花算法
雪花算法是Twitter开源的分布式id的生成算法,会返回一个long型
具体生成如下
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
首位为无效位,不使用,接下来的41位为时间戳,在后5位是datacenterId,在后5位是workerId,最后12位是毫秒类的计数(差不多一毫秒可以生成4096个),加起来一共有64个,最后转化为长度为18的Long型
属性自动填充
以最常用的创建时间和更新时间为例,每次插入数据的时候,创建时间和更新时间字段会自动填充当前时间值,每次数据的时候,更新时间字段会自动更新为当前时间
只需要实现MetaObjectHandler 接口即可
@Slf4j
@Component
public class MyAutoFillFieldHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("插入数据时自动填充创建时间和更新时间");
this.strictInsertFill(metaObject,"createTime",Date.class,new Date());
this.strictInsertFill(metaObject,"updateTime",Date.class,new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("更新数据时自动填充创建时间和更新时间");
this.strictInsertFill(metaObject,"updateTime",Date.class,new Date());
}
}
然后在实体类上标记哈
@Data
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)//插入时自动填充
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//插入和更新时自动填充
private Date updateTime;
}
测试:插入
@Test
void test2() {
System.out.println(("----- 测试自动填充 ------"));
User user =new User();
user.setAge(22);
user.setEmail("3526837@qq.com");
user.setName("xiaozhu");
userMapper.insert(user);
}
JDBC Connection [HikariProxyConnection@565627330 wrapping com.mysql.cj.jdbc.ConnectionImpl@309cedb6] will not be managed by Spring
==> Preparing: INSERT INTO user ( id, name, age, email, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ? ) ##在这里就已经把时间拿过来了,我们自己是没有设置值的
==> Parameters: 1324632793531674626(Long), xiaozhu(String), 22(Integer), 3526837@qq.com(String), 2020-11-06 16:40:43.125(Timestamp), 2020-11-06 16:40:43.127(Timestamp)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@489091bd]
最终数据自动填充上了
测试:更新
@Test
void test3() {
System.out.println(("----- 测试自动填充 ------"));
List<User> userList = userMapper.selectList(null);
for (User user : userList) {
userMapper.updateById(user);
}
}
乐观锁
乐观锁:觉得什么都是好的,不会加锁,通过version判断
悲观锁:觉得什么都是不好的,干什么都会加锁
乐观锁:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion(这一步必须为原子操作)
- 如果version不对,就更新失败
数据库加上一个version字段
对应的实体类也加上version属性
@Data
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@Version //加上version注解
private Long version;
}
加上OptimisticLockerInnerInterceptor拦截器,并且添加开启事务的注解
@SpringBootApplication
@EnableTransactionManagement //开启事务
@MapperScan("com.zhu.one.mapper")
public class OneApplication {
public static void main(String[] args) {
SpringApplication.run(OneApplication.class, args);
}
@Bean
public MybatisPlusInterceptor getOptimisticLockerInnerInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//将乐观锁的拦截器添加进去
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
测试
@Test
void test3() {
System.out.println(("----- 测试乐观锁 ------"));
//按照程序的逻辑最好age应该被更改为122,但是如果乐观锁生效的话应该是22,最好一个update会更新不成功
User user= userMapper.selectById(1L);
user.setAge(122);
User user1= userMapper.selectById(1L);
user1.setAge(22);
userMapper.updateById(user1);
userMapper.updateById(user);
}
测试结果
最后age结果为22,说明乐观锁生效
分页测试
@Test
void test5() {
System.out.println(("----- 测试分页查询 ------"));
Page page = new Page(2,3);
userMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
}
User(id=4, name=Sandy, age=21, email=test4@baomidou.com, createTime=null, updateTime=Fri Nov 06 16:44:45 CST 2020, version=1)
User(id=5, name=Billie, age=24, email=test5@baomidou.com, createTime=null, updateTime=Fri Nov 06 16:44:45 CST 2020, version=1)
User(id=1324614255098048513, name=xiaozhu, age=22, email=3526837@qq.com, createTime=null, updateTime=Fri Nov 06 16:44:45 CST 2020, version=1)
逻辑删除
数据库添加字段deleted,默认为0,表示未删除,1表示已删除
实体类添加对应字段并且添加注解
@Data
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@Version
private Long version;
@TableLogic
private Integer deleted;
}
@Test
void test6() {
System.out.println(("----- 测试逻辑删除 ------"));
userMapper.deleteById(1324632793531674626L);
}
JDBC Connection [HikariProxyConnection@1729045606 wrapping com.mysql.cj.jdbc.ConnectionImpl@6e03db1f] will not be managed by Spring
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 1324632793531674626(Long)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5f2bd6d9]
虽然是删除,却走的是更新操作,逻辑删除的好处就是数据其实没有被删除,后天数据库还是有的,只是前段通过字段控制显示了
代码生成器
导入依赖
<!--末班引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<!--代码生成依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
public class Code {
public static void main(String[] args) {
AutoGenerator autoGenerator = new AutoGenerator();
//全局配置
GlobalConfig globalConfig=new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/one/src/main/java");
globalConfig.setAuthor("xiaozhu");
globalConfig.setOpen(false);
globalConfig.setFileOverride(false);
globalConfig.setServiceName("%sService");
autoGenerator.setGlobalConfig(globalConfig);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/nacos_config?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("xxxxx");
dsc.setDbType(DbType.MYSQL);
autoGenerator.setDataSource(dsc);
//包的配置
PackageConfig packageConfig=new PackageConfig();
packageConfig.setModuleName("one");
packageConfig.setParent("com.zhu");
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setService("serviec");
packageConfig.setController("controller");
autoGenerator.setPackageInfo(packageConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
TableFill createTime=new TableFill("createTime",FieldFill.INSERT);
TableFill updateTime=new TableFill("updateTime",FieldFill.INSERT);
List list=new ArrayList();
list.add(createTime);
list.add(createTime);
strategy.setTableFillList(list);
autoGenerator.setStrategy(strategy);
autoGenerator.execute();
}
}