Mybatis-Plus最優化持久層開發

Mybatis-plus:最優化持久層開發

一:Mybatis-plus快速入門:

1.1:簡介:

Mybatis-plus(簡稱MP)是一個Mybatis的增強工具,在mybatis的基礎上只做增強不做改變; 提高效率;自動生成單表的CRUD功能;
提供了豐富的條件拼接方式;
全自動ORM類型持久層框架;(不僅提供數據庫操作的方法,還會提供sql語句的實現)

1.2:Mybatis-plus快速入門:

!!!!!!!!!!!!!!!!!!!!!!!!!!!
如果我們想要對User表的數據進行單表CRUD:我們使用Mybatis-plus之后:我們只需要:1.創建mapper接口2.繼承 BaseMapper<User> (<>:要操作的表/實體類):我們就會擁有CRUD方法+CURD的sql語句注意:繼承的BaseMapper(它里面有單表的增刪改查方法),就不用寫mapper.xml文件了,之后就可以直接使用mapper對象調用相應的CRUD方法即可進行數據庫的操作了!!!

Mapper接口

public interface UserMapper extends BaseMapper<User>{/*原來Mybatis中:我們需要在mapper中自定義方法,然后在mapper.xml中使用sql實現方法但是使用了Mybatis-plus之后,我們直接繼承 “BaseMapper<>”:它里面有單表的增刪改查各種方法以及實現我們繼承它以后就擁有了這些方法,就不用寫mapper.xml文件了;*/
}

SpringBoot測試類

@SpringBootTest  //這個注解:就會自動完成ioc容器初始化,我們想要誰直接拿即可!!!!!!!!!!!!!!!!!
public class SpringBootMybatisPlusTest {@Autowiredprivate UserMapper userMapper; //拿到對象!!!public void test(){List<User> users = userMapper.selectList(null); //不傳參數:直接寫null:代表查詢全部數據;直接調用baseMapper接口中相應的方法即可}
}

二:Mybatis-plus的核心功能

Mybatis-plus是如何增強的

Mybatis-plus可以對三層架構的兩層進行增強:
1.MapperC層:只要繼承,就擁有了crud方法
2.Service層:繼承

原理:!!!!!!!!
mapper接口只要繼承BaseMapper<實體類> 接口:接下來我們就能使用通過mapper對象和BaseMapper接口中提供的CRUD方法來對  實體類表 進行操作;

2.1:基于Mapper接口的CRUD

