本文会介绍一下springboot与mybatis、mybatisplus如何进行整合,文章篇幅会有点长
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
我们把Mybatis的功能架构分为三层:
API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
优点:
缺点:
1、pom.xml引入jar
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2、编辑application.yml
spring:
datasource:
name: druidDataSource
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot-learning?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
username: root
password: config.file=classpath:druid.properties
filters: stat,log4j,config
max-active: 100
initial-size: 1
max-wait: 60000
min-idle: 1
db-type: mysql
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 50
max-pool-prepared-statement-per-connection-size: 20
connection-properties: config.file=classpath:druid.properties # 启用加密,配置公钥。
filter:
config:
enabled: true
#mybaits
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.github.lybgeek.orm.mybatis.model
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、集成代码生成器
通过mybatis-generator-maven-plugin和generatorConfig.xml配合自动生成model、dao、mapper.xml模板代码
a、在pom.xml引入mybatis-generator-maven-plugin插件
<build>
<plugins>
<!-- mybaitis 自动生成代码配置 mybatis-generator:generate -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<executions>
<execution>
<id>Generate MyBatis Files</id>
<goals>
<goal>generate</goal>
</goals>
<phase>generate</phase>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
b、在classpath下引入generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--<properties resource="jdbc.properties" />-->
<properties url="file:///F:/jdbc.properties" />
<context id="mysqlTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}" />
<!-- 指定生成的类型为java类型,避免数据库中number等类型字段 -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 自动生成的实体的存放包路径 -->
<javaModelGenerator targetPackage="com.github.lybgeek.orm.mybatis.model"
targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--自动生成的*Mapper.xml文件存放路径 -->
<sqlMapGenerator targetPackage="mapper/bookorderitem"
targetProject="src/main/resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--自动生成的*Mapper.java存放路径 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.github.lybgeek.orm.mybatis.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<table tableName="book_order_item" domainObjectName="BookOrderItem"
enableCountByExample="true" enableUpdateByExample="true"
enableDeleteByExample="true" enableSelectByExample="true"
selectByExampleQueryId="true">
<generatedKey column="id" sqlStatement="mysql" identity="true" />
</table>
</context>
</generatorConfiguration>
4、在启动类上加上@MapperScan注解
@SpringBootApplication
@MapperScan(basePackages = {"com.github.lybgeek.orm.mybatis.dao"})
public class OrmApplication {
public static void main( String[] args ) {
SpringApplication.run(OrmApplication.class,args);
}
}
1、pom引入
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
2、分页代码例子
@Override
public PageResult<BookOrderDTO> pageBookOrder(PageQuery<BookOrderDTO> pageQuery) {
Integer pageNo = ObjectUtils.isEmpty(pageQuery.getPageNo()) ? 1 : pageQuery.getPageNo();
Integer pageSize = ObjectUtils.isEmpty(pageQuery.getPageSize()) ? 5 : pageQuery.getPageSize();
BookOrderDTO bookOrderDTO = pageQuery.getQueryParams();
Page<BookOrder> page = PageHelper.startPage(pageNo,pageSize);
PageHelper.orderBy("bo.create_date DESC");
List<BookOrderDTO> list = listBookOrders(bookOrderDTO);
return PageUtil.INSTANCE.getPage(page,list);
}
以自动生成数据库创建时间和更新时间为例
1、编写自定义注解
Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
@Documented
public @interface CreateDate {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
@Documented
public @interface UpdateDate {
String value() default "";
}
2、编写拦截器
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
Object.class})})
public class DateTimeInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation)
throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
// 获取 SQL
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
// 获取参数
Object parameter = invocation.getArgs()[1];
// 获取私有成员变量
Field[] declaredFields = parameter.getClass().getDeclaredFields();
// Class parentClz = parameter.getClass().getSuperclass();
//
// if(parentClz.newInstance() instanceof BaseEntity){
// declaredFields = parentClz.getDeclaredFields();
// }
for (Field field : declaredFields) {
if (field.getAnnotation(CreateDate.class) != null) {
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
// insert语句插入createDate
field.setAccessible(true);
field.set(parameter, new Date());
}
} else if (field.getAnnotation(UpdateDate.class) != null) {
if (SqlCommandType.INSERT.equals(sqlCommandType)
|| SqlCommandType.UPDATE.equals(sqlCommandType)) {
// insert 或update语句插入updateDate
field.setAccessible(true);
field.set(parameter, new Date());
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
3、配置拦截器
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.addInterceptor(dateTimeInterceptor());
}
@Bean
public DateTimeInterceptor dateTimeInterceptor() {
return new DateTimeInterceptor();
}
4、在需要填充字段上,加上指定注解
@CreateDate
private Date createDate;
@UpdateDate
private Date updateDate;
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
1、pom引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2、编辑application.yml
spring:
datasource:
name: druidDataSource
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot-learning?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
username: root
password: config.file=classpath:druid.properties
filters: stat,log4j,config
max-active: 100
initial-size: 1
max-wait: 60000
min-idle: 1
db-type: mysql
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 50
max-pool-prepared-statement-per-connection-size: 20
connection-properties: config.file=classpath:druid.properties # 启用加密,配置公钥。
filter:
config:
enabled: true
mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.github.lybgeek.orm.mybatisplus.model
global-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: 0
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: 1
#驼峰下划线转换
db-column-underline: true
#刷新mapper 调试神器
refresh-mapper: true
#数据库大写下划线转换
#capital-mode: true
# Sequence序列接口实现类配置
#key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
#逻辑删除配置
logic-delete-value: -1
logic-not-delete-value: 0
#自定义填充策略接口实现
#meta-object-handler: com.baomidou.springboot.xxx
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、集成代码生成器
a、pom.xml引入
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
b、代码生成器核心代码
// 执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
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) throws Exception{
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String basePath = CodeGenerator.class.getResource("").getPath();
String projectPath = basePath.substring(0, basePath.indexOf("/target"));
// String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("lyb-geek");
gc.setOpen(false);
gc.setBaseColumnList(true);
gc.setBaseResultMap(true);
gc.setServiceName("%sService");
// gc.setSwagger2(true);// 实体属性 Swagger2 注解
gc.setDateType(DateType.ONLY_DATE);
mpg.setGlobalConfig(gc);
String url = YmlUtil.getValue("spring.datasource.druid.url").toString();
String username = YmlUtil.getValue("spring.datasource.druid.username").toString();
String pwd = PropertiesUtil.INSTANCE.getProperty("password");
String publicKey = PropertiesUtil.INSTANCE.getProperty("config.decrypt.key");
String password = ConfigTools.decrypt(publicKey,pwd);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(url);
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername(username);
dsc.setPassword(password);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.github.lybgeek.orm");
pc.setEntity("model");
pc.setMapper("dao");
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/mapperPlus/" + pc.getModuleName()
// + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
// }
// });
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/mybatisplus/" + tableInfo.getEntityName().toLowerCase()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录");
return false;
}
});
*/
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("com.github.lybgeek.orm.common.model.BaseEntity");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// strategy.setSuperControllerClass("com.github.lybgeek.orm.controller.BaseController");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setSuperEntityColumns("id","create_date","update_date");
strategy.setControllerMappingHyphenStyle(true);
// strategy.setTablePrefix(pc.getModuleName() + "_");
//移除表的前缀
// strategy.setTablePrefix("t_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
4、与mybatis一样,在启动类上加上@MapperScan注解
本来想分为两篇分别介绍mybatis和mybatis-plus,但后边觉得mybatis-plus官网的例子已经很详尽了,就没必要多花篇幅介绍,在这边安利一下mybatis-plus,它确实是一个很强大而且易用的orm框架,而且是国人开发的,比较了解国人开发的一些痛点,而且集成了分布式事务,但是暂时支持rabbit实现可靠消息分布式事务3.1.1 以上版本,不过这个方案是否能使用在生产线上,有待验证。其官网链接如下
https://mp.baomidou.com/
https://www.w3cschool.cn/mybatis/ https://mp.baomidou.com/
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-orm