mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Insert 插入
// 插入一條記錄
int insert(T entity);
Save
// 插入一條記錄(選擇字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
測(cè)試:
@Test
public void test2(){
User user = new User();
user.setName("latteit");
user.setAge(10);
user.setEmail("xxx@qq.com");
int insert = usermapper.insert(user);// 幫我們自動(dòng)生成id
System.out.println(insert); // 受影響的行數(shù)
System.out.println(user); // 發(fā)現(xiàn),id會(huì)自動(dòng)回填
}
數(shù)據(jù)庫(kù)插入的id的默認(rèn)值為:全局的唯一id
主鍵生成策略
默認(rèn) ID_WORKER 全局唯一id
雪花算法:
snow?ake是Twitter開(kāi)源的分布式ID生成算法,結(jié)果是一個(gè)long型的ID。其核心思想是:使用41bit作為 毫秒數(shù),10bit作為機(jī)器的ID(5個(gè)bit是數(shù)據(jù)中心,5個(gè)bit的機(jī)器ID),12bit作為毫秒內(nèi)的流水號(hào)(意味 著每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生 4096 個(gè) ID),后還有一個(gè)符號(hào)位,永遠(yuǎn)是0??梢员WC幾乎全球唯 一!
主鍵自增
我們需要配置主鍵自增:
1、實(shí)體類(lèi)字段上 @TableId(type = IdType.AUTO)
2、數(shù)據(jù)庫(kù)字段一定要是自增!
public enum IdType {
AUTO(0), //數(shù)據(jù)可id自增
NONE(1), //未設(shè)置主鍵
INPUT(2), //手動(dòng)輸入
ID_WORKER(3), //默認(rèn)的全局唯一id
UUID(4), //全局唯一id uuid
ID_WORKER_STR(5); // ID_WORKEK 字符串表示法
}
update
// 根據(jù) whereEntity 條件,更新記錄
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根據(jù) ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
Update
// 根據(jù) UpdateWrapper 條件,更新記錄 需要設(shè)置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根據(jù) whereEntity 條件,更新記錄
boolean update(T entity, Wrapper<T> updateWrapper);
// 根據(jù) ID 選擇修改
boolean updateById(T entity);
// 根據(jù)ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根據(jù)ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
SaveOrUpdate 修改插入
// TableId 注解存在更新記錄,否插入一條記錄
boolean saveOrUpdate(T entity);
// 根據(jù)updateWrapper嘗試更新,否繼續(xù)執(zhí)行saveOrUpdate(T)方法
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();
// 通過(guò)條件自動(dòng)拼接動(dòng)態(tài)sql
user.setAge(6);
user.setEmail("asghagsghas@com");
user.setName("jack");
user.setId(1L);
// 注意:updateById 但是參數(shù)是一個(gè) 對(duì)象
//更新滿(mǎn)足條件的
int i = usermapper.updateById(user);
//更新全部
usermapper.update(user,null);
System.out.println(i);
}
自動(dòng)填充
創(chuàng)建時(shí)間、修改時(shí)間!這些個(gè)操作一遍都是自動(dòng)化完成的,我們不希望手動(dòng)更新!
阿里巴巴開(kāi)發(fā)手冊(cè):所有的數(shù)據(jù)庫(kù)表:gmt_create、gmt_modi?ed幾乎所有的表都要配置上!而且需 要自動(dòng)化!
方式一:數(shù)據(jù)庫(kù)級(jí)別
? 在表中新增字段 create_time 、update_time(默認(rèn)CURRENT_TIMESIAMP)
再次測(cè)試插入方法,我們需要先把實(shí)體類(lèi)同步!
private Date updateTime;
private Date createTime;
插入就行
方式二:代碼級(jí)別
1、刪除數(shù)據(jù)庫(kù)的默認(rèn)值、更新操作!
2、實(shí)體類(lèi)字段屬性上需要增加注解
@TableField(fill = FieldFill.INSERT_UPDATE)// 字段添加填充內(nèi)容
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
3、編寫(xiě)處理器來(lái)處理這個(gè)注解即可
@Slf4j
@Component // 一定不要忘記把處理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override// 插入時(shí)的填充策略
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override // 更新時(shí)的填充策略
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4、測(cè)試插入
5、測(cè)試更新、觀察時(shí)間即可!
樂(lè)觀鎖
樂(lè)觀鎖:顧名思義十分樂(lè)觀,它總是被認(rèn)為不會(huì)出現(xiàn)問(wèn)題,無(wú)論干什么都不去上鎖!如果出現(xiàn)了問(wèn)題,再次更新測(cè)試
悲觀鎖:顧名思義十分悲觀,它總是出現(xiàn)問(wèn)題,無(wú)論干什么都會(huì)上鎖!再去操作!
樂(lè)觀鎖實(shí)現(xiàn)方式
樂(lè)觀鎖: 1、先查詢(xún),獲得版本號(hào) version=1
--A
update user set name ="shuishui" ,version =version+1
where id =2 and version=1
--B 如果線(xiàn)程搶先完成,這個(gè)時(shí)候version=2,會(huì)導(dǎo)致A修改失敗
update user set name ="shuishui" ,version =version+1
where id =2 and version=1
測(cè)試樂(lè)觀鎖
1、表中創(chuàng)建樂(lè)觀鎖字段version 默認(rèn)值為1
@Version //樂(lè)觀鎖Version注解
private Integer version;
3、注冊(cè)組件
注意:3.4.0開(kāi)始插件的配置方式改變了,3.4.0之前的版本
// 掃描我們的 mapper 文件夾
@MapperScan("com.latte.mapper")
@EnableTransactionManagement
@Configuration // 配置類(lèi)
public class MyBatisPlusConfig {
// 注冊(cè)樂(lè)觀鎖插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
3.4.0之后的版本
@Configuration
@MapperScan("com.latte.mapper")
@EnableTransactionManagement
public class MybatisPlusConfig {
// 注冊(cè)樂(lè)觀鎖插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//樂(lè)觀鎖插件
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
4、測(cè)試一下!
// 測(cè)試樂(lè)觀鎖成功!
@Test
public void testOptimisticLocker(){
// 1、查詢(xún)用戶(hù)信息
User user = usermapper.selectById(1L);
// 2、修改用戶(hù)信息
user.setName("latte");
user.setEmail("xxx@qq.com");
// 3、執(zhí)行更新操作
usermapper.updateById(user);
}
// 測(cè)試樂(lè)觀鎖失敗!多線(xiàn)程下
@Test
public void testOptimisticLocker2(){
// 線(xiàn)程 1
User user = usermapper.selectById(1L);
user.setName("latte");
user.setEmail("xxx@qq.com");
// 模擬另外一個(gè)線(xiàn)程執(zhí)行了插隊(duì)操作
User user2 = usermapper.selectById(1L);
user2.setName("latte2");
user2.setEmail("xxx@qq.com");
usermapper.updateById(user2);
// 自旋鎖來(lái)多次嘗試提交!
usermapper.updateById(user); // 如果沒(méi)有樂(lè)觀鎖就會(huì)覆蓋插隊(duì)線(xiàn)程的值!
}
select
// 根據(jù) ID 查詢(xún)
T selectById(Serializable id);
// 根據(jù) entity 條件,查詢(xún)一條記錄
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查詢(xún)(根據(jù)ID 批量查詢(xún))
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根據(jù) entity 條件,查詢(xún)?nèi)坑涗?/span>
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查詢(xún)(根據(jù) columnMap 條件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根據(jù) Wrapper 條件,查詢(xún)?nèi)坑涗?/span>
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根據(jù) Wrapper 條件,查詢(xún)?nèi)坑涗?。注意?只返回第一個(gè)字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根據(jù) entity 條件,查詢(xún)?nèi)坑涗洠ú⒎?yè))
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根據(jù) Wrapper 條件,查詢(xún)?nèi)坑涗洠ú⒎?yè))
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根據(jù) Wrapper 條件,查詢(xún)總記錄數(shù)
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Get 查詢(xún)單條記錄
// 根據(jù) ID 查詢(xún)
T getById(Serializable id);
// 根據(jù) Wrapper,查詢(xún)一條記錄。結(jié)果集,如果是多個(gè)會(huì)拋出異常,隨機(jī)取一條加上限制條件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根據(jù) Wrapper,查詢(xún)一條記錄
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根據(jù) Wrapper,查詢(xún)一條記錄
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根據(jù) Wrapper,查詢(xún)一條記錄
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
List 查詢(xún)多條記錄
// 查詢(xún)所有
List<T> list();
// 查詢(xún)列表
List<T> list(Wrapper<T> queryWrapper);
// 查詢(xún)(根據(jù)ID 批量查詢(xún))
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查詢(xún)(根據(jù) columnMap 條件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查詢(xún)所有列表
List<Map<String, Object>> listMaps();
// 查詢(xún)列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查詢(xún)?nèi)坑涗?/span>
List<Object> listObjs();
// 查詢(xún)?nèi)坑涗?/span>
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根據(jù) Wrapper 條件,查詢(xún)?nèi)坑涗?/span>
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根據(jù) Wrapper 條件,查詢(xún)?nèi)坑涗?/span>
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
Page 分頁(yè)查
// 無(wú)條件分頁(yè)查詢(xún)
IPage<T> page(IPage<T> page);
// 條件分頁(yè)查詢(xún)
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 無(wú)條件分頁(yè)查詢(xún)
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 條件分頁(yè)查詢(xún)
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
Count
// 查詢(xún)總記錄數(shù)
int count();
// 根據(jù) Wrapper 條件,查詢(xún)總記錄數(shù)
int count(Wrapper<T> queryWrapper);
Chain
query
// 鏈?zhǔn)讲樵?xún) 普通
QueryChainWrapper<T> query();
// 鏈?zhǔn)讲樵?xún) lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery();
// 示例:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();
update
// 鏈?zhǔn)礁?普通
UpdateChainWrapper<T> update();
// 鏈?zhǔn)礁?lambda 式。注意:不支持 Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
// 示例:
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);
測(cè)試:
// 測(cè)試查詢(xún)
@Test
public void testSelectById(){
User user = usermapper.selectById(1368490321062813699L);
System.out.println(user);
}
// 測(cè)試批量查詢(xún)!
@Test
public void testSelectByBatchId(){
List<User> users = usermapper.selectBatchIds(Arrays.asList(1, 2, 3));
for (User user : users) {
System.out.println(user);
}
}
// 按條件查詢(xún)之一使用map操作
@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);
}
}
分頁(yè)查詢(xún)
分頁(yè)在網(wǎng)站使用的十分多
1、原始的limit進(jìn)行分頁(yè)
2、pageHelper 第三方插件
3、Mybatis-Plus中也內(nèi)置了分頁(yè)插件!
支持的數(shù)據(jù)庫(kù)
IPage<UserVo> selectPageVo(IPage<?> page, Integer state);
// or (class MyPage extends Ipage<UserVo>{ private Integer state; })
MyPage selectPageVo(MyPage page);
// or
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>
其他:
生成 countSql 會(huì)在 left join 的表不參與 where 條件的情況下,把 left join 優(yōu)化掉
所以建議任何帶有 left join 的sql,都寫(xiě)標(biāo)準(zhǔn)sql既給于表一個(gè)別名,字段也要 別名.字段
如何使用
1、配置攔截器組件即可
3.4.0以前
// 分頁(yè)插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
3.4.0以后
// 注冊(cè)樂(lè)觀鎖插件與分頁(yè)插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//分頁(yè)插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//樂(lè)觀鎖插件
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
2、直接使用Page對(duì)象即可!
// 測(cè)試分頁(yè)查詢(xún)
@Test
public void testPage(){
// 參數(shù)一:當(dāng)前頁(yè)
// 參數(shù)二:頁(yè)面大小
// 使用了分頁(yè)插件之后,所有的分頁(yè)操作也變得簡(jiǎn)單的!
Page<User> page = new Page<>(1,2);
usermapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}
delete
// 根據(jù) entity 條件,刪除記錄
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 刪除(根據(jù)ID 批量刪除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根據(jù) ID 刪除
int deleteById(Serializable id);
// 根據(jù) columnMap 條件,刪除記錄
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
Remove
// 根據(jù) entity 條件,刪除記錄
boolean remove(Wrapper<T> queryWrapper);
// 根據(jù) ID 刪除
boolean removeById(Serializable id);
// 根據(jù) columnMap 條件,刪除記錄
boolean removeByMap(Map<String, Object> columnMap);
// 刪除(根據(jù)ID 批量刪除)
boolean removeByIds(Collection<? extends Serializable> idList);
測(cè)試:
1、根據(jù) id 刪除記錄
// 測(cè)試刪除
@Test
public void testDeleteById(){
usermapper.deleteById(1368490321062813699L);
}
// 通過(guò)id批量刪除
@Test
public void testDeleteBatchId(){
usermapper.deleteBatchIds(Arrays.asList(2,3,4));
}
// 通過(guò)map刪除
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","jom");
usermapper.deleteByMap(map);
}
邏輯刪除
物理刪除 :從數(shù)據(jù)庫(kù)中直接移出
邏輯刪除:在數(shù)據(jù)庫(kù)中沒(méi)有被移出,而是通過(guò)一個(gè)變量來(lái)讓他失效!deleted=0 ==>deleted =1(失效)
管理員可以查看被刪除的記錄!防止數(shù)據(jù)的丟失,類(lèi)似于回收站!
1、在數(shù)據(jù)表中增加一個(gè) deleted 字段
2、實(shí)體類(lèi)中增加屬性
@TableLogic //邏輯刪除
private Integer deleted;
注冊(cè) Bean(3.1.1開(kāi)始不再需要這一步):
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局邏輯刪除的實(shí)體字段名(since 3.3.0,配置后可以忽略不配置步驟2)
logic-delete-value: 1 # 邏輯已刪除值(默認(rèn)為 1)
logic-not-delete-value: 0 # 邏輯未刪除值(默認(rèn)為 0)
測(cè)試一下刪除!
查詢(xún)的時(shí)候也會(huì)自動(dòng)過(guò)濾,就查詢(xún)不到之前邏輯刪除的值了
聯(lián)系客服