mybatis-plus 2.3p

2 篇文章 0 订阅
1 篇文章 0 订阅

mybatis-plus 2.3

1.简介

Mybatis 增强工具包 - 只做增强不做改变,简化CRUD操作

2. 优点

  • 无侵入:Mybatis-Plus 在 Mybatis 的基础上进行扩展,只做增强不做改变,引入 Mybatis-Plus 不会对您现有的 Mybatis 构架产生任何影响,而且 MP 支持所有 Mybatis 原生的特性
  • 依赖少:仅仅依赖 Mybatis 以及 Mybatis-Spring
  • 损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作
  • 预防Sql注入:内置Sql注入剥离器,有效预防Sql注入攻击
  • 通用CRUD操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 多种主键策略:支持多达4种主键策略(内含分布式唯一ID生成器),可自由配置,完美解决主键问题
  • 支持热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
  • 支持ActiveRecord:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可实现基本 CRUD 操作
  • 支持代码生成:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用(P.S. 比 Mybatis 官方的 Generator 更加强大!)
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 支持关键词自动转义:支持数据库关键词(order、key…)自动转义,还可自定义关键词
  • 内置分页插件:基于Mybatis物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于写基本List查询
  • 内置性能分析插件:可输出Sql语句以及其执行时间,建议开发测试时启用该功能,能有效解决慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,预防误操作

3. 官方文档

中文

4. 快速入门

4.1 配置

Maven依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>2.3</version>
</dependency>

applicationContext.xml中配置

​ 取代了原本的SqlSession,使用的是com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean

<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
    <!-- 导入数据源 -->
    <property name="dataSource" ref="dataSource"></property>
    <!-- 配置实体类中的别名 -->
    <property name="typeAliasesPackage" value="com.entity"></property>
    <!-- 引入MP的全局策略 -->
    <property name="globalConfig" ref="globalConfiguration"></property>
    <!-- 配置xml文件 -->
    <property name="mapperLocations">
        <list>
            <value>classpath:mapper/*-mapper.xml</value>
        </list>
    </property>
</bean>

mybatis-plus全局策略文件 , 需要使用就要在sqlsessionactory中给globalConfing中注入全局策略文件

<!-- 创建MP的全局策略文件 -->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    <property name="dbColumnUnderline" value="true"></property>
    <!-- 全局主键生成策略-->
    <property name="idType" value="0"></property>
    <!-- 全局表前缀策略-->
    <property name="tablePrefix" value="tbl_"></property>
</bean>

4.2 编写代码

写一个测试代码

创建实体类User 和对应数据库表

private int id;
private String name;
private int age;
private String phone;

创建原始 Mapper 类并继承通用 BaseMapper

​ 创建Mapper类时 必须要先在applicationContext.xml 中创建接口或注解创建映射器

<!-- MapperScannerConfigurer 支持过滤由指定的创建接口或注解创建映射器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--把dao层下面的所以接口加入到ioc容器,并且以自身的名称首字母小写配置一个别名-->
    <property name="basePackage" value="com.dao"></property>
</bean>
public interface UserDao extends BaseMapper<User> {

}
4.2.1 测试新增方法
public class UserService {
    ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper usermapper= (UserMapper)con.getBean(UserMapper.class);
    AddressMapper addressMapper = (AddressMapper)con.getBean(AddressMapper.class);


    /**
     * 测试 MP-insert()
     *      插入一条记录
     */
    @Test
    public void insertTest01(){
        User user = new User();
        user.setName("zs");
        user.setPwd("123456");
        user.setAddid(1);
        Integer row = usermapper.insert(user);

        //判断是否成功
        if(row>0){
            System.out.println("执行成功");
        }
        System.out.println("受影响行数:"+row);
    }

    /**
     * 测试 MP-insertAllColumn()
     *      插入一条记录
     */
    @Test
    public void insertTest02(){
        User user = new User();
        user.setName("ls");
        user.setPwd("123456");
        user.setAddid(1);
        Integer row = usermapper.insertAllColumn(user);

        //判断是否成功
        if(row>0){
            System.out.println("执行成功");
        }
        System.out.println("受影响行数:"+row);
    }
}
4.2.2 删除方法 - 结合构造器
/**
     * 测试 MP-delete()     可以用构造器
     *      根据 entity 条件,删除记录
     *              需要一个new EntityWrapper<T>构造器 参数 后面加加上就是条件  可以跟N的条件
     *              .eq("数据库表的字段","参数值") 第一个参数是  数据库表的字段,第二个参数是  字段里的值
     */
