SpringBoot + Vue 后台管理系统(五):mybat
什么是MyBatis-Plus?
翻译过来就是“加强的mybatis”;封装了各种方法,形成了类似于JPA的使用方式。有兴趣的朋友参考文档:MyBatis-Plus
SpringBoot集合方式
1.添加以下依赖(注:包含MyBatis的依赖)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.0</version>
</dependency>
本文使用的是druid + mysql 的多数据源;所以在pom文件导入依赖
<!-- 数据库关联 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
自动配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
配置文件
spring:
profiles:
active: dev
datasource:
url: jdbc:mysql://lcoalhost:3306/db_comm_01?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 12345678
type: com.alibaba.druid.pool.DruidDataSource
member:
datasource:
url: jdbc:mysql://lcoalhost:3306/db_member_01?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 12345678
type: com.alibaba.druid.pool.DruidDataSource
oauth:
datasource:
url: jdbc:mysql://lcoalhost:3306/oauth2?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 12345678
type: com.alibaba.druid.pool.DruidDataSource
redis:
database: 0
host: lcoalhost
port: 6379
password: 12345678
2.配置
数据源DataSourceConfig.java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
DataSource dsComm() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.member.datasource")
DataSource dsMember() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.oauth.datasource")
DataSource dsOauth() {
return DruidDataSourceBuilder.create().build();
}
}
MyBatis-Plus配置MyBatisPlusConfig.java
@Configuration
public class MybatisPlusConfig {
/** mybatis-plus分页插件<br> */
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置数据库方言
paginationInterceptor.setDialectType(DbType.MYSQL.getDb());
return paginationInterceptor;
}
}
多数据源分开配置SqlSessionFactory等Bean
//只要拷贝多个这个文件即可处理多数据源的问题,根据不同的数据源创建相应的包分开放Entity,Mapper,Repository等类即可。
@Configuration
@MapperScan(basePackages = "bertram.wang.domain.mapper.comm",
sqlSessionFactoryRef = "sqlSessionFactoryComm",
sqlSessionTemplateRef = "sqlSessionTemplateComm")
public class MyBatisConfigCommTest {
@Resource(name = "dsComm")
DataSource dsComm;
//配置事务管理器
@Primary
@Bean(name = "dsCommTransaction")
PlatformTransactionManager dsMemberTransaction() {
return new DataSourceTransactionManager(dsComm);
}
@Bean
SqlSessionFactory sqlSessionFactoryComm() {
SqlSessionFactory sessionFactory = null;
try {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dsComm);
sqlSessionFactory.setTypeAliasesPackage("bertram.wang.domain.entity.comm");
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/comm/*Mapper.xml"));
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
sqlSessionFactory.setConfiguration(configuration);
sessionFactory = sqlSessionFactory.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return sessionFactory;
}
@Bean
SqlSessionTemplate sqlSessionTemplateComm() {
return new SqlSessionTemplate(sqlSessionFactoryComm());
}
}
文档结构示例
3.使用
实体示例: User extends BaseEntity (主动填充后面会介绍)
@Data
@Accessors(chain = true)
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键标识,自动增长
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 创建日期,添加时自动填充当前日期
*/
@TableField(fill = FieldFill.INSERT)
private Date createDate;
/**
* 修改日期,添加和修改自动填充当前日期
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date modifyDate;
}
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_user")
public class User extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* *角色ID数组
*/
private transient List<Integer> roleIds;
/**
* *昵称,限制16字符
*/
private String name;
/**
* *用户密码(MD5加密)
*/
private String password;
}
Mapper示例: 没有自实现的方法
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
Repository以其实现示例
public interface UserRepository extends IService<User> {
}
@Repository
public class UserRepositoryImpl extends ServiceImpl<UserMapper, User> implements UserRepository {
}
测试单元
// Select
@Test
public void () throws Exception {
User user = userRepository.getById(1);
log.info("users:{}", page.getRecords());
}
执行日志
执行的SQL很简单: select * from user where id = 1;(忽略通配符)
再看上面的logo。和springboot一样自带logo牛逼哄哄的样子。springboot打印logo是可以关闭:app.setBannerMode(Banner.Mode.OFF);
以上是用了mybatis-plus默认配置。
mybatis-plus配置字段及意义
mybatis-plus:
config-location: xxxxxxx # MyBatis 配置文件位置 ---String 默认:null
mapper-locations: # MyBatis Mapper 所对应的 XML 文件位置 ---String[] 默认: []
- classpath*:/mapper/comm
- classpath*:/mapper/member
type-aliases-package: bertram.wang.domain.entity # 实体包 --- String
type-aliases-super-type: bertram.wang.domain.entity.BaseEntity # 实体的父类类名 Class<?>
type-handlers-package: xxxxxxxx # SqlSessionFactoryBean 会把该包下面的类注册为对应的 TypeHandler ---String 默认:null
typeEnumsPackage: xxxxx # 让实体类字段能够简单快捷的使用枚举属性 ---String 默认:null
check-config-location: false # 检查mybatis xml 文件的存在
executor-type: simple # 知道mybatis的执行器
# configuration-properties: # 指定外部化 MyBatis Properties 配置,通过该配置可以抽离配置,实现不同环境的配置部署
configuration: # 本部分(Configuration)的配置大都为 MyBatis 原生支持的配置
map-underscore-to-camel-case: true # 是否开启自动驼峰命名规则(camel case)映射
default-enum-type-handler: org.apache.ibatis.type.EnumTypeHandler
aggressive-lazy-loading: true #当设置为 true 的时候,懒加载的对象可能被任何懒属性全部加载,否则,每个属性都按需加载。需要和 lazyLoadingEnabled 一起使用
auto-mapping-behavior: partial # 自动映射策略
auto-mapping-unknown-column-behavior: none # 自动映射遇到未知列时的处理策略
cache-enabled: true # 映射器缓存开启
call-setters-on-nulls: false # 空值的列
configuration-factory: xxxxxxx # 指定一个提供 Configuration 实例的工厂类 (从 3.2.3 版本开始)
global-config:
banner: true # 控制台 print mybatis-plus 的 LOGO
sql-parser-cache: true # 开启缓存
worker-id: 1234312 # ID的部分值
datacenter-id: 1313 # 数据标识ID部分
super-mapper-class: com.baomidou.mybatisplus.core.mapper.Mapper.class # 通用Mapper父类
db-config:
db-type: mysql # 数据库类型
id-type: auto # id策略
table-prefix: t_ # 表前缀
table-underline: true # 表明下划线命名
column-like: false # 是否开启 LIKE 查询,即根据 entity 自动生成的 where 条件中 String 类型字段 是否使用 LIKE,默认不开启
capital-mode: false # 不开启大写命名
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 #逻辑未删除值
添加以下配置到配置文件:
mybatis-plus:
global-config:
banner: false # 控制台 print mybatis-plus 的 LOGO
sql-parser-cache: true # 开启缓存
db-config:
db-type: mysql # 数据库类型
id-type: auto # id策略
table-underline: true # 表明下划线命名
***执行发现并没有生效???????
image.png没生效,那就自己注册一个Bean呗! MyBatisPlusConfig.java添加Bean
// 和上面配置文件同样的属性
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setBanner(false);
globalConfig.setSqlParserCache(true);
DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setDbType(DbType.MYSQL);
dbConfig.setIdType(IdType.AUTO);
dbConfig.setTableUnderline(true);
return globalConfig;
}
MyBatisConfigComm.java 中使用
@Autowired
GlobalConfig globalConfig;
// 在SqlSessionFactory Bean生成时添加以下代码。
sqlSessionFactory.setGlobalConfig(globalConfig);
执行生效
没有打印logo说明注入的Bean生效了。
如果就这样结束了那就不怎么坑了。在项目中insert, insertBatch操作!
Insert插入一条数据
公用字段创建时间和修改时间其实使用的都是当前时间。如果能自动填充方便一些。强大的mybatis-plus提供了自动填充功能。具体参考:自动填充功能
根据官方说的创建MyMetaObjectHandler,实体有加注解。
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);
@Override
public void insertFill(MetaObject metaObject) {
LOGGER.info("start insert fill ....");
this.setInsertFieldValByName("createDate", new Date(), metaObject);
this.setInsertFieldValByName("modifyDate", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
LOGGER.info("start update fill ....");
this.setUpdateFieldValByName("modifyDate", new Date(), metaObject);
}
}
执行单元测试
@Test
public void test2() {
log.info("==============测试开始==================");
User user = new User();
user.setName("bertram.wang");
user.setPassword("password_bertram.wang");
userRepository.save(user);
log.info("==============测试结束==================");
}
结果很明显并没有用
在看配置的时候就发现GlobalConfig下有个 MetaObjectHandler属性,只是告诉我们说注入Bean即可。既然没用那就set进去就好了
globalConfig.setMetaObjectHandler(myMetaObjectHandler());
成功生效
看到这里应该万事大吉了。
InsertBatch 批量插入
@Test
public void test3() {
log.info("==============测试开始==================");
List<User> users = new ArrayList<>();
for(int i=0; i<3; i++) {
User user = new User();
user.setName("name_"+i);
user.setPassword("password_"+i);
users.add(user);
}
userRepository.saveBatch(users);
log.info("==============测试结束==================");
}
执行异常
org.apache.ibatis.exceptions.PersistenceException: ...Mapped Statements collection does not contain value for bertram.wang.domain.mapper.comm.UserMapper.insert????
异常一直没有找到处理的方式。 求大神指教!!!! 换了一个方式处理。
自动配置不会存在这个异常
很好。把刚才一系列的操作删除换回原始的自动配置的GlobalConfig
发现现在确实没有抛出以上异常
异常虽然没有了又回到怎么设置自动填充的问题了?
数据库设置成默认当前时间。每次修改都设置一下修改时间。这样可以解决。(不建议)
处理方案
找到当前的自动配置GlobalConfig信息,然后再手动set进去。
MyBatisConfigComm.java 方法 sqlSessionFactoryComm 添加一下代码:
// 获得前配置的全局变量修改
GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(configuration);
globalConfig.setBanner(false);
globalConfig.setMetaObjectHandler(myMetaObjectHandler);
globalConfig.setSqlInjector(logicSqlInjector);
globalConfig.getDbConfig().setDbType(DbType.MYSQL);
globalConfig.getDbConfig().setIdType(IdType.AUTO);
globalConfig.getDbConfig().setColumnLike(true);
sqlSessionFactory.setGlobalConfig(globalConfig);
最后的 MyBatisConfigComm.java完成示例:
@Configuration
@MapperScan(basePackages = "bertram.wang.domain.mapper.comm", sqlSessionFactoryRef = "sqlSessionFactoryComm", sqlSessionTemplateRef = "sqlSessionTemplateComm")
public class MyBatisConfigComm {
@Autowired
MyMetaObjectHandler myMetaObjectHandler;
@Autowired
LogicSqlInjector logicSqlInjector;
@Resource(name = "dsComm")
DataSource dsComm;
//配置事务管理器
@Primary
@Bean(name = "dsCommTransaction")
PlatformTransactionManager dsMemberTransaction() {
return new DataSourceTransactionManager(dsComm);
}
@Bean
SqlSessionFactory sqlSessionFactoryComm() {
SqlSessionFactory sessionFactory = null;
try {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dsComm);
sqlSessionFactory.setTypeAliasesPackage("bertram.wang.domain.entity.comm");
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/comm/*Mapper.xml"));
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
sqlSessionFactory.setConfiguration(configuration);
// 获得前配置的全局变量修改
GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(configuration);
globalConfig.setBanner(false);
globalConfig.setMetaObjectHandler(myMetaObjectHandler);
globalConfig.setSqlInjector(logicSqlInjector);
globalConfig.getDbConfig().setDbType(DbType.MYSQL);
globalConfig.getDbConfig().setIdType(IdType.AUTO);
globalConfig.getDbConfig().setColumnLike(true);
sqlSessionFactory.setGlobalConfig(globalConfig);
sessionFactory = sqlSessionFactory.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return sessionFactory;
}
@Bean
SqlSessionTemplate sqlSessionTemplateComm() {
return new SqlSessionTemplate(sqlSessionFactoryComm());
}
}
替换前面的这个文件即可。
执行成功