(1)mapper接口如果我們想要對User表的數據進行單表CRUD:我們使用Mybatis-plus之后:我們只需要:1.創建mapper接口2.繼承 BaseMapper<User> (要操作的表/實體類):我們就會擁有CRUD方法+CURD的sql語句*/public interface Use rMapper extends BaseMapper<User> {//繼承之后:下面就相當于有了方法}(2)測試類:@SpringBootTest
public class MybatisPlusTest {@Autowiredprivate UserMapper userMapper;//(1)insert:@Testpublic void test(){User user=new User();user.setName("kun");user.setAge(88);user.setEmail("xxx");//baseMapper提供的數據庫insert方法int row = userMapper.insert(user);}//(2)delete:@Testpublic void test_delete(){//1.根據id刪除:()內裝值int rows = userMapper.deleteById(1687124323556002889L);//2.根據id刪除:age=20  name=jack; ()內裝條件: -->拼接條件Map param=new HashMap();param.put("age",20);     //-->刪除age=20 + name=jackparam.put("name","jack");int i = userMapper.deleteByMap(param);System.out.println("i = " + i);//wrapper 條件封裝對象,無限封裝條件;//userMapper.delete(wrapper)}//(3)Update()@Testpublic void test_update(){//1.將主鍵userId為1的age改為30:  ()內裝值//update user set age=30 where id=1:就等同于下方User user=new User();user.setId(1L);user.setAge(30);int i = userMapper.updateById(user);//2.將所有人age改為20User user1=new User();user1.setAge(20); //int update = userMapper.update(user1, null);// null:代表沒條件,該所有System.out.println("update = " + update);/*TODO:update:當屬性為null時:代表不修改updateById():實體類的id必須有值update() :實體類可以沒有id值*/}//(4)select a:根據主鍵查詢  b:根據主鍵集合查詢public void test_select(){//a:根據id查詢User user = userMapper.selectById(1);//b:根據集合查詢:eg:根據ids查詢List<Long> ids=new ArrayList<>();ids.add(1L);ids.add(2L);List<User> users = userMapper.selectBatchIds(ids); //selectBatchIds:批量idsSystem.out.println("users = " + users);}}

2.2:就Service接口的CRUD

service接口繼承:

2.3:分頁查詢實現:

Mybatis-plus實現分頁查詢:!!!!使用步驟:1.導入分頁插件2.使用分頁查詢

-04@SpringBootApplication
@MapperScan("com.atguigu.mapper")
/*
啟動類也是配置類:所以我們可以聲明帶@Bean的方法
1.配置一個分頁的插件:Mybatis-plus提供的,我們直接加進來使用就行了;在配置類/啟動類:中使用@Bean返回*/public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Bean//1.將Mybatis-plus插件加到ioc容器public MybatisPlusInterceptor plusInterceptor(){//a:是所有Mybatis-plus的插件集合:我們想要使用任何插件都可以加到這個集合中去;eg:我們可以將分頁插件加到里面;MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();//b:加入分頁插件:mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//指定數據庫return mybatisPlusInterceptor;}
}/*
測試類:
2.之后就可以使用分頁插件了:*/
@SpringBootTest
public class MybatisPlusTest {@Autowiredprivate UserMapper userMapper; //注入UserMapper對象:進行數據庫操作@Testpublic void testPage(){//a:創建Page對象: 參數解釋:(參數1:頁碼, 參數2:頁容量)Page<User> page=new Page<>(1,3);userMapper.selectPage(page,null); //需要放入Page對象//最后分頁的結果也會被封裝到page里面:-->所以直接通過page對象獲取結果即可long pages = page.getPages();long current = page.getCurrent(); //獲取當前頁碼、List<User> records = page.getRecords(); //獲取當前頁數據long total = page.getTotal();//獲取總條數}}

自定義mapper方法使用分頁

上面:我們是使用Mybatis提供的方法:  userMapper.selectPage(page,null);
如果我們自定義的mapper方法想要使用分頁查詢:1.在mapper接口中定義方法:自定義方法想要分頁:在第一個參數加一個IPage對象,返回值也是IPage2.在mapper文件中實現:使用sql語句實現:不要加limit和;3.測試

1.public interface UserMapper extends BaseMapper<User> {//繼承BaseMapper接口:里面有單表的方法/*演示:自定義mapper方法實現分頁:eg:查詢*///1.在mapper接口中定義抽象方法:但是:方法的第一個參數:要傳一個IPage,返回值要是IPage,里面寫查詢集合的泛型即可IPage<User> queryByAge(IPage<User>page, @Param("age") Integer age);
}2.<!--2.使用sql語句實現UserMapper接口的方法:不用在最后加limit,!--><select id="queryByAge" resultType="com.atguigu.pojo.User"> <!--resultType:泛型-->select * from user where age>#{age}</select>3./*3.測試自定義方法分頁*/public void test_MyPage(){//a:傳一個分頁插件的值:Page<User> page=new Page<>(1,3);//b.userMapper.queryByAge(page,1);//c://最后分頁的結果也會被封裝到page里面:-->所以直接通過page對象獲取結果即可long pages = page.getPages();long current = page.getCurrent(); //獲取當前頁碼、List<User> records = page.getRecords(); //獲取當前頁數據long total = page.getTotal();//獲取總條數System.out.println("total:"+total);}}

2.4:條件構造器使用:

2.4.1條件構造器的作用:
warpper對象:動態進行 條件的拼接;
就相當于在sql語句后面加條件,只是使用java代碼的格式;
---->:就不用在mapper.xml文件中使用sql語句實現了,直接使用java代碼來代替sql語句;!!!!!!!!

warpper對象:動態進行 條件的拼接;
就相當于在sql語句后面加條件,只是使用java代碼的格式;
---->:就不用在mapper.xml文件中使用sql語句實現了,直接使用java代碼來代替sql語句;!!!!!!!!

2.4.2條件構造器的類結構:
一般使用:第一種: UpdateWrapper(修改)、QueryWrapper(刪除、查詢、修改)第二種: LambdaUpdateWrapper(修改)、 LambdaQueryWrapper(刪除、查詢、修改)
  • (1)第一種:基于queryWrapper組裝條件:增/刪/改

      使用方法:1.在mapper接口中定義方法,并繼承base接口(提供了各種方法的實現)2.直接使用java代碼實現:不需要在mapper.xml文件中實現了//a:創建QueryWrapperQueryWrapper<實體類>queryWrapper=new QueryWrapper<>();//b:條件拼接:調用queryWrapper方法//c:使用mappper對象:調用CRUD方法,傳入對象即可
    

1.mapper接口:public interface UserMapper extends BaseMapper<User> {//繼承BaseMapper接口:里面有單表的方法/*演示:自定義mapper方法實現分頁:eg:查詢*///1.在mapper接口中定義抽象方法:但是:方法的第一個參數:要傳一個IPage,返回值要是IPage,里面寫查詢集合的泛型即可IPage<User> queryByAge(IPage<User>page, @Param("age") Integer age);
}2./*
演示條件構造器使用:進行條件的動態拼接:(1)QueryWrapper測試:*/
@SpringBootTest
public class MybatisPlusQueryWrapper {@Autowiredprivate UserMapper userMapper; //拿到對象:操作數據庫@Testpublic void test_01(){//查詢用戶名包含 a,age在20到30之間的,且郵箱不為空的用戶;//分析:查詢:返回的是集合List-->selectList//a:創建一個QueryWrapper集合:相當于容器來裝條件QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:之后sql語句的條件:直接使用queryWrapper動態調用wrapper的方法來完成動態拼接;queryWrapper.like("name","a"); //條件1:name種包含a的queryWrapper.between("age",20,30); //條件2:age在20-30之間queryWrapper.isNotNull("email"); //第三個條件:email不為nullList<User> users = userMapper.selectList(queryWrapper);  ----->:因為繼承了base接口,所以單表直接調用方法即可!//queryWrapper就是sql條件,將它·傳進去!!!//之后這個就會變成sql語句; !!!!!!!!!!!//就相當于:select  * from user where name(like %a% and age>=20 and age<=30 and email is not null)/*!!!一個個調用麻煩,可以使用鏈式調用:!!!!queryWrapper.like("name","a").between("age",20,30).isNotNull("email");*/}
}

(2)queryWrapper實戰使用:

	@SpringBootTestpublic class MybatisPlusQueryWrapper {@Autowiredprivate UserMapper userMapper; //拿到對象:操作數據庫按照年齡降序查詢用戶,如果年齡age相同則按id升序排列//(2)queryWrapper:按年齡降序查詢用戶,如果年齡相同則按id升序排列@Testpublic void test_02(){//a:創建QueryMapper集合:裝條件QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:使用條件構造器進行條件的拼接:queryWrapper.orderByDesc("age").orderByAsc("id");//a:條件1:age降序排列; b:條件2:id增序//c:放到queryWrapper中,進行條件拼接; ==order by age desc,id ascList<User> users = userMapper.selectList(queryWrapper);}//(3)刪除email為null的用戶@Testpublic void test_03(){//a:QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:queryWrapper.isNotNull("email");//c:int delete = userMapper.delete(queryWrapper);}//(4):將age>20且用戶名中包含a或email為null的用戶信息修改://分析:修改:--update:所以usermapper調用update方法:相應的條件:age>20... 使用queryWrapper封裝,然后作為條件放入update方法形參中;!!!!!@Testpublic void test_04(){//a:QueryWrapper<User> queryWrapper=new QueryWrapper<>();//b:添加條件:queryWrapper.gt("age",20).like("name","a")                ---------->B:相當于:where ........or().isNotNull("email");//1.條件:age>20 name包含a,--->:條件直接調用時:默認自動使用and進行拼接;!!!!!//queryWrapper.gt("age",20).like("name","a") == where age>20 and ..      //2.如果想要在條件之后追加or關鍵字:可以使用: “or().條件”;//c:創建User對象,進行update修改User user=new User();user.setAge(88);                ----->A:相當于update user  set name="" age= user.setEmail("hehe");//d:如果要修改:第一位傳入要修改的對象userMapper.update(user, queryWrapper); //放入對象 + queryWrapper}//(5):查詢用戶信息的name和age字段;  --->指定列查詢!!!//select name,age from t_user where id>1;public void test_05() {//a:QueryWrapper<User> queryWrapper = new QueryWrapper<>();//b:條件拼接:queryWrapper.gt("age",1);//!!!查詢時:默認是查詢全部���!!!!!,但可以使用select指定queryWrapper.select("name","age");userMapper.selectList(queryWrapper);}//(6)前端傳入兩個參數,name,age:---->:動態條件組織判斷!!!!// 只要name不為null,就作為條件 來查詢符合的//只要age>18作為條件,就作為條件 來查詢符合的@Testpublic void test_06(){String name="xx";Integer age=19;//a:QueryWrapper<User>queryWrapper=new QueryWrapper<>();//b:進行條件拼接://b.1:如果name!=null,就使用queryWrapper進行條件拼接if(StringUtils.isNotBlank(name)){  //調用isNotBlank進行判斷//動態條件判斷:如果name不為null,就進行條件的拼接queryWrapper.eq("name",name); //使用queryWrapper進行拼接}//b.2:如果age>18 進行動態拼接:if (age>18 && age!=null){queryWrapper.eq("age",age);}userMapper.selectList(queryWrapper);/*注意:!!!!!!!!!!!!!!!!Wrapper每個方法都有:一個boolean類型的condition,允許我們第一個參數放一個比較表達式,:如果condition為true-->整個條件為true,就執行下面代碼:如果condition為false-->整個條件為false,就失效,不執行下面代碼-->condition里面有動態判斷,就不用我們在外部寫判斷了eg:*/queryWrapper.eq(StringUtils.isNotBlank(name),"name",name);queryWrapper.eq(age>18 && age!=null,"age",age);}

updateWrapper:改

進行修改時:使用updateWrapper:!!!!

     //a:UpdateWrapper<User> queryWrapper=new UpdateWrapper<>();//b:queryWrapper.gt("age",20).like("name","a").isNotNull("email").set("email",null).set("age",100);//c:userMapper.update(null,queryWrapper);

在修改時updateWrapper和queryWrapper區別:

(參數1:條件; 參數2:修改的數據)
queryWrapper修改:參數1只能放條件,且列名不能為null
updateWrapper修改:參數1可以放條件, 且列名可以設置為null;且可以直接調用set方法進行修改
  • (2)第二種:

      和第一種用法一樣,只是對第一種的增強eg:Lambda:避免列寫錯的機制:傳入的列名可以是” 方法引用的表達式 “:類名::getName -->相當于找方法對應的列名
    

LambdaQueryWrapper:增/刪/改

eg:
查詢用戶名包含 a like,年齡在20-30之間,并且郵箱不為null的用戶信息;LambdaQueryWrapper<User>lambdaQueryWrapper=new LambdaQueryWrapper<>();//即只要將原來的列名,變為Lambda方法引用即可,其余不變!!!!!!!!!!lambdaQueryWrapper.like(User::getName,"a").between(User::getAge,20,30).isNotNull(User::getEmail);userMapper.selectList(queryWrapper);

LambdaupdateWrapper:改

eg:LambdaUpdateWrapper<User>lambdaUpdateWrapper=new LambdaUpdateWrapper<>();//即只要將原來的列名,變為Lambda方法引用即可,其余不變!!!!!!!!!!lambdaUpdateWrapper.gt(User::getAge,20).like(User::getName,"a").isNotNull(User::getEmail).set(User::getEmail,null).set(User::getAge,100);userMapper.update(null,lambdaUpdateWrapper);

(3)總結:

Wrapper:里面:完成了動態條件封裝
最終推薦使用Lambda;(不用寫列名,只需類名::方法即可)如果復雜的sql:qg:嵌套、子查詢 不會使用Wrapper怎么辦:我們仍然使用原來的:定義mapper如果為單表的話:直接使用mapper對象調用CRUD方法即可;如果為多表的話:在mapper.xml文件中實現;

2.5Mybatis-plus核心注解的使用:

注解的作用:指定實體類和表之間的映射;

1.@TableName
作用:指定數據庫表名;(當【BaseMapper<實體類>】 實體類名 和 數據庫表名不同時);
使用:@TableName("數據庫表名")a:位置:加到實體類上
b:可以不加,不加的話默認使用實體類的名字作為 表名! 忽略大小寫;  eg:BaseMapper<User>:默認將實體類名:User,作為表名 來進行操作;c:使用@TableName注解場景:當數據庫的表名和實體類名稱不同時(忽略大小寫),需要使用@TableName來指定 表名:eg:數據庫名:t_user;  實體類名:User兩個名稱不同,此時我們需要在實體類上方使用: ”@TableName("t_user")“ 來指定表名;
d: 如果表名命名規范:eg:都以 "t_"開頭,且除了”t_“以外,實體類名=表名我們可以將前綴統一提取到配置文件中(application.yml),這樣就不需要每個實體類都加@TableName注解來指定表名了它會自動查找相應的表;mybatis-plus:global-config:db-config:table-prefix: t_ #表名前綴;#加了這個之后,我們就不需要在每個實體類加@TableName注解了,它就會自己根據前綴"t_"進行查找;#前提:數據庫的表都是以 “t_”開頭的
2.@TableId:
作用:描述主鍵的一些特性; eg: value:指定表主鍵名;  type:設置主鍵type策略
使用:在實體類的主鍵屬性上:+@TableId(value="主鍵列名",type="主鍵策略");b:位置:加到實體類的主鍵屬性上
c:使用@TableId的場景:場景1:表 主鍵的列名 和 實體類的屬性名 不一致時,使用這個注解來指定表的列名;!!!eg: 1:如果 實體類屬性名:id; 數據庫主鍵列名:x_id; --->兩個名稱不一樣,我們可以在實體類主鍵的屬性上方加@TableId(value="x_id") 場景2:設置表主鍵增長:type主鍵策略:

type增長策略:

@SpringBootTestpublic class MybatisPlusTableIdTest {@Autowiredprivate UserMapper userMapper;@Testpublic  void test_01(){//以插入數據舉例:User user=new User();user.setName("坤坤");user.setAge(20);user.setEmail("xxx@qq.com");//插入的時候:主鍵id不要賦值; 主鍵自增長 或者 type策略 進行賦值!!!!!!!!!!!!/*1.默認主鍵的type(策略)是:雪花算法;--->:它會生成一個不重復的long類型的數字; eg:123456789雪花算法:a:要求數據庫主鍵是 bigint / varchar(64) 類型;         -->:eg:varchar(64)/bigint money;!!!b:要求實體類相應屬性:使用Long/String接值(int接不到)  -->:eg:Long/String  money;!!!c:隨機生成一個數字,給予主鍵值(不重復)2.但我們想要把主鍵type(策略)變成auto自增長,方式1:直接在實體類的主鍵上方加:@TableId(type= IdType.AUTO); 前提是mysql數據庫必須設置了主鍵自增長(auto_increment)auto:a:要求mysql數據庫的 表主鍵 必須設置了 自增長b:插入數據就是自增長了方式2:全局設置主鍵自增長策略:如果每個表都設置為自增長(auto),在配置文件(application.yml)中配置*/userMapper.insert(user); //之間調用BaseMapper中的insert方法;}
}User視圖類:public class User(){@TableId(type = IdType.AUTO)private Long id;   }
3.@TableFiled
作用:描述非主鍵字段
使用:在實體類的非主鍵字段上:+@TableFiled(value="",exist="")a:使用場景1:value="" (不是必須指定的,String類型):當實體類的屬性名 和 列名 不同的時候 使用@TableFiled指定數據庫表名;使用場景2:esist=ture/false; (默認為true):eg:@TableFiled(value="name",exist=false):private String name;-->:false代表:認為name沒有數據庫對應的列,因此在查詢等時候不會對他進行操作;

三:Mybatis-plus高級擴展

3.1邏輯刪除實現:

(1)邏輯刪除概念:
邏輯刪除:是 "假刪除數據":是將想要刪除數據的狀態修改為 "被刪除狀態",但是數據并沒有消失,之后在查詢時,查詢沒有 刪除狀態 的數據,也是一種刪除;物理刪除:delete from:刪除之后就沒有了相應的數據;(2)邏輯刪除的實現:方式1:單個表邏輯刪除的實現:a:在數據庫表中 插入一個邏輯刪除字段(int類型,有1/0狀態字段!):alert table User add deleted int default 1/0; -->: 1/0:邏輯刪除的狀態字段:1代表:邏輯刪除; 0代表:未邏輯刪		除;!!!!b:在實體類的對應屬性上加:@TableLogiceg:@TableLogic //代表這個屬性對應的列是 :邏輯刪除狀態字段//當我們刪除數據時候,自動變成修改此列的屬性值(即將deleted變為1);   默認:0是未刪除,1是刪除//當我們查詢數據時候:默認只查詢 deleted=0 的列的數據private Integer deleted;方式2:多個表邏輯刪除的實現(全局指定):a:同上b:在配置文件(application.yml)中:配置mybatis-plus:global-config:db-config:logic-delete-field: deleted # 全局邏輯刪除的實體屬性名注意:這種就不需要在類的屬性名上 + @TableLogic了但是仍然需要在實體類中創建一個和列名deleted 對應的屬性名;

代碼演示:

以單個表實現邏輯刪除為例:@TableLogicprivate Integer deleted;@SpringBootTest
public class MybatisPlusTableLogicTest {@Autowiredprivate UserMapper userMapper;public void test_01(){//a:之前是物理刪除:delete from user where id=5;//b:現在:邏輯刪除:相當于:update user set deleted=1 where id=5userMapper.deleteById(5);//eg:userMapper.selectList(null); -->之后在查詢時:就只會查詢deleted=0的了:!!!!!(自動在條件位置加上where deleted=0)}

3.2樂觀鎖的實現

1.樂觀鎖 和悲觀鎖 都是在 并發編程 中用于處理并發訪問和資源競爭的兩種不同機制;2.(1)悲觀鎖:同步鎖/互斥鎖:線程在訪問共享資源之前會獲取到鎖,在數據訪問時只允許一個線程訪問資源,只有當前線程訪問完成只后,才會釋放鎖,讓其它線程繼續操作資源;(2)樂觀鎖:不需要提前加鎖,而是在數據更新階段進行檢測樂觀鎖和悲觀鎖是兩種解決并發數據問題的思路,不是技術!!3.具體的技術和方案:1.樂觀鎖實現方案和技術版本號/時間戳CAS無鎖數據結構2.悲觀鎖的實現方案和技術鎖機制數據庫鎖信號量4. 現在主要學習如何使用樂觀鎖(版本號)解決并發問題!!!!!!!(1)版本號:解決數據并發更新出現錯誤數據的問題;--->保證數據一致性;(2)樂觀鎖技術的實現流程:a:每條數據添加一個版本號字段versionb:取出記錄時,獲取當前versionc:更新時,檢查獲取版本號是不是數據庫當前最新版本號d:如果是(代表沒人修改過數據),執行更新:set數據更新,version=version+1e:如果不是(證明已經修改過了),更新失敗5.使用mybatis-plus數據使用樂觀鎖步驟: 1.數據庫插入一個version字段:alert table user add version int default 1  (int類型 樂觀鎖字段)2 實體類創建相應的屬性: private Integer version;  + 在屬性上方使用@Version注解3.添加攔截器(添加版本號更新插件)之后在更新的時候就會檢查版本,檢查數據錯誤的問題;

樂觀鎖測試:

1.alter  table user add version int default 1;  #int 類型 樂觀鎖字段2.
public class User {@Versionprivate Integer version; //版本號字段
}//注意:之后在數據修改時都會檢查樂觀鎖;3.在配置類/Main類中加入攔截器public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Beanpublic MybatisPlusInterceptor plusInterceptor(){//攔截器2:樂觀鎖【版本號插件】 mybatis-plus在每次更新時候,每次幫我們對比版本號字段和增加版本號+1mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;}4.
/*
測試樂觀鎖實現*/
@SpringBootTest
public class MybatisPlusVersionTest {private UserMapper userMapper;@Testpublic void testById(){//步驟1:先查詢,再更新 獲取version數據//同時查詢兩條,但是version唯一,最后更新的失敗、User user=new User();  //user 版本號為:1User user1=new User(); //user1 版本號為:1user.setAge(20);user.setAge(30);userMapper.updateById(user); //20-->:此時數據庫的version ->2//樂觀鎖生效:失敗userMapper.updateById(user1);//因為user1的版本號為1,但是數據庫的版本號為2,證明不是最新數據 -->1!=2,樂觀鎖生效,更新失敗//所以最終age為:20}
}

3.3防止全表更新和刪除

在開發中一般不會出現全表的更新/刪除:Mybatis-plus提供一種防御插件:一旦檢測到是全表的update/delete:就會報異常;實現方法:添加防止全表更新和刪除的攔截器:

代碼測試:

1.加入攔截器/插件:
public class Main {public static void main(String[] args) {SpringApplication.run(Main.class, args);}@Beanpublic MybatisPlusInterceptor plusInterceptor(){//攔截器3:防止全表刪除和更新的攔截器mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return mybatisPlusInterceptor;}2.測試類中:public void test(){@Au..private UserMapper userMapper; //拿到mapper對象,進行數據庫操作!!!;//a:全表刪除!mapper.delete(null); ----->:null,代表沒有寫條件,代表:全表刪除;//b:全表更新:mapper.update(null); ------>: null,代表沒有條件,代表全表更新!----------->:之后就會拋出異常:不允許全表delete/update!!!!!!!}

四:Mybatis-Plus代碼生成器(MybatisX插件)!!!

學習目標:1.如何使用MybatisX插件: 逆向工程 生成Mybatis-Plus代碼;//逆向工程:根據表自動生成實體類、mapper、service;!!!!!!!!!!!!!!!!!!!!!!2. 使用MybatisX插件 動態生成自定義的sql語句

4.1Mybatis插件逆向工程

//逆向工程:根據表自動生成實體類、mapper、service;!!!!!!!!!!!!!!!!!!!!!!步驟:連接數據庫;.....

4.2Mybatis-plus快速生成單表CRUD代碼(自定義sql)!!!!!!!!

如果我們需要自己定義一些sql語句:eg:批量查詢、根據id查詢......//步驟:1.直接在mapper接口中書寫相應的 ” 方法名 “ (//按照mybatisX的方法命名規則)eg:批量插入:insertBatch根據條件查詢:selectByNameAndAgeAndAge2.然后鼠標放在方法名上,點擊MybatisX,--->MybatisX 就會在mapper接口自動寫好 且 在mapper.xml文件中自動生成sql語句!!!!!!!!//之后有關單表的CRUD我們就不需要自己寫了!!!!!!!!!!//我們可以看mybatisX的官方文檔:介紹了如何寫

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/45136.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/45136.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/45136.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

國漫推薦11

1.《元龍》 2.《惡魔法則》2023年9月29日 3.《三十六騎》 4.《山河劍心》 5.劍網3俠肝義膽沈劍心 《劍網3俠肝義膽沈劍心》 《劍網3俠肝義膽沈劍心 第二季》 《劍網3俠肝義膽沈劍心之長漂》&#xff08;番外&#xff09; 《劍網3俠肝義膽沈劍心 第三季》 6.《仙逆》東方玄幻…

Uniswap V2和Uniswap V3的區別

Uniswap V2和Uniswap V3是兩個不同版本的去中心化交易協議&#xff0c;由Uniswap團隊開發和維護。它們之間的主要區別包括以下幾點&#xff1a; 資金池模型不同: Uniswap V2: 使用恒定乘積市場模型&#xff0c;也就是 x * y k。這意味著每個資金池中的資產的乘積保持不變&…

Transformer的模型的擴展與應用領域的拓展 - Transformer教程

在如今的人工智能領域&#xff0c;Transformer模型已經成為了眾多研究和應用的焦點。從自然語言處理到計算機視覺&#xff0c;Transformer模型的擴展與應用領域的拓展帶來了無數的可能性。今天&#xff0c;我們就來聊聊Transformer模型的擴展以及它在不同領域的廣泛應用。 首先…

生產管理系統功能全拆解:哪些功能是企業真正需要的?

制造業的伙伴經常聽到“生產管理”&#xff0c;但很多人可能只是模糊地知道它與工廠、生產線有關。那么&#xff0c;到底什么是生產管理呢&#xff1f;它的重要性又體現在哪里呢&#xff1f;接下來&#xff0c;我就以輕松的方式&#xff0c;帶大家走進生產管理的世界&#xff0…

函數練習·二 基礎題

# 【以下功能都使用函數封裝】 # 提示: 涉及到要返回的題目,請使用return # 基礎題 # 1.封裝函數&#xff0c;計算從1到某個數以內所有奇數的和并返回 def fn1(n): return sum([i for i in range(1, n, 2)]) print(fn1(7)) # 2.封裝函數&#xff0c;判斷某個數是否是偶…

微信閃退怎么回事?實用技巧助你輕松應對

在使用微信的過程中&#xff0c;偶爾會遇到閃退的問題&#xff0c;這不僅影響我們的日常溝通&#xff0c;還可能導致重要信息的丟失。那么&#xff0c;微信閃退怎么回事呢&#xff1f;閃退的原因可能有很多&#xff0c;包括軟件問題、手機存儲不足、系統不兼容等。本文將詳細分…

筆記本電腦數據丟失如何恢復?

在計算機網絡日益普及的今天&#xff0c;計算機已波及到人們的生活、工作、學習及消費等廣泛領域&#xff0c;其服務和管理也涉及政府、工商、金融及用戶等諸多方面。筆記本電腦等電子產品被各行各業的人所喜愛和接受&#xff0c;早已成為人們出差的必備品&#xff0c;可以用來…

keepalived高可用集群

一、keepalived&#xff1a; 1.keepalive是lvs集群中的高可用架構&#xff0c;只是針對調度器的高可用&#xff0c;基于vrrp來實現調度器的主和備&#xff0c;也就是高可用的HA架構&#xff1b;設置一臺主調度器和一臺備調度器&#xff0c;在主調度器正常工作的時候&#xff0…

OS_同步與互斥

2024-07-04&#xff1a;操作系統同步與互斥學習筆記 第9節 同步與互斥 9.1 同步互斥的基本概念9.1.1 同步關系9.1.2 互斥關系9.1.3 臨界資源9.1.4 臨界區9.1.5 同步機制應遵循規則 9.2 軟件同步機制9.2.1 單標志法9.2.2 雙標志先檢查法9.2.3 雙標志后檢查法9.2.4 peterson算法 …

BP神經網絡與反向傳播算法在深度學習中的應用

BP神經網絡與反向傳播算法在深度學習中的應用 在神經網絡的發展歷史中&#xff0c;BP神經網絡&#xff08;Backpropagation Neural Network&#xff09;占有重要地位。BP神經網絡通過反向傳播算法進行訓練&#xff0c;這種算法在神經網絡中引入了一種高效的學習方式。隨著深度…

jstat命令介紹

jstat&#xff1a;查看JVM統計信息 一 基本情況二 基本語法2.1 option參數1. 類裝載相關的&#xff1a;2. 垃圾回收相關的-gc&#xff1a;顯示與GC相關的堆信息。包括Eden區、兩個Survivor區、老年代、永久代等的容量、已用空間、GC時間合計等信息。-gccapacity&#xff1a;顯示…

【C++】C++-機房收費管理系統(源碼+注釋)【獨一無二】

&#x1f449;博__主&#x1f448;&#xff1a;米碼收割機 &#x1f449;技__能&#x1f448;&#xff1a;C/Python語言 &#x1f449;公眾號&#x1f448;&#xff1a;測試開發自動化【獲取源碼商業合作】 &#x1f449;榮__譽&#x1f448;&#xff1a;阿里云博客專家博主、5…

LeetCode之最長回文子串

1.題目鏈接 5. 最長回文子串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/longest-palindromic-substring/description/ 2.題目解析 對于這道題目我們可以使用動態規劃的思路來求解&#xff0c;具體思路是&#xff0c;對于一個長度大于2的子串&…

生成式信息檢索(問答系統與信息檢索的進步)

文章目錄 什么是問答系統&#xff08;Question Answering Systems&#xff09;檢索系統的演變經典檢索系統“Term” 文檔搜素的最小單位倒排索引詞嵌入的出現預訓練語言模型 用于問答的語言模型設計方案選擇&#xff1a;封閉式與開放式問答系統對比方案A&#xff1a;封閉式生成…

【干貨】一文帶你看懂什么是渠道分銷?如何管理渠道分銷

在當今競爭激烈的市場環境中&#xff0c;企業想要擴大市場份額、提高產品或服務的可見度&#xff0c;有效的渠道分銷策略是關鍵。 什么是渠道分銷&#xff1f; 渠道分銷&#xff0c;簡而言之&#xff0c;是指企業利用中間商&#xff08;如經銷商、代理商、零售商等&#xff0…

springboot解壓文件流zip壓縮包

springboot解壓文件流zip壓縮包 原始文件存儲的地方&#xff1a; 需要在當前目錄下解壓該文件&#xff0c;如下圖&#xff1a; 代碼示例&#xff1a; private Result<String> getLocationGuideLayerName(YbYstbtqTaskResolveParam params, String fishnetLayerName)…

華為od100問持續分享-1

我是一名軟件開發培訓機構老師&#xff0c;我的學生已經有上百人通過了華為OD機試&#xff0c;學生們每次考完試&#xff0c;會把題目拿出來一起交流分享。 重要&#xff1a;2024年5月份開始&#xff0c;考的都是OD統一考試&#xff08;D卷&#xff09;&#xff0c;題庫已經整…

入門PHP就來我這(高級)24 ~ Session判斷用戶登錄

有膽量你就來跟著路老師卷起來&#xff01; -- 純干貨&#xff0c;技術知識分享 路老師給大家分享PHP語言的知識了&#xff0c;旨在想讓大家入門PHP&#xff0c;并深入了解PHP語言。 上一篇我們介紹了Session管理部分的概念&#xff0c;本文通過session來改寫一些用戶登錄&…

一致性Hash問題及解決方案

Hash算法的應用場景 請求的負載均衡 Nginx的ip_hash策略可以在客戶端ip不發生變化的情況下&#xff0c;將其發出的請求始終路由到同一個目標服務器上&#xff0c;實現會話粘滯&#xff0c;避免處理session共享問題。 如果沒有ip_hash策略&#xff0c;可以通過維護一張映射表的…

常用包管理工具(apk、apt、yum)常用命令

apk 包管理工具apk是Alpine Linux中使用廣泛的一個工具&#xff0c;用于管理軟件包的安裝、更新、卸載等操作。以下是一些常用的apk命令及其解釋&#xff1a; 1.更新 apk update&#xff1a;從遠程鏡像源更新本地倉庫中的所有軟件包索引apk upgrade&#xff1a;升級本地已安裝…