@Test
public void deleteUserTest01(){
    //第一种写法
    //        EntityWrapper<User> ew = new EntityWrapper<User>();
    //        ew.eq("id", "1");
    //        ew.eq("name","zs");
    //        Integer row = usermapper.delete(ew);

    //第二种写法
    Integer row = usermapper.delete(new EntityWrapper<User>()
                                    .eq("id", "1")
                                   );

    //判断是否成功
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}

/**
     * 测试 MP - deleteBatchIds()
     *      删除(根据ID 批量删除)
     *          idList – 主键ID列表
     *              是一个List集合     数组不行
     */
@Test
public void deleteUserTest02(){
    //        int[] arr = new int[]{1,2};
    List<Integer> userids = new ArrayList<Integer>();
    userids.add(2);
    userids.add(3);
    Integer row = usermapper.deleteBatchIds(userids);

    //判断是否成功
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}

/**
     * 测试 MP - deleteById()
     *      根据 ID 删除
     */
@Test
public void deleteUserTest03(){
    Integer row = usermapper.deleteById(2);

    //判断是否成功
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}

/**
     * 测试 MP - deleteByMap()
     *      根据 Map 条件,删除记录
     *              key -- 表的字段
     *              value -- 参数值
     */
@Test
public void deleteUserTest04(){
    Map<String,Object> map = new HashMap<String, Object>();
    map.put("id","1");
    map.put("name","zs");
    Integer row = usermapper.deleteByMap(map);

    //判断是否成功
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}
4.2.3 修改方法 - 结合构造器
/**
* 测试 MP - update()     可以用构造器
*      根据 whereEntity 条件,更新记录
*      第一个参数entity – 实体对象       第二个参数(修改的条件)wrapper – 实体对象封装操作类(可以为 null)
*          执行是会判断entity实体类中的每个属性值是否为空,为空则不作改变
*/
@Test
public void updateTest01(){
    User user = new User();
    user.setName("测试");
    //        user.setPwd("789");
    user.setAddid(2);
    //创建一个wrapper实体对象
    EntityWrapper<User> ew = new EntityWrapper<User>();
    ew.eq("id","2");
    Integer row = usermapper.update(user, ew);

    //构造器
    //        Integer row = usermapper.update(user,
    //                new EntityWrapper<User>().eq("id","2")
    //        );

    //判断执行结果
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}

/**
* 测试 MP- updateById()
*          根据主键id进行修改,定义entity实体对象时要给主键id赋值,没有给主键id赋值也会执行成功,但是数据库数据不会有改变
*      插入数据时,会根据实体类的每个属性进行非空判断,只有非空的属性所对应的字段才会出现在SQL语句中。
*/
@Test
public void updateTest02(){
    User user = new User();
    user.setId(5);        //不给id赋值正常执行(不报错),但是数据不会改变
    user.setName("测试根据id修改");
    //        user.setPwd("789");
    user.setAddid(2);

    //执行的时候会判断user对象中的所有属性是否为空,如果为空则为空的数据就不会发生任改变
    Integer row = usermapper.updateById(user);

    //验证执行是否成功
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}

/**
* 测试 MP - updateAllColumnById()
*      根据 ID 修改     不给id时 也不会对数据库数组有改变
*      插入数据时,不管属性是否为空,属性所对应的字段都会出现在SQL语句中。
*/
@Test
public void updateTest03(){
    User user = new User();
    user.setId(3);        //不给id赋值正常执行(不报错),但是数据不会改变
    user.setName("updateAllColumnById测试2");
    //        user.setPwd("789");     //插入数据时,不管属性是否为空,属性所对应的字段都会出现在SQL语句中。
    user.setAddid(2);

    //执行的时候会判断user对象中的所有属性是否有为空的属性,如果为空则 为空的属性值就会在数据库中直接改为空(null)
    Integer row = usermapper.updateAllColumnById(user);

    //验证执行是否成功
    if(row>0){
        System.out.println("执行成功");
    }
    System.out.println("受影响行数:"+row);
}

