自动完成简单crud,进行简化操作
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, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
导入需要的依赖(建议mybatis和mybatis-plus不要一起使用,可能有版本冲突)
mysql
mysql-connector-java
5.1.47
org.projectlombok
lombok
true
com.baomidou
mybatis-plus-boot-starter
3.0.5
连接数据库
spring.datasource.url=jdbc:mysql://localhost:3366/mybatis_plus
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private int age;
private String email;
}
创建Mapper,自动生成了简单的crud操作
//注入到容器中
@Repository
public interface userMapper extends BaseMapper {
}
在测试类中测试
@Autowired
private userMapper userMapper;
@Test
void contextLoads() {
List userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
#配置日志 默认自带日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@Test
public void test(){
User user = new User();
user.setName("小米");
user.setAge(3);
user.setEmail("2621");
userMapper.insert(user);
}
没有设置,会有默认的全局唯一id,即在id属性上加
public class User {
//@TableId("IdType.ID_WORKER") //默认通过雪花算法设置全局唯一的id
private Long id;
private String name;
private int age;
private String email;
}
分布式系统唯一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。可以保证几乎全球唯一!
@Test
public void UpdateTest(){
User user = new User();
user.setId(6L);
user.setName("小米2");
user.setAge(4);
user.setEmail("26213025");
userMapper.updateById(user);
}
通过updateById方法修改内容,传递的参数是user对象,会根据设置的值,动态创建修改语句,就如不设置Email,修改时就不会修改Email
概述,在开发中类似时间的的操作,如某事件创建或者修改的时间需要保存下来,手动去设置比较麻烦,mybatis-plus提供了自动填充的功能
首选在数据库创建字段 create_time 和 update_time
在实体类中写入,并标记填充字段
public class User {
// @TableId("IdType.ID_WORKER") //默认通过雪花算法设置全局唯一的id
private Long id;
private String name;
private int age;
private String email;
// 注意!这里需要标记为填充字段
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
标记字段的解释
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
填充的方式
MyBatis-Plus的版本3.3.0之下的是如下操作
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
MyBatis-Plus的版本3.3.0及以上
官网连接https://mp.baomidou.com/guide/auto-fill-metainfo.html(中国人写的,通俗易懂)
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
// 或者
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
// 或者
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
}
之后进行插入或者修改操作时,会自动填充好相应字段。
乐观锁:顾名思义就是十分乐观,总是认为不会出现问题,做什么事务都不上锁,如果出现了问题,再次尝试更新值测试
悲观锁:顾名思义十分悲观,总是认为会出问题,做什么都加上锁,再去操作
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁的实现方式:
取出记录时,获取版本号
更新时,带上这个版本号
执行更新时,set version = new version where version = oldversion
如果version不对,就更新失败
实现方式
user类添加字段
@Version //乐观锁version注解
private Integer version;
配置类
@MapperScan("com.mapper")
@EnableTransactionManagement //自动配置事务
@Configuration
public class MybatisPlusConfig {
/**
* 旧版
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
/**
* 新版
*/
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// return mybatisPlusInterceptor;
// }
}
测试,在更新操作中sql语句中version会加一,在版本号还是查询时版本号时,及数据没有被其他人修改过
//测试乐观锁
@Test
public void testOptimisticLocker(){
User user = userMapper.selectById(1l);
user.setName("xiaoming");
user.setAge(16);
userMapper.updateById(user);
}
//测试乐观锁
@Test
public void testOptimisticLocker2(){
//模拟并发,测试乐观锁
User user = userMapper.selectById(1l);
user.setName("xiaoming1");
user.setAge(16);
//第二者插入
User user2 = userMapper.selectById(1l);
user2.setName("xiaoming2");
user2.setAge(16);
//修改成功
userMapper.updateById(user2);
//修改失败
userMapper.updateById(user);
}
//查询操作
@Test
public void selectTest(){
//查询全部
// userMapper.selectList(null);
//通过id查询一个
// userMapper.selectById();
//通过id查询多个
userMapper.selectBatchIds(Arrays.asList(1l,2l));
//条件查询 在查询时将map中的值作为条件
HashMap map = new HashMap<>();
map.put("name","Sandy");
map.put("age",21);
List userList = userMapper.selectByMap(map);
for (User user : userList) {
System.out.println(user);
}
}
配置分页插件 MybatisPlusConfig中
// 旧版 分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
// 最新版 分页
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
// return interceptor;
// }
//测试分页
@Test
public void PaginationTest(){
//参数一 当前页 参数二 页面大小 根据sql可以看出也是通过limit实现
// SELECT id,name,age,email,version,create_time,update_time FROM user LIMIT 0,5
Page page = new Page<>(1,5);
IPage userIPage = userMapper.selectPage(page, null);
long pages = userIPage.getPages();
System.out.println("总页数"+pages);
List records = userIPage.getRecords();
for (User user : records) {
System.out.println(user);
}
}
方法与查询类似
//测试删除
@Test
public void DeleteTest(){
//传入list集合批量删除
// userMapper.deleteBatchIds(Arrays.asList(1l,2l));
//通过id删除
// userMapper.deleteById(3l);
//通过map传入条件删除
HashMap map = new HashMap<>();
map.put("name","小米2");
userMapper.deleteByMap(map);
}
物理删除:从数据库中删除
逻辑删除:在数据库中没有删除,而是通过一个变量让他失效
首选在数据库中添加字段deleted并设置默认为0
注意不要将字段名设置成delete,这将在sql语句中当成关键字导致sql出错
在实体类中添加字段和注解
@TableLogic //逻辑删除
private Integer deleted;
配置
#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
添加组件
3.3版本以上不需要此组件,只需要上面两个步骤
// 逻辑删除组件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
测试 看出实际走的是update操作
userMapper.deleteById(5L);
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
==> Parameters: 5(Long)
<== Updates: 1
通过wrapper,设置需要的条件,与map类似,区别是wrapper是链式书写,内置许多条件方法
@SpringBootTest
public class WrapperTest {
@Autowired
private userMapper userMapper;
@Test
public void test1(){
//通过wrapper设置条件,编写单表的带条件sql
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.ge("age",10);
userMapper.selectList(wrapper);
}
@Test
public void test2(){
//通过wrapper设置条件,编写单表的带条件sql
QueryWrapper wrapper = new QueryWrapper<>();
//==> Preparing: SELECT id,name,age,email,version,deleted,create_time,update_time FROM user WHERE deleted=0 AND name = ? AND age >= ?
//==> Parameters: xiaoming2(String), 10(Integer)
wrapper.eq("name","xiaoming2")
.ge("age",10);
userMapper.selectOne(wrapper); //查询一个
}
@Test
public void test3(){
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.between("age",10,20);
userMapper.selectCount(wrapper);
}
@Test
public void test4(){
QueryWrapper wrapper = new QueryWrapper<>();
//==> Preparing: SELECT id,name,age,email,version,deleted,create_time,update_time FROM user WHERE deleted=0 AND name NOT LIKE ? AND email LIKE ?
//==> Parameters: %2%(String), 26%(String)
wrapper.notLike("name","2")
.likeRight("email",26); //like的右边,即以26开始
List
导入依赖
mysql
mysql-connector-java
5.1.47
com.baomidou
mybatis-plus-boot-starter
3.0.5
org.apache.velocity
velocity-engine-core
2.0
io.springfox
springfox-swagger2
3.0.0
io.springfox
springfox-swagger-ui
3.0.0
org.projectlombok
lombok
true
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
public class KuangCode {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("smile");
gc.setOpen(false);
gc.setFileOverride(false); // 是否覆盖
gc.setServiceName("%sService"); // 去Service的I前缀
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3366/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("blog"); //模板名
pc.setParent("com");
pc.setEntity("pojo");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user"); // 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtModified = new TableFill("update_time", FieldFill.INSERT_UPDATE);
ArrayList tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true); //localhost:8080/hello_id_2
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}