MyBatisPlus —— 5、插件

目录

1、分页插件

1.1、添加配置类

1.2、测试

2、自定义分页

2.1、在 mapper 接口中定义方法

2.2、在 mapper 对应的 xml 配置文件编写 SQL

2.2.1、开启类型别名

2.2.2、在 mapper 对应的 xml 配置文件编写 SQL

2.3、测试

3、乐观锁

3.1、场景

3.2、乐观锁与悲观锁

3.3、模拟修改中途

3.3.1、添加表及测试数据

3.3.2、创建实体类

3.3.3、添加 mapper 接口

3.3.4、乐观锁实现流程

3.3.5、MyBatisPlus 实现乐观锁

        3.3.5.1、实体类对应属性添加 @Version 注解

        3.3.5.2、在配置类添加乐观锁插件

        3.3.5.3、测试

        3.3.5.4、优化测试:使小王修改失败后重新修改 


1、分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

1.1、添加配置类

@Configuration
@MapperScan("com.zyj.mybatisplus.mapper") //扫描mapper接口所在的包,也可以在对应的mapper接口添加@Mapper注解,就不用写这句
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

1.2、测试

测试方法:

@SpringBootTest
public class MyBatisPlusPluginsTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testPage(){
        Page<User> page = new Page<>(2, 3);
        // SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
        userMapper.selectPage(page, null);
        System.out.println("getRecords: " + page.getRecords()); // 获取此页的信息
        System.out.println("getPages: " + page.getPages()); // 获取总页数
        System.out.println("getTotal: " + page.getTotal()); // 获取总的记录数
        System.out.println("hasNext: " + page.hasNext()); // 是否有下一页
        System.out.println("hasPrevious: " + page.hasPrevious()); // 是否有上一页
    }

}

输出结果:

==>  Preparing: SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0
==> Parameters: 
<==    Columns: total
<==        Row: 6
<==      Total: 1
==>  Preparing: SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
==> Parameters: 3(Long), 3(Long)
<==    Columns: id, name, age, email, is_deleted
<==        Row: 4, 小明, 21, [email protected], 0
<==        Row: 5, Billie, 24, [email protected], 0
<==        Row: 9, 小红, null, [email protected], 0
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7fd8c559]
getRecords: [User(id=4, name=小明, age=21, [email protected], isDeleted=0), User(id=5, name=Billie, age=24, [email protected], isDeleted=0), User(id=9, name=小红, age=null, [email protected], isDeleted=0)]
getPages: 2
getTotal: 6
hasNext: false
hasPrevious: true

2、自定义分页

2.1、在 mapper 接口中定义方法

注:若使用 MyBatis-Plus 提供的分页对象 Page,则 Page 对象必须位于第一个参数的位置

    /**
     * 通过年龄查询用户信息并分页
     * @param page MyBatis-Plus提供的分页对象,必须位于第一个参数的位置
     * @param age
     * @return
     */
    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);

2.2、在 mapper 对应的 xml 配置文件编写 SQL

2.2.1、开启类型别名

在 application.yml 中开启类型别名

mybatis-plus:
  type-aliases-package: com.zyj.mybatisplus.pojo  #设置类型别名所对应的包

2.2.2、在 mapper 对应的 xml 配置文件编写 SQL

    <!-- Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age); -->
    <select id="selectPageVo" resultType="User">
        select uid, user_name, age, email from t_user where is_deleted = 0 and age > #{age}
    </select>

2.3、测试

测试方法:

    @Test
    public void testPageVo(){
        Page<User> page = new Page<>(1, 3);
        userMapper.selectPageVo(page, 20);
        System.out.println("getRecords: " + page.getRecords()); // 获取此页的信息
        System.out.println("getPages: " + page.getPages()); // 获取总页数
        System.out.println("getTotal: " + page.getTotal()); // 获取总的记录数
        System.out.println("hasNext: " + page.hasNext()); // 是否有下一页
        System.out.println("hasPrevious: " + page.hasPrevious()); // 是否有上一页
    }

输出结果:

==>  Preparing: SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0 AND age > ?
==> Parameters: 20(Integer)
<==    Columns: total
<==        Row: 3
<==      Total: 1
==>  Preparing: select uid, user_name, age, email from t_user where is_deleted = 0 and age > ? LIMIT ?
==> Parameters: 20(Integer), 3(Long)
<==    Columns: uid, user_name, age, email
<==        Row: 3, Tom, 28, [email protected]
<==        Row: 4, 小明, 21, [email protected]
<==        Row: 5, Billie, 24, [email protected]
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@772861aa]
getRecords: [User(id=null, name=null, age=28, [email protected], isDeleted=null), User(id=null, name=null, age=21, [email protected], isDeleted=null), User(id=null, name=null, age=24, [email protected], isDeleted=null)]
getPages: 1
getTotal: 3
hasNext: false
hasPrevious: false

3、乐观锁

3.1、场景

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。

此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。

现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1万多。

3.2、乐观锁与悲观锁

上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。

如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元。

3.3、模拟修改中途

3.3.1、添加表及测试数据

CREATE TABLE t_product ( 
	id BIGINT(20) NOT NULL COMMENT '主键ID', 
	NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', 
	price INT(11) DEFAULT 0 COMMENT '价格', 
	VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号', 
	PRIMARY KEY (id)
);

INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人笔记本', 100);