/**
     * 测试 MP - updateForSet
     *      根据 whereEntity 条件,更新记录
     *      (知道有这么个东西,不会用)
     */
@Test
public void updateTest04(){
    usermapper.updateForSet("ceshi",new EntityWrapper<User>());
}

4.2.4 查询方法 - 结合构造器 - 分页
 /**
     * 查询测试 -- selectById()
     *      根据 ID 查询
     *      id – 主键ID
     */
@Test
public void selectTest01(){
    User user = usermapper.selectById(2);

    //验证是否查询到数据
    if(user != null){
        System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
    }
}

/**
     * 查询测试 -- selectBatchIds()
     *      查询(根据ID 批量查询)
     *         idList – 主键ID列表     List集合
     */
@Test
public void selectTest02(){
    List<Integer> idList = new ArrayList<Integer>();
    idList.add(2);
    idList.add(3);
    idList.add(4);
    List<User> list = usermapper.selectBatchIds(idList);

    //遍历查询的所有数据
    for (User user : list) {
        System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
    }
}


/**
     * 查询测试  -- selectByMap()
     *      查询(根据  Map 多条件查询)
     *      columnMap – 表字段 map 对象
     *          key     表中的字段名
     *          value   参数值
     */
@Test
public void selectTest03(){
    Map<String,Object> map = new HashMap<String, Object>();
    map.put("id","2");
    map.put("name","测试");
    List<User> list = usermapper.selectByMap(map);

    //遍历查询的所有数据
    for (User user : list) {
        System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
    }
}

/**
     * 查询测试  -- selectCount()
     *      根据 Wrapper 条件,查询总记录数
     */
@Test
public void selectTest04(){

    Integer count = usermapper.selectCount(new EntityWrapper<User>()
                                           .like("name","小")
                                          );

    System.out.println("根据like模糊查询的总数是:"+count);
}

/**
     * 查询测试  -- selectList()
     *      根据 构造器EntityWrapper 多条件,查询全部记录
     *          不给参数默认查询全部
     *
     */
@Test
public void selectTest05(){
    //        Integer[] userid = new Integer[]{2,3,4};
    //        EntityWrapper<User> ew = new EntityWrapper<User>();
    //        ew.in("id",userid); //in查询多种参数

    List<User> list = usermapper.selectList(null);

    //遍历查询的所有数据
    for (User user : list) {
        System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
    }
}

/**
     * 测试 --- selectMaps()
     *      根据 Wrapper 条件,查询全部记录
     *          可以为 null  查询全部
     *      return: List<Map<String, Object>>
     *
     */
@Test
public void selectTest06(){
    EntityWrapper<User> ew = new EntityWrapper<User>();
    ew.ge("id","4");
    List<Map<String, Object>> maps = usermapper.selectMaps(ew); //带条件查询

    //        List<Map<String, Object>> maps = usermapper.selectMaps(null);     //无条件查询

    //遍历结果集
    for (Map<String, Object> map : maps) {
        //key       .keySet
        //value     .values()
        //            for (Object s : map.keySet()) {
        //                System.out.print(s);
        //            }

        for (Map.Entry<String, Object> entr : map.entrySet()) {
            System  .out.println(entr.getKey()+":"+entr.getValue());
        }
        System.out.println();
    }
}

/**
     * 测试查询  --  selectObjs()
     *      根据 Wrapper 条件,查询全部记录
     *          注意: 只返回第一个字段的值
     */
@Test
public void selectTest08(){
    EntityWrapper<User> ew = new EntityWrapper<User>();
    ew.eq("id","2");
    List<Object> list = usermapper.selectObjs(null);

    for (Object o : list) {
        System.out.println(o);
    }
}

