前言:最近也在忙于学习公司的一些代码,业务,这篇Mybatis-Plus是前几天复习的,没有太多的时间做下笔记,因此熬了一会儿,相当于又复习了一遍,以加深自己的印象和帮助到各位小伙伴儿们😉😉。
最近还会继续更新,如果有什么需要改进的地方,还请大佬不吝赐教🤞🤞
小威在此先感谢诸佬了👏👏

🏠个人主页:小威要向诸佬学习呀
🧑个人简介:大家好,我是小威,一个想要与大家共同进步的男人😉😉
目前状况🎉:目前大二,在一家满意的公司实习👏👏🎁如果大佬在准备面试,找工作,刷算法,可以使用我找实习前用的刷题神器哦刷题神器点这里哟
💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘
牛客部分使用反馈,个人感觉还不错,帮我找到了心仪的公司,希望各位伙伴儿们通过它也能提高不少🥂🥂🥂
以下正文开始

在我们做项目的过程中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以选择用普通的方法来自己填充,也可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作。
因此我们两个方法都介绍一遍。

首先用到我们上一篇的项目,我们需要给项目添加两个字段,并且需要在数据库中添加create_time,update_time字段。
private Date createTime;
private Date updateTime;

拿我们添加用户的demo举例,按照我们平常的做法,我们应该这样做:
@Test
public void insertUser(){
System.out.println(("----- insert method test ------"));
User user=new User();
user.setName("wangWu");
user.setId(8L);
user.setAge(21);
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
user.setEmail("wangWU@qq.com");
int result = userMapper.insert(user);
System.out.println(result);
}
我们需要自己通过user对象设置CreateTime,UpdateTime属性,这样的方法当然可以运行的。
但是一旦所创建的对象比较多时,我们一直写一些重复的代码,会看起来很不舒服,因此,我们下面介绍如何通过Mybatis-Plus自动填充。
第一步,我们需要在实体类给对应的字段中添加相关的注解。
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
上面的第一个注解,fill是填充的意思,也就是在插入数据的时候给表自动填充,第二个则是在插入和更新数据的时候自动填充。
但是,光有这些还不够。我们应该自己设置一个类来进行配置。
实现元对象处理器接口
MetaObjectHandler接口是mybatisPlus提供给我们的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值。
不要忘记添加 @Component 注解
package com.mpdemo.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);//根据名字设置属性值
this.setFieldValByName("updateTime",new Date(),metaObject);
this.setFieldValByName("version",1,metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
启动项目进行增添和修改测试,结果如下


在我们进行大项目的开发时,访问数据时不可能串行(one by one)地进行的,但如果多个人同时修改一个数据,可能最后一个数据会将前面的数据覆盖掉,因此能够使用乐观锁而不是悲观锁,Mybatis-Plus会基于版本号这样做:
接下来我们来实现。

首先还是在实体类和数据库中定义新字段:
ALTER TABLE `user` ADD COLUMN `version` INT
在实体类中需要为版本号加上@Version注解,表示这个字段是版本号。
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
同时加上@TableField注解,在新增时定义版本号的默认值。
在handler类中配置
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);//根据名字设置属性值
this.setFieldValByName("updateTime",new Date(),metaObject);
this.setFieldValByName("version",1,metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
同时也需要在configuration配置类中进行配置
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement //开启事务注解
@Configuration
@MapperScan("com.atguigu.mybatis_plus.mapper")
public class MybatisPlusConfig {
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
编写添加用户数据和更新用户数据的类
//增加用户数据测试类
@Test
public void insertUser(){
System.out.println(("----- insert method test ------"));
User user=new User();
user.setName("wangWu");
user.setId(8L);
user.setAge(21);
// user.setCreateTime(new Date());
// user.setUpdateTime(new Date());
user.setEmail("wangWU@qq.com");
int result = userMapper.insert(user);
System.out.println(result);
}
编写更新数据测试类
@Test
public void testOptimisticLocker(){
User user=userMapper.selectById(8L);//必须先查询获取version的值,然后再修改,version值才会有变化
user.setAge(20);
int i = userMapper.updateById(user);
System.out.println(i);
}
需要注意的是:一定要先查询对象的version值,才生效!如果直接进行updateById的话不会生效。
测试结果如下:
添加用户,version值为1

修改用户age为21,此时version+1变为了2。


Mybatis-Plus自带分页查询的插件,不用编写一些类,但需要我们简单配置。
首先还是在我们的configuration配置类中配置:
//分页的插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
配置完上面内容即可使用:
@Test
public void testPage(){
Page<User> page=new Page<>(2,3);//前面数据表示当前页,后面数据表示每一页显示几条数据。
userMapper.selectPage(page,null);//查询条件为空
System.out.println(page.getCurrent());//获取当前页
System.out.println(page.getRecords());//获取每页数据的list集合
System.out.println(page.getSize());//每页显示记录的条数
System.out.println(page.getTotal());//总记录数
System.out.println(page.getPages());//总页数
System.out.println(page.hasNext());//是否有下一页
System.out.println(page.hasPrevious());//是否有上一页
}
查询结果如下:根据第一行的日志SQL语句,Mybatis-Plus在帮我们查询时自带了Limit关键字进行查询。


首先,需要知道什么是逻辑删除:
物理删除:真实删除,直接将对应的数据从数据库中删除,之后查询不到此条被删除数据
逻辑删除:假删除,将对应的数据中代表是否被删除字段状态修改为“被删除状态”,一般用0和1表示,之后在数据库中仍旧能看到此条数据记录,存在有一个删除字段,用0和1代表是否数据被删除。
首先还是先在数据库和实体类中添加字段
/**
* @TableLogic 逻辑删除注解
*/
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
ALTER TABLE `user` ADD COLUMN `deleted` boolean
然后跟上面的操作一样,在handler类中进行配置
@Override
public void insertFill(MetaObject metaObject) {
//这里和上面的一样,不写了,占字数🤣。
this.setFieldValByName("deleted", 0, metaObject);//表示deleted字段的默认值为0,在插入时字段填充字段值。
}
同时,也可以在Properties或Ymal中对默认值进行设置。
mybatis-plus.global-config.db-config.logic-delete-value=1//删除
mybatis-plus.global-config.db-config.logic-not-delete-value=0//没有删除
旧版的还需要再配置类中添加配置:
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
首先我们先编写,删除一条记录的代码:
/**
* 测试 逻辑删除
*/
@Test
public void testLogicDelete() {
int result = userMapper.deleteById(7L);
System.out.println(result);
}
运行程序,查看控制台语句:


我们经过测试后发现,数据并没有被删除,deleted字段的值由0变成了1
测试后分析打印的sql语句,是一条update
注意:被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
最后操作查询所有字段的语句:
/**
* 测试 逻辑删除后的查询:
* 不包括被逻辑删除的记录
*/
@Test
public void testLogicDeleteSelect() {
User user = new User();
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}

可以看出控制台的SQL语句自动加上了deleted不为0的条件。
文章到这里就结束了,下篇我们将继续介绍Mybatis-Plus的其他知识点,喜欢的大佬可以多多支持哦😉😉。
如果有什么疑问的地方请指出,诸佬们一起讨论🍻🍻

最后再次给大家安利一波牛客,牛客真的很不错的软件,点击刷题神器
注册牛客,快来和博主一起刷题吧嘿嘿嘿👏
同时祝伙伴儿找到理想的工作及猛猛地提升算法能力哦😏
再次感谢各位小伙伴儿们的支持🤞

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t