一、配置日志
mybatis-plus :
configuration :
log-impl : org.apache.ibatis.logging.stdout.StdOutImpl
二、CRUD
Mapper
Service
1、插入操作
Mapper
Insert 插入
int insert ( T entity) ;
Service
Save
boolean save ( T entity) ;
boolean saveBatch ( Collection< T> entityList) ;
boolean saveBatch ( Collection< T> entityList, int batchSize) ;
测试:
@Test
public void test2 ( ) {
User user = new User ( ) ;
user. setName ( "latteit" ) ;
user. setAge ( 10 ) ;
user. setEmail ( "xxx@qq.com" ) ;
int insert = usermapper. insert ( user) ;
System. out. println ( insert) ;
System. out. println ( user) ;
}
数据库插入的id的默认值为:全局的唯一id
主键生成策略
默认 ID_WORKER 全局唯一id
雪花算法: snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为 毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味 着每个节点在每毫秒可以产生 4096 个 ID),后还有一个符号位,永远是0。可以保证几乎全球唯 一!
主键自增
我们需要配置主键自增:
1、实体类字段上 @TableId(type = IdType.AUTO)
2、数据库字段一定要是自增!
public enum IdType {
AUTO ( 0 ) ,
NONE ( 1 ) ,
INPUT ( 2 ) ,
ID_WORKER ( 3 ) ,
UUID ( 4 ) ,
ID_WORKER_STR ( 5 ) ;
}
2、更新操作
Mapper
update
int update ( @Param ( Constants. ENTITY) T entity, @Param ( Constants. WRAPPER) Wrapper< T> updateWrapper) ;
int updateById ( @Param ( Constants. ENTITY) T entity) ;
Service
Update
boolean update ( Wrapper< T> updateWrapper) ;
boolean update ( T entity, Wrapper< T> updateWrapper) ;
boolean updateById ( T entity) ;
boolean updateBatchById ( Collection< T> entityList) ;
boolean updateBatchById ( Collection< T> entityList, int batchSize) ;
SaveOrUpdate 修改插入
boolean saveOrUpdate ( T entity) ;
boolean saveOrUpdate ( T entity, Wrapper< T> updateWrapper) ;
boolean saveOrUpdateBatch ( Collection< T> entityList) ;
boolean saveOrUpdateBatch ( Collection< T> entityList, int batchSize) ;
测试:
@Test
public void test4 ( ) {
User user = new User ( ) ;
user. setAge ( 6 ) ;
user. setEmail ( "asghagsghas@com" ) ;
user. setName ( "jack" ) ;
user. setId ( 1 L) ;
int i = usermapper. updateById ( user) ;
usermapper. update ( user, null) ;
System. out. println ( i) ;
}
自动填充
创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新! 阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需 要自动化!
方式一:数据库级别
在表中新增字段 create_time 、update_time(默认CURRENT_TIMESIAMP)
再次测试插入方法,我们需要先把实体类同步!
private Date updateTime;
private Date createTime;
插入就行
方式二:代码级别
1、删除数据库的默认值、更新操作!
2、实体类字段属性上需要增加注解
@TableField ( fill = FieldFill. INSERT_UPDATE)
private Date updateTime;
@TableField ( fill = FieldFill. INSERT)
private Date createTime;
3、编写处理器来处理这个注解即可
@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) ;
}
}
4、测试插入
5、测试更新、观察时间即可!
乐观锁
乐观锁:顾名思义十分乐观,它总是被认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再次更新测试
悲观锁:顾名思义十分悲观,它总是出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式
取出记录是,获取当前version 更新时,带上这个version 执行更新事,set version=newVersion where version =oldVersion 如果version不对,就更新失败
乐观锁: 1 、先查询,获得版本号 version= 1
-- A
update user set name = "shuishui" , version = version+ 1
where id = 2 and version= 1
-- B 如果线程抢先完成,这个时候version= 2 ,会导致A修改失败
update user set name = "shuishui" , version = version+ 1
where id = 2 and version= 1
测试乐观锁 1、表中创建乐观锁字段version 默认值为1 2、我们实体类加对应的字段
@Version
private Integer version;
3、注册组件 注意:3.4.0开始插件的配置方式改变了,3.4.0之前的版本
@MapperScan ( "com.latte.mapper" )
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor ( ) {
return new OptimisticLockerInterceptor ( ) ;
}
}
3.4.0之后的版本
@Configuration
@MapperScan ( "com.latte.mapper" )
@EnableTransactionManagement
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor ( ) {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor ( ) ;
mybatisPlusInterceptor. addInnerInterceptor ( new OptimisticLockerInnerInterceptor ( ) ) ;
return mybatisPlusInterceptor;
}
}
4、测试一下!
@Test
public void testOptimisticLocker ( ) {
User user = usermapper. selectById ( 1 L) ;
user. setName ( "latte" ) ;
user. setEmail ( "xxx@qq.com" ) ;
usermapper. updateById ( user) ;
}
@Test
public void testOptimisticLocker2 ( ) {
User user = usermapper. selectById ( 1 L) ;
user. setName ( "latte" ) ;
user. setEmail ( "xxx@qq.com" ) ;
User user2 = usermapper. selectById ( 1 L) ;
user2. setName ( "latte2" ) ;
user2. setEmail ( "xxx@qq.com" ) ;
usermapper. updateById ( user2) ;
usermapper. updateById ( user) ;
}
说明:
支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime 整数类型下 newVersion = oldVersion + 1 newVersion 会回写到 entity 中 仅支持 updateById(id) 与 update(entity, wrapper) 方法 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
3、查询操作
Mapper
select
T selectById ( Serializable id) ;
T selectOne ( @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
List< T> selectBatchIds ( @Param ( Constants. COLLECTION) Collection< ? extends Serializable > idList) ;
List< T> selectList ( @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
List< T> selectByMap ( @Param ( Constants. COLUMN_MAP) Map< String, Object> columnMap) ;
List< Map< String, Object> > selectMaps ( @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
List< Object> selectObjs ( @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
IPage< T> selectPage ( IPage< T> page, @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
IPage< Map< String, Object> > selectMapsPage ( IPage< T> page, @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
Integer selectCount ( @Param ( Constants. WRAPPER) Wrapper< T> queryWrapper) ;
Service
Get 查询单条记录
T getById ( Serializable id) ;
T getOne ( Wrapper< T> queryWrapper) ;
T getOne ( Wrapper< T> queryWrapper, boolean throwEx) ;
Map< String, Object> getMap ( Wrapper< T> queryWrapper) ;
< V> V getObj ( Wrapper< T> queryWrapper, Function< ? super Object, V> mapper) ;
List 查询多条记录
List< T> list ( ) ;
List< T> list ( Wrapper< T> queryWrapper) ;
Collection< T> listByIds ( Collection< ? extends Serializable > idList) ;
Collection< T> listByMap ( Map< String, Object> columnMap) ;
List< Map< String, Object> > listMaps ( ) ;
List< Map< String, Object> > listMaps ( Wrapper< T> queryWrapper) ;
List< Object> listObjs ( ) ;
< V> List< V> listObjs ( Function< ? super Object, V> mapper) ;
List< Object> listObjs ( Wrapper< T> queryWrapper) ;
< V> List< V> listObjs ( Wrapper< T> queryWrapper, Function< ? super Object, V> mapper) ;
Page 分页查
IPage< T> page ( IPage< T> page) ;
IPage< T> page ( IPage< T> page, Wrapper< T> queryWrapper) ;
IPage< Map< String, Object> > pageMaps ( IPage< T> page) ;
IPage< Map< String, Object> > pageMaps ( IPage< T> page, Wrapper< T> queryWrapper) ;
Count
int count ( ) ;
int count ( Wrapper< T> queryWrapper) ;
Chain
query
QueryChainWrapper< T> query ( ) ;
LambdaQueryChainWrapper< T> lambdaQuery ( ) ;
query ( ) . eq ( "column" , value) . one ( ) ;
lambdaQuery ( ) . eq ( Entity: : getId, value) . list ( ) ;
update
UpdateChainWrapper< T> update ( ) ;
LambdaUpdateChainWrapper< T> lambdaUpdate ( ) ;
update ( ) . eq ( "column" , value) . remove ( ) ;
lambdaUpdate ( ) . eq ( Entity: : getId, value) . update ( entity) ;
测试:
@Test
public void testSelectById ( ) {
User user = usermapper. selectById ( 1368490321062813699 L) ;
System. out. println ( user) ;
}
@Test
public void testSelectByBatchId ( ) {
List< User> users = usermapper. selectBatchIds ( Arrays. asList ( 1 , 2 , 3 ) ) ;
for ( User user : users) {
System. out. println ( user) ;
}
}
@Test
public void testSelectByBatchIds ( ) {
HashMap< String, Object> map = new HashMap < > ( ) ;
map. put ( "name" , "jack" ) ;
map. put ( "age" , 6 ) ;
List< User> users = usermapper. selectByMap ( map) ;
for ( User user : users) {
System. out. println ( user) ;
}
}
分页查询
分页在网站使用的十分多
1、原始的limit进行分页
2、pageHelper 第三方插件
3、Mybatis-Plus中也内置了分页插件!
支持的数据库
mysql 、mariadb 、oracle 、db2 、h2 、hsql 、sqlite 、postgresql 、sqlserver 、presto 、Gauss 、Firebird Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库
自定义的 mapper#method 使用分页
IPage< UserVo> selectPageVo ( IPage< ? > page, Integer state) ;
MyPage selectPageVo ( MyPage page) ;
List< UserVo> selectPageVo ( IPage< UserVo> page, Integer state) ;
< select id = " selectPageVo" resultType = " xxx.xxx.xxx.UserVo" >
SELECT id,name FROM user WHERE state=#{state}
</ select>
如果返回类型是 IPage 则入参的 IPage 不能为null,因为 返回的IPage == 入参的IPage 如果返回类型是 List 则入参的 IPage 可以为 null(为 null 则不分页),但需要你手动 入参的IPage.setRecords(返回的 List); 如果 xml 需要从 page 里取值,需要 page.属性 获取
其他:
生成 countSql 会在 left join 的表不参与 where 条件的情况下,把 left join 优化掉 所以建议任何带有 left join 的sql,都写标准sql既给于表一个别名,字段也要 别名.字段
如何使用
1、配置拦截器组件即可
3.4.0以前
@Bean
public PaginationInterceptor paginationInterceptor ( ) {
return new PaginationInterceptor ( ) ;
}
3.4.0以后
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor ( ) {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor ( ) ;
mybatisPlusInterceptor. addInnerInterceptor ( new PaginationInnerInterceptor ( DbType. MYSQL) ) ;
mybatisPlusInterceptor. addInnerInterceptor ( new OptimisticLockerInnerInterceptor ( ) ) ;
return mybatisPlusInterceptor;
}
2、直接使用Page对象即可!
@Test
public void testPage ( ) {
Page< User> page = new Page < > ( 1 , 2 ) ;
usermapper. selectPage ( page, null) ;
page. getRecords ( ) . forEach ( System. out: : println) ;
System. out. println ( page. getTotal ( ) ) ;
}
4、删除操作
Mapper
delete
int delete ( @Param ( Constants. WRAPPER) Wrapper< T> wrapper) ;
int deleteBatchIds ( @Param ( Constants. COLLECTION) Collection< ? extends Serializable > idList) ;
int deleteById ( Serializable id) ;
int deleteByMap ( @Param ( Constants. COLUMN_MAP) Map< String, Object> columnMap) ;
Service
Remove
boolean remove ( Wrapper< T> queryWrapper) ;
boolean removeById ( Serializable id) ;
boolean removeByMap ( Map< String, Object> columnMap) ;
boolean removeByIds ( Collection< ? extends Serializable > idList) ;
测试:
1、根据 id 删除记录
@Test
public void testDeleteById ( ) {
usermapper. deleteById ( 1368490321062813699 L) ;
}
@Test
public void testDeleteBatchId ( ) {
usermapper. deleteBatchIds ( Arrays. asList ( 2 , 3 , 4 ) ) ;
}
@Test
public void testDeleteMap ( ) {
HashMap< String, Object> map = new HashMap < > ( ) ;
map. put ( "name" , "jom" ) ;
usermapper. deleteByMap ( map) ;
}
逻辑删除
物理删除 :从数据库中直接移出
逻辑删除:在数据库中没有被移出,而是通过一个变量来让他失效!deleted=0 ==>deleted =1(失效)
管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!
测试一下:
1、在数据表中增加一个 deleted 字段
2、实体类中增加属性
@TableLogic
private Integer deleted;
注册 Bean(3.1.1开始不再需要这一步):
@Bean
public ISqlInjector sqlInjector ( ) {
return new LogicSqlInjector ( ) ;
}
配置
mybatis-plus :
global-config :
db-config :
logic-delete-field : flag
logic-delete-value : 1
logic-not-delete-value : 0
测试一下删除! 走的是更新,不是删除了,记录依旧在数据库,但是值确已经变化了!
查询的时候也会自动过滤,就查询不到之前逻辑删除的值了