/**
     * 测试查询  --- selectOne()
     *      根据 entity 条件,查询一条记录
     *      实体类中的   int类型的值必须要赋值,如果不赋值则默认是0,因此数据库中对于的值也必须要是0(否则报错,查不到对于的数据)
     *                      要么关闭单独关闭数据库映射,但是这样也拿不到值
     *                  String 类型的值为默认值null的话就不根据此字段查询
     */
@Test
public void selectTest09(){
    User user1 = new User();
    user1.setId(2);
    //        user1.setName("测试");
    user1.setAddid(1);
    //        user1.setPwd(null);
    User user = usermapper.selectOne(user1);
    System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
}

分页查询方法

/**
     * 查询测试 -- selectMapsPage()
     *      根据 Wrapper 条件,查询全部记录(并翻页)
     *      rowBounds – 分页查询条件(可以为 RowBounds.DEFAULT)
     *      wrapper – 实体对象封装操作类 (查询条件)
     */
@Test
public void selectTest07(){
    Page page = new Page(3,2);
    List<Map<String, Object>> maps = usermapper.selectMapsPage(page, null);

    //遍历结果集
    for (Map<String, Object> map : maps) {
        //key       .keySet
        //value     .values()
        //            for (Object s : map.keySet()) {
        //                System.out.print(s);
        //            }

        for (Map.Entry<String, Object> entr : map.entrySet()) {
            System  .out.println(entr.getKey()+":"+entr.getValue());
        }
        System.out.println();
    }
}

/**
     * 测试查询 -- selectPage()
     *      根据 entity 条件,查询全部记录(并翻页)
     *        rowBounds – 分页查询的条件(可以为 RowBounds.DEFAULT  查询全部)
     *              选创建一个page对象 或者直接 在第一个参数中 new
     *              current 是第几页开始      底层是从0开始
     *        wrapper – 实体对象封装操作类(可以为 null
     */
@Test
public void selectTest010(){
    Page page = new Page(2,3);
    List<User> list = usermapper.selectPage(page, null);
    System.out.println("总条数:"+page.getTotal());
    System.out.println("当前页码:"+page.getCurrent());
    System.out.println("总页码:"+page.getPages());
    System.out.println("每页显示的条数:"+page.getSize());
    System.out.println("是否有上一页:"+page.hasPrevious());
    System.out.println("是否有下一页:"+page.hasNext());
    for (User user : list) {
        System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
    }
}

4.3 常用注解

4.3.1 @TableName(“表名”)

当表名为 mp_user 时,在不改变 实体类的名字的情况下,通过添加 @TableName(“表名mp_user”)的方式来指定对应的数据库表名,以此解决在不编写sql语句的情况下,实体类的名字与数据库表名不一致而导致无法进行表操作的问题。

属性类型必须指定默认值描述
valueString“”表名
schemaString“”schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)
resultMapString“”xml 中 resultMap 的 id
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入)
excludePropertyString[]{}需要排除的属性名(@since 3.3.1)
@TableName("mp_user") //此注解用于标识当前实体类所对应的表,编译时生效
public class User{
	
        .....................
}
4.3.2 @TableField(“表字段名”)

使用 @TableField(“name”)来直接指定 user 实体类中某一个属性所对应的数据库表中的哪一列

​ 常用的有 exist = false/true 是否和数据库表字段发生映射

属性类型必须指定默认值描述
valueString“”数据库字段名
elString“”映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
existbooleantrue是否为数据库表字段
conditionString“”字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)
updateString“”字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)
insertStrategyEnumNDEFAULT举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategyEnumNDEFAULT举例:IGNORED: update table_a set column=#{columnProperty}
whereStrategyEnumNDEFAULT举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC类型 (该默认值不代表会按照该值生效)
typeHandlerClass<? extends TypeHandler>UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
numericScaleString“”指定小数点后保留的位数
private Long id;
//用户名
@TableField("name")//当前注解用于指定属性对应的表字段
private String username;
4.3.3 @TableId

当前注解用于标注 javabean 中哪个字段是 主键 id

属性类型必须指定默认值描述
valueString“”主键字段名
typeEnumIdType.NONE主键类型
//主键
@TableId //主键策略
private Long id;

4.4 ActiveRecord 模式