3.3.2、创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;
}

3.3.3、添加 mapper 接口

@Mapper
public interface ProductMapper extends BaseMapper<Product>{
}

3.3.4、乐观锁实现流程

数据库中添加version字段

取出记录时,获取当前version

SELECT id,`name`,price,`version` FROM product WHERE id=1;

更新时,version + 1,如果where语句中的version版本不对,则更新失败

UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1;

3.3.5、MyBatisPlus 实现乐观锁

3.3.5.1、实体类对应属性添加 @Version 注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {

    private Long id;

    private String name;

    private Integer price;

    @Version  // 标识该属性为乐观锁版本号的字段
    private Integer version;
}

3.3.5.2、在配置类添加乐观锁插件

@Configuration
@MapperScan("com.zyj.mybatisplus.mapper") //扫描mapper接口所在的包,也可以在对应的mapper接口添加@Mapper注解,就不用写这句
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

}

3.3.5.3、测试

测试方法:

    @Test
    public void test01(){
        // 小李查询商品价格
        Product productLi = productMapper.selectById(1);
        System.out.println("小李查询到的价格:" + productLi.getPrice());
        // 小王查询商品价格
        Product productWang = productMapper.selectById(1);
        System.out.println("小王查询到的价格:" + productWang.getPrice());
        // 小李将商品价格增加50
        // UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
        productLi.setPrice(productLi.getPrice() + 50);
        productMapper.updateById(productLi);
        // 小王将商品价格减30
        productWang.setPrice(productWang.getPrice() - 30);
        productMapper.updateById(productWang);
        // 老板查询商品价格
        Product productBoss = productMapper.selectById(1);
        System.out.println("老板查询到的价格:" + productBoss.getPrice());
    }

输出结果:

==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 100, 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@41b1f51e]
小李查询到的价格:100
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a583586] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@975629453 wrapping com.mysql.cj.jdbc.ConnectionImpl@709ed6f3] will not be managed by Spring
==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 100, 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a583586]
小王查询到的价格:100
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64d4f7c7] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@927159199 wrapping com.mysql.cj.jdbc.ConnectionImpl@709ed6f3] will not be managed by Spring
==>  Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
==> Parameters: 外星人笔记本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64d4f7c7]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6cd3ad8a] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1964514128 wrapping com.mysql.cj.jdbc.ConnectionImpl@709ed6f3] will not be managed by Spring
==>  Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
==> Parameters: 外星人笔记本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
<==    Updates: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6cd3ad8a]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5f254608] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@787156891 wrapping com.mysql.cj.jdbc.ConnectionImpl@709ed6f3] will not be managed by Spring
==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 150, 1
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5f254608]
老板查询到的价格:150

3.3.5.4、优化测试:使小王修改失败后重新修改 

测试方法:

    @Test
    public void test01(){
        // 小李查询商品价格
        Product productLi = productMapper.selectById(1);
        System.out.println("小李查询到的价格:" + productLi.getPrice());
        // 小王查询商品价格
        Product productWang = productMapper.selectById(1);
        System.out.println("小王查询到的价格:" + productWang.getPrice());
        // 小李将商品价格增加50
        // UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
        productLi.setPrice(productLi.getPrice() + 50);
        productMapper.updateById(productLi);
        // 小王将商品价格减30
        productWang.setPrice(productWang.getPrice() - 30);
        int result = productMapper.updateById(productWang);
        if(result == 0){
            // 若操作失败,重试
            Product productNew = productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice() - 30);
            productMapper.updateById(productNew);
        }
        // 老板查询商品价格
        Product productBoss = productMapper.selectById(1);
        System.out.println("老板查询到的价格:" + productBoss.getPrice());
    }

输出结果:

==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 100, 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3dd818e8]
小李查询到的价格:100
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c26273d] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@976725249 wrapping com.mysql.cj.jdbc.ConnectionImpl@20ab3e3a] will not be managed by Spring
==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 100, 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c26273d]
小王查询到的价格:100
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@268cbb86] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@501855493 wrapping com.mysql.cj.jdbc.ConnectionImpl@20ab3e3a] will not be managed by Spring
==>  Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
==> Parameters: 外星人笔记本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@268cbb86]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@b9a77c8] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@2055276126 wrapping com.mysql.cj.jdbc.ConnectionImpl@20ab3e3a] will not be managed by Spring
==>  Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
==> Parameters: 外星人笔记本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
<==    Updates: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@b9a77c8]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75181b50] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@761533964 wrapping com.mysql.cj.jdbc.ConnectionImpl@20ab3e3a] will not be managed by Spring
==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 150, 1
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@75181b50]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2eeb0f9b] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@454841229 wrapping com.mysql.cj.jdbc.ConnectionImpl@20ab3e3a] will not be managed by Spring
==>  Preparing: UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
==> Parameters: 外星人笔记本(String), 120(Integer), 2(Integer), 1(Long), 1(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2eeb0f9b]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6325f352] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@365211514 wrapping com.mysql.cj.jdbc.ConnectionImpl@20ab3e3a] will not be managed by Spring
==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
==> Parameters: 1(Integer)
<==    Columns: id, name, price, version
<==        Row: 1, 外星人笔记本, 120, 2
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6325f352]
老板查询到的价格:120

猜你喜欢

转载自blog.csdn.net/Mr_zhangyj/article/details/124111265