mybatisplus 和 springboot 的集成
导入依赖
<!--spring-boot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
配置文件
## web ##
server:
servlet:
context-path: /
port: 80
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.100.66:3306/hl?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Hongkong&useSSL=false&allowPublicKeyRetrieval=true
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
mapper-locations: mapper/*.xml #定义xml文件的位置
type-aliases-package: com.lomi.entity #定义实体文件的包
dao从层
public interface GoodsMapper extends BaseMapper<Goods> {
}
GoodsService层
public interface GoodsService extends IService<Goods> {
void add(Goods goods);
}
GoodsServiceImpl
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
@Resource
GoodsExMapper goodsExMapper;
@Override
@Transactional
public void add(Goods goods) {
getBaseMapper().insert(goods);
}
}
/**
* 定义dao文件的的包
*/
@MapperScan("com.lomi.mapper")
@SpringBootApplication
public class MybatisplusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisplusApplication.class, args);
}
}
GoodsMapper.xml可以不存在
用法和建议
mybatisPlus对dao层和Service都有一些默认封装,可以选择只用dao层,也可以选择dao和service层一起使用。
service的批量操作效率比拼装 foreach方式更高
mybatisPlus对dao层的封装
增删改查,分页,列表,查询数量,查询是否存在等接口
@Override
public void t1() {
LambdaQueryWrapper<Goods> qw = Wrappers.lambdaQuery();
Goods goods = Goods.randomGoods();
Page page = new Page(1,4);
//查询
goodsExMapper.selectById(1668801996867579904L);
//多个会抛出异常
try{
goodsExMapper.selectOne(qw);
}catch (Exception e){
log.warn("不止一个");
}
boolean exists = goodsExMapper.exists(qw);
log.warn("是否存在{}", exists );
Long count = goodsExMapper.selectCount(qw);
log.warn("数量{}", count );
List<Goods> list = goodsExMapper.selectList(qw);
log.warn("不分页结果{}", JSONUtil.toJsonStr( list ));
IPage selectPage = goodsExMapper.selectPage(page, qw);
log.warn("分页结果{}", JSONUtil.toJsonStr( selectPage ));
//添加
goodsExMapper.insert(goods);
//更新
goodsExMapper.updateById( goods );
log.warn("完成更新");
//批量
//批量查询(用的in,真批量,建议使用)
List<Goods> list1 = goodsExMapper.selectBatchIds(Arrays.asList(1668805297105350656L, 1668805300435628032L));
log.warn("批量查询{}",list1);
//批量删除(用的in,真批量,建议使用)
int i = goodsExMapper.deleteBatchIds(Arrays.asList(1668805297105350656L, 1668805300435628032L));
log.warn("批量删除{}",i);
//删除
goodsExMapper.deleteById(1L);
log.warn("删除Id是1的数据");
//条件删除
//goodsExMapper.delete(qw);
}
mybatisPlus对service的封装
对比dao层的封装,提供里更多批量接口,提供了saveOrUpdate之类的接口,后面会体现提供的批量接口效率都很高
@Override
public void t1() {
t2();
add();
get();
up();
delete();
batch();
}
@Override
@Transactional
public void batchAdd(List<Goods> list) {
saveBatch(list);
}
/**
* 获取当前的mapper
*/
private void t2() {
GoodsMapper goodsMapper = getBaseMapper();
log.debug( "goodsMapper:" + goodsMapper );
}
/**
* 添加
*/
private void add() {
add( Goods.randomGoods() );
save(Goods.randomGoods());
}
/**
* 查询
*/
private void get() {
//用过Id查询
Goods goods = getById(id);
LambdaQueryWrapper<Goods> qw = Wrappers.lambdaQuery();
qw.gt( Goods::getId,1L);
//查询单个,多个会抛出异常
//getOne(qw);
//查询单个不抛出异常,得到第一个
Goods one = getOne(qw, false);
log.debug( "查询单个:" + one );
//获取任意对象
HashMap<String, Object> obj = (HashMap<String, Object>) getObj(qw, item -> {
//item.get
return BeanUtil.beanToMap( item );
});
log.debug( "查询对象封装:" + obj );
//查询数量
count();
long count = count(qw);
log.debug( "查询数量:" + count );
//不分页查询列表
list();
list(qw);
//分页查询1
Page page = new Page(1,10);
IPage pageList1 = page(page, qw);
log.debug( "分页查询1:" + pageList1 );
//分页查询2
List<Goods> pageList2 = goodsExMapper.pageList(page);
log.debug( "分页查询2:" + pageList2.getClass() );
}
Long id = 1668822727982657536L;
/**
* 修改
*/
private void up() {
Goods goods = getById(id);
goods.setName("改");
//添加或者更新
saveOrUpdate(goods);
//通过Id更新
updateById( goods );
//查询条件更新
LambdaUpdateWrapper<Goods> uw = Wrappers.lambdaUpdate(Goods.randomGoods());
uw.eq( Goods::getId,1L);
uw.set(Goods::getName,"uw名字");
update(uw);
//查询条件更新2
LambdaQueryWrapper<Goods> qw = Wrappers.lambdaQuery();
qw.eq( Goods::getId,1L);
update(goods,qw);
}
/**
* 删除
*/
private void delete() {
removeById(1L);
}
/**
* 批量接口
*/
private void batch() {
//批量查询(这个用的底层的in批量查询)
listByIds(Arrays.asList( 1L ) );
//批量插入(1000条数据时,约比sql上拼装foreach块60倍)
saveBatch(Arrays.asList( Goods.randomGoods(),Goods.randomGoods() ));
log.warn("批量插入----------------");
//批量添加或者更新
saveOrUpdateBatch(Arrays.asList( Goods.randomGoods(),Goods.randomGoods() ));
log.warn("批量插入或者更新----------------");
//批量删除
removeByIds( Arrays.asList( 1L,2L ) );
log.warn("批量删除----------------");
//批量更新
updateBatchById( Arrays.asList( Goods.randomGoods(),Goods.randomGoods() ) );
log.warn("批量更新----------------");
updateBatchById( Arrays.asList( Goods.randomGoods(),Goods.randomGoods() ),1000 );
log.warn("批量更新2----------------");
}
mybatisplus不同版本的分页
不同版本启用分页插件
/**
* mybatisPlus 3.5以后 用这种用法
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
/*
*
* mybatis 3.3-3.4 这样用
*
* */
/* @Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setDbType(DbType.MYSQL);
return paginationInterceptor;
}*/
/*
*
* mybatis 3.2以前使用这种用法
*
* */
/*@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor().setDialectType(DbType.MYSQL.getDb());
}*/
使用分页的常见两种方式
//直接使用mybatisplus的selectPage接口
Page page = new Page(1,4);
IPage selectPage = goodsExMapper.selectPage(page, qw);
log.warn("分页结果{},{}", JSONUtil.toJsonStr( selectPage ),page.getTotal());
//请求参数中带有Page对象就会分页
Page page2 = new Page(1,4);
List<Goods> list2 = goodsExMapper.pageList(page2);
log.warn("分页结果2{},{}", JSONUtil.toJsonStr( list2 ),page2.getTotal());
批量service层批量接口和在sql上拼接foreach效率差异
结论service层批量插入约是sql上凭借foreach的60倍
foreach方式
<insert id="addBatch">
insert into goods (id,
name,
stock,
des,
des2,
data,
create_date)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.id,jdbcType=BIGINT},
#{item.name,jdbcType=VARCHAR},
#{item.stock,jdbcType=INTEGER},
#{item.des,jdbcType=VARCHAR},
#{item.des2,jdbcType=VARCHAR},
#{item.data,jdbcType=LONGVARCHAR},
#{item.createDate,jdbcType=TIMESTAMP})
</foreach>
</insert>
@Override
@Transactional
public void batchAdd(List<Goods> list) {
goodsExMapper.addBatch(list);
}
使用mybatisplus service封装的方式
@Override
@Transactional
public void batchAdd(List<Goods> list) {
saveBatch(list);
}
记录运行时间的测试代码
/**
* 批量
* @return
* @throws Exception
*/
@RequestMapping(value="t3", method= {RequestMethod.GET})
public String t3() throws Exception{
List<Goods> list1 = new ArrayList<>();
List<Goods> list2 = new ArrayList<>();
Stream.generate(Goods::randomGoods ).limit(1000).forEach( item-> list1.add( item ) );
Stream.generate(Goods::randomGoods ).limit(1000).forEach( item-> list2.add( item ) );
Long time1 = System.currentTimeMillis();
//foreach方式
iGoodsService.batchAdd(list1);
Long time2 = System.currentTimeMillis();
//mybatisplus封装的批量插入
goodsService.batchAdd(list2);
Long time3 = System.currentTimeMillis();
log.warn("dao层子写批量:{}", time2-time1);
log.warn("mybatisplus——service封装的批量:{}",time3-time2 );
return "OK";
}
三次运行的结果分别是
2023-06-14 14:28:23.992 WARN 17156 --- [p-nio-80-exec-2] c.lomi.controller.MyBatisPlusController : dao层子写批量:13187
2023-06-14 14:28:23.993 WARN 17156 --- [p-nio-80-exec-2] c.lomi.controller.MyBatisPlusController : mybatisplus——service封装的批量:211
2023-06-14 14:29:00.470 WARN 17156 --- [p-nio-80-exec-9] c.lomi.controller.MyBatisPlusController : dao层子写批量:12562
2023-06-14 14:29:00.470 WARN 17156 --- [p-nio-80-exec-9] c.lomi.controller.MyBatisPlusController : mybatisplus——service封装的批量:183
2023-06-14 14:29:25.417 WARN 17156 --- [p-nio-80-exec-5] c.lomi.controller.MyBatisPlusController : dao层子写批量:13079
2023-06-14 14:29:25.417 WARN 17156 --- [p-nio-80-exec-5] c.lomi.controller.MyBatisPlusController : mybatisplus——service封装的批量:168
mybatisplus乐观锁
/**
* mybatisPlus 3.5以后 用这种用法
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//乐观锁插件
interceptor.addInnerInterceptor( new OptimisticLockerInnerInterceptor());
return interceptor;
}
在实体上标记version
@Version
private Integer version;
然后再更新的时候就会带上 version的条件,如果version是null,那么乐观锁不会生效
@Override
public void updatebyVersion() {
Goods goods = getById(1668873830610841600L);
goods.setName("改1");
log.warn("打印1,{},{}",goods.getVersion(),goods.getName());
boolean rt1 = updateById( goods );
log.warn("打印2,{},{}",goods.getVersion(),goods.getName());
log.warn("更新结果{}",rt1);
goods.setName("改2");
log.warn("打印3,{},{}",goods.getVersion(),goods.getName());
boolean rt2 = updateById(goods);
log.warn("打印4,{},{}",goods.getVersion(),goods.getName());
log.warn("更新结果{}",rt2);
//删除的时候不会带上乐观锁
removeById(goods);
}
注解方式的sql
这不是mybatisplus的,是mybatis的语法,并且个人不推荐用注解形式的sql,xml 格式的sql 比 注解方式的sql 可读性搞很多,尽量写到xml里面去,对齐格式,方便阅读,个人建议优先使用 xml方式的sql,可以少量使用QueryWrapper,UpdateWrapper这种面向对象的方式,namedsql方式建议少使用
//使用#{}获取参数
@Select("select * from goods where id = #{id}")
Goods querById_nameSql(@Param("id") Long id);
@Update("update goods set name = #{param.name} where id = #{param.id}")
int update_namedsql(@Param("param") Goods param);
//参数有 Page对象就会分页
@Select("select * from goods")
List<Goods> queryPage_namedsql(@Param("name") String name,Page page);
/**
* ${ew.sqlSelect} :查询字段的部分的sql,来自接口 Query 的getSqlSelect方法,查询语句才能用
* ${ew.sqlSet} set 部分的sql ,来自接口 Update的getSqlSet方法
* ${ew.sqlSegment} where后面的 sql ,来自接口 ISqlSegment的getSqlSegment方法
* Constants.WRAPPER里面的参数都是可以通过 ${}方式取到
*/
@Update("update goods set ${ew.sqlSet} where ${ew.sqlSegment}")
int updateParam_namedsql(@Param(Constants.WRAPPER) Wrapper<Goods> wp, Page page);
mybatisQueryWrapper or方式的查询
/**
* 默认都说and
* 使用 and 或者 or 等于建立了一个子条件,同一层有多个条件会添加括号
*/
@Override
public void orQuery() {
//WHERE (name = ? OR name = ?)
LambdaQueryWrapper<Goods> query1 = Wrappers.lambdaQuery();
query1.eq( Goods::getName,"name1" );
LambdaQueryWrapper<Goods> query12 = query1.or();
query12.eq(Goods::getName,"name2");
List<Goods> list = list(query1);
// WHERE (name = ? AND (id = ? AND des = ? OR id = ? AND des = ?))
//外面的条件
LambdaQueryWrapper<Goods> query2 = Wrappers.lambdaQuery();
query2.eq( Goods::getName,"name1" );
LambdaQueryWrapper<Goods> and = query2.and(qw->{
//子条件1
qw.eq( Goods::getId,1 );
qw.eq( Goods::getDes,"des1" );
//子条件2
LambdaQueryWrapper<Goods> qwor = qw.or();
qwor.eq( Goods::getId,2 );
qwor.eq( Goods::getDes,"des2" );
});
List<Goods> list2 = list(query2);
// WHERE (name = ? AND ((id = ? AND des = ?) OR (id = ? AND des = ?)))
//外面的条件
LambdaQueryWrapper<Goods> query3 = Wrappers.lambdaQuery();
query3.eq( Goods::getName,"name1" );
LambdaQueryWrapper<Goods> and3 = query3.and(qw->{
//子条件1
qw.and(item->{
item.eq( Goods::getId,1 );
item.eq( Goods::getDes,"des1" );
});
//子条件2
LambdaQueryWrapper<Goods> qwor = qw.or();
qwor.or(item->{
item.eq( Goods::getId,2 );
item.eq( Goods::getDes,"des2" );
});
});
List<Goods> list3 = list(query3);
}
标签:总结,Goods,mybatisplus,log,qw,批量,warn,goods
From: https://www.cnblogs.com/cxygg/p/17481251.html