AR模式的使用需要满足两个条件,如下:

条件1:必须存在对应的原始mapper并继承Model<User>泛型类,并配置相应类注解,

public class User extends Model<User>{

}

条件2: 在 mapper 接口 中要 继承 BaseMapper<Object.class> 泛型类

package com.mp.dao;
 
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mp.entity.User;
 
public interface UserMapper extends BaseMapper<User>{
	
}

测试使用

/**
* 测试 mybatisplus AR模式
*/
@Test
public void modle(){
    User user1 = new User();
    List<User> list = user1.selectAll();
    for (User user : list) {
        System.out.println(user.getId()+"--"+user.getName()+"--"+user.getPwd()+"--"+user.getAddid());
    }
}

5. mybatisplus扩展

5.1 逻辑删除

说明:

只对自动注入的sql起效:

  • 插入: 不作限制
  • 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
  • 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
  • 删除: 转变为 更新

例如:

  • 删除: update user set deleted=1 where id = 1 and deleted=0
  • 查找: select id,name,deleted from user where deleted=0

字段类型支持说明:

  • 支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
  • 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()

附录:

  • 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
  • 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。
第一步:

applicationContext.xml中的mybatisplus全局策略文件globalConfiguration 中在添加逻辑删除

 <!-- 创建MP的全局策略文件 -->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    ....

    <!-- 逻辑删除 -->
    <property name="sqlInjector" ref="logicSqlInjector"></property>
    <!-- 配置逻辑删除字段 -->
    <property name="logicDeleteValue" value="1"></property>
    <!-- 配置注册的字段 -->
    <property name="logicNotDeleteValue" value="0"></property>

    ....
</bean>

ref引用配置

 <!-- 逻辑删除 -->
<bean id="logicSqlInjector" class="com.baomidou.mybatisplus.mapper.LogicSqlInjector"></bean>
第二步:

实体类字段上加上@tablelogic注解

@TableLogic //逻辑删除注解
private int addid;
第三步:

测试使用

​ 逻辑删除只要是执行了delete删除语句时 mp 就会给你执行update修改语句 修改配置了注解的字段改为配置中预定的值,

​ 而且在配置了逻辑删除后, 在执行mybatisplus的 CRUD 操作都会带一个条件

/**
     * 逻辑删除
     *      删除: 转变为 更新
     */
@Test
public void logicDelete(){
    //        Integer integer = usermapper.deleteById(5); //单个删除
    Integer name = usermapper.delete(new EntityWrapper<User>().like("name", "逻辑删除"));  //条件删除
    if(name > 0){
        System.out.println("删除成功");
    }
}

实际执行的sql语句

Time14 ms - ID:com.mapper.UserMapper.delete
Execute SQLUPDATE
       tbl_user 
   SET
       addid=1 
   WHERE
       addid=0 
       AND (
           name LIKE '%逻辑删除%'
       )]

5.2 配置全局共属性默认值

在mp全局策略中添加

 <!-- 全局共属性默认值 -->
 <property name="metaObjectHandler" ref="metaObjectHandler"></property>

ref引用配置

注意这里的class 是自己的创建的类

<!-- 全局公共属性默认值 -->
<bean id="metaObjectHandler" class="com.Handler.MyObjectHandler"></bean>

MyObjectHandler类

​ 需要继承一个 MetaObjectHandler

配置完之后在执行mp的CRUD操作时就会给配置的公共属性附一个默认值

public class MyObjectHandler extends MetaObjectHandler {

