SpringBoot使用Mybatis-Plus及多数据源、代码生成
【摘要】
SpringBoot使用Mybatis-Plus及多数据源、代码生成
一、优点
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为...
SpringBoot使用Mybatis-Plus及多数据源、代码生成
一、优点
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
二、支持数据库
mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver
三、SpringBoot使用Mybatis-Plus
1. pom
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
加入lomok方便写bean
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
2. application.properties
server.port=8080
#mysql
spring.datasource.url=jdbc:mysql://192.168.0.106:3306/db1?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type =com.alibaba.druid.pool.DruidDataSource
#mybatis-plus
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus.mapper-locations=classpath:mapper/xml/*.xml
mybatis-plus.type-aliases-package=com.bxc.eurekaprovide.Entity
mybatis-plus.configuration.map-underscore-to-camel-case=true
yml形式配置:
spring:
datasource:
url: jdbc:mysql://192.168.0.106:3306/db1?useUnicode=true&characterEncoding=utf8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
mybatis-plus:
mapper-locations: classpath:mapper/xml/*.xml
type-aliases-package: com.bxc.eurekaprovide.Entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
3. 配置分页
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInterceptor.setLimit(20);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
4. 实体类
@Data
@TableName("user")
public class UserEntity {
// @TableId(value = "id",type = IdType.AUTO)
@TableId(value = "id",type = IdType.ASSIGN_ID)
private Long id;
private String username;
private String passwd;
@TableLogic
private boolean deleted = false;
}
5. Mapper
@Mapper
@Component
public interface UserMapper extends BaseMapper<UserEntity> {
}
6. 添加数据
@GetMapping("/AddUser")
public String AddUser(){
UserEntity entity = new UserEntity();
entity.setUsername("admin");
entity.setPasswd("123");
return userMapper.insert(entity) > 0 ? "success":"err";
}
7.查询数据
-
根据id查询
@GetMapping("/FindUserById/{id}") public Object FindUserById(@PathVariable("id")Long id){ return userMapper.selectById(id); }
-
分页查询
@GetMapping("/FindUser") public Object FindUser(){ Page page = new Page(); page.setSize(20); page.setCurrent(1); QueryWrapper<UserEntity> userEntityQueryWrapper = new QueryWrapper<>(); Page<UserEntity> pageResult = userMapper.selectPage(page, userEntityQueryWrapper); return pageResult.getRecords(); }
-
等于查询
QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<UserEntity>(); queryWrapper .eq(!StringUtils.isEmpty(username), "username", username) .or() .eq(!StringUtils.isEmpty(username), "username", username); List<UserEntity> list = userMapper.selectList(queryWrapper);
-
模糊查询
- like %**%
queryWrapper.like(!StringUtils.isEmpty(username), "username", username);
- likeLeft %**
queryWrapper.likeLeft(!StringUtils.isEmpty(username), "username", username);
- likeRight **%
queryWrapper.likeRight(!StringUtils.isEmpty(username), "username", username);
-
大于
queryWrapper.ge(id!=null,"id", id);
-
大于等于
queryWrapper.gt(id!=null,"id", id);
-
between
queryWrapper.between(id1 != null & id2 != null, "id", id1, id2);
-
In
queryWrapper.in(!StringUtils.isEmpty(ids), "id", !StringUtils.isEmpty(ids) ? ids.split(",") : null);
-
排序
queryWrapper.orderByDesc("id"); //降序 queryWrapper.orderByAsc("id"); //升序
-
查询字段为null的
queryWrapper.isNull("name");
8.更改数据
-
根据id修改
UserEntity entity = new UserEntity(); entity.setId(1l); entity.setUsername("ll"); int count = userMapper.updateById(entity);
-
根据条件修改
UpdateWrapper<UserEntity> updateWrapper = new UpdateWrapper<>(); Long id = entity.getId(); if (id != null) { updateWrapper.eq("id", id); } userMapper.update(entity, updateWrapper);
9.逻辑删除
@GetMapping("/DeleteUser/{id}")
public String DeleteUser(@PathVariable("id")Long id){
return userMapper.deleteById(id) > 0 ? "success" : "fail";
}
10.使用雪花算法更改ID自增模式
- SnowflakeIdUtils
@Component
public class SnowflakeIdUtils {
// ==============================Fields===========================================
/**
* 开始时间截 (2015-01-01)
*/
private final long twepoch = 1420041600000L;
/**
* 机器id所占的位数
*/
private final long workerIdBits = 5L;
/**
* 数据标识id所占的位数
*/
private final long datacenterIdBits = 5L;
/**
* 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
*/
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/**
* 支持的最大数据标识id,结果是31
*/
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/**
* 序列在id中占的位数
*/
private final long sequenceBits = 12L;
/**
* 机器ID向左移12位
*/
private final long workerIdShift = sequenceBits;
/**
* 数据标识id向左移17位(12+5)
*/
private final long datacenterIdShift = sequenceBits + workerIdBits;
/**
* 时间截向左移22位(5+5+12)
*/
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/**
* 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
*/
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 工作机器ID(0~31)
*/
private long workerId;
/**
* 数据中心ID(0~31)
*/
private long datacenterId;
/**
* 毫秒内序列(0~4095)
*/
private long sequence = 0L;
/**
* 上次生成ID的时间截
*/
private long lastTimestamp = -1L;
//==============================Constructors=====================================
public SnowflakeIdUtils() {
this.workerId = 3;
this.datacenterId = 1;
}
/**
* 构造函数
*
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdUtils(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
*
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
*
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
}
- CustomIdGenerator
@Component
public class CustomIdGenerator implements IdentifierGenerator {
@Autowired
private SnowflakeIdUtils snowflakeIdUtils;
@Override
public Long nextId(Object entity) {
//可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成.
String bizKey = entity.getClass().getName();
//根据bizKey调用分布式ID生成
//返回生成的id值即可.
return snowflakeIdUtils.nextId();
}
}
四、SpringBoot Mybatis-Plus 配置多数据源
1. POM
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
2. application.properties
server.port=8087
#设置默认的数据源或者数据源组,默认值即为master
spring.datasource.dynamic.primary = testdb
#设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
spring.datasource.dynamic.strict = false
spring.datasource.dynamic.datasource.testdb.url =jdbc:mysql://192.168.2.122:3306/testdb?useUnicode=true&characterEncoding=utf8
spring.datasource.dynamic.datasource.testdb.username =root
spring.datasource.dynamic.datasource.testdb.password =root
spring.datasource.dynamic.datasource.testdb.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.testdb2.url =jdbc:mysql://192.168.2.122:3306/testdb2?useUnicode=true&characterEncoding=utf8
spring.datasource.dynamic.datasource.testdb2.username =root
spring.datasource.dynamic.datasource.testdb2.password =root
spring.datasource.dynamic.datasource.testdb2.driver-class-name=com.mysql.jdbc.Driver
logging.level.com.bxc.mybitisplus3_muldb = debug
3. TestDbUserMapper
@Mapper
@Component
@DS("testdb")
public interface TestDbUserMapper extends BaseMapper<UserEntity> {
}
4. TestDb2UserMapper
@Mapper
@Component
@DS("testdb2")
public interface TestDb2UserMapper extends BaseMapper<UserEntity> {
}
五、自动生成代码
1. POM
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
2. CodeGenerator
public class CodeGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
final String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("jobob");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://192.168.2.122:3306/testdb?useUnicode=true&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
final PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.bxc.mybatisplus3_gen");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
// strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
文章来源: blog.csdn.net,作者:小毕超,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_43692950/article/details/107449265
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)