    /**
     * 新增时自动注入的值
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        Object ob = getFieldValByName("pwd",metaObject);
        //等于空说明该字段需要附一个默认值,不为空则说明用自定义的值
        if(ob == null){
            //第一个值是需要添加的默认的属性名(实体类中的属性名),第二个参数是默认值,第三个参数metaObject
            setFieldValByName("pwd","公共属性默认值",metaObject);
        }
    }

    /**
     * 修改是自动注入的值
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        Object ob = getFieldValByName("pwd",metaObject);
        //等于空说明该字段需要附一个默认值,不为空则说明用自定义的值
        if(ob == null){
            //第一个值是需要添加的默认的属性名(实体类中的属性名),第二个参数是默认值,第三个参数metaObject
            setFieldValByName("pwd","公共属性默认值",metaObject);
        }
    }
}

5.3 乐观锁

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
使用方法

字段上加上@Version注解

@Version
private Integer version;

说明:

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity
  • 仅支持 updateById(id)update(entity, wrapper) 方法
  • update(entity, wrapper) 方法下, wrapper 不能复用!!!

sqlSessionFactoryBean中给plugins注入值

<property name="plugins">
    <list>
		....	 <!-- 这里还有其他插件-->
        <!-- 注册乐观锁-->
        <bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"></bean>
    </list>
</property>

测试使用

​ 只对updateById方法起作用

/**
* 乐观锁测试    updateById只查询单个值, 乐观锁起作用
*/
@Test
public void versino(){
    User user = new User();
    user.setId(4);
    user.setName("测试乐观锁333");
    user.setVersion(2);
    Integer update = usermapper.updateById(user);
    if(update > 0 ){
        System.out.println("修改成功");
    }
}

/**
* 测试update的乐观锁, update根据条件查询能查出多个值, 不能确定修改某一个值 所有乐观锁没用
*/
@Test
public void version2(){
    User user = new User();
    user.setName("测试乐观锁444");
    usermapper.update(user,new EntityWrapper<User>().eq("id","5").eq("version","0"));
}
Mybatis-plusMyBatis增强工具包,用于简化CRUD操作。该工具包为MyBatis提供了一些高效,有用,即用的功能,使用它可以有效地节省您的开发时间。Mybatis-plus特征与MyBatis完全兼容 启动时自动配置 开箱即用的用于操作数据库的界面 强大而灵活的条件包装器 生成主键的多种策略 Lambda样式的API 全能和高度可定制的代码生成器 自动分页操作 SQL注入防御 支持活动记录 支持可插拔的自定义界面 内置许多有用的扩展Mybatis-plus功能1、单表CURD(简单 + 批量)操作,自动完成(支持 like 比较等查询)。 2、分页插件,Count查询自动或自定义SQL查询。 3、Spring根据不同环境加载不同配置支持(支持typeAliasesPackage通配符扫描)。 【自动生成Entity Mapper Service文件】Mybatis-plusMybatis增强工具包) v3.3.2更新日志分页参数提取,单元测试用例修复 达梦数据库代码生成器表过滤支持 微软数据库代码生成器表过滤支持 修复代码生成器属性字段规则错误 SelectById 支持自定义方法名 修复分页插件获取数据库类型问题 Json转换器空值处理 bugfix(mybatis-plus-generator):SQL类型返回错误问题 调整未知方言异常,自动识别url转换小写匹配. fix: 初始化TableInfo中遇到多个字段有@TableId注解时未能抛出异常的问题 SuperController有Class参数的set方法 增加方法StrategyConfig.setSuperServiceImplClass(java.lang.Class<?>). 代码生成器命名策略调整. 扩展分页缓存key值计算. 去除方法推测,直接访问属性字段. 修正枚举处理器类型不匹配比较. 修改表前缀匹配方式 修改在Mybatis全局配置文件中设置分页插件参数不生效问题 修改在Mybatis全局配置文件中设置分页插件参数不生效问 修复PR未指定解析器的时候引发空指针 增加分页插件limit参数配置 修复指定superEntityClass重复生成父类字段问题 无主键的情况无需导入IdType与TableId包 调整生成BaseResultMap格式 支持lombok模式下选择是否进行链式set生成 修复解析器for update错误 过滤PG约束列(只留下主键约束) 增加生成器禁用模板生成 fix(kotlin): 修复动态表名BUG,最大努力替换表名 修复PG约束生成重复属性字段问题 fix(kotlin): 将LambdaUtils中缓存的key改为String 代码生成器增加数据库关键字处理接口 fix github/issues/2454 支持注解可继承 新增 AES 加密数据库用户名密码 优化方法入参泛型,支持更多类型 修复代码生成器开启移除is前缀生成实体缺少包导入 fixed github issues/2470Mybatis-plus截图
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立勤.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值