MybatisPlus乐观锁











代码片段

java 复制代码
TestOneMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hk.mapper.TestOneMapper">
    <select id="query" resultType="com.hk.entity.TestOneInfo">
        select * from test_testone
    </select>
    <select id="queryList" resultType="com.hk.entity.TestOneInfo">
        select * from test_testone
        ${ew.customSqlSegment}
    </select>
</mapper>



TestOneInfo.java

package com.hk.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.Version;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

@Data
@TableName("test_testone")
public class TestOneInfo implements Serializable{
	@TableId(type = IdType.ASSIGN_ID)
	private String id = null;
	private String name = null;
	@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	private Date createTime = new Date();
	private String createId = null;
	@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	private Date updateTime = null;
	private String updateId = null;
	@Version
	private Long version = 0L;
}


TestOneMapper.java

package com.hk.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.hk.entity.TestOneInfo;
import org.apache.ibatis.annotations.Param;

public interface TestOneMapper extends BaseMapper<TestOneInfo> {
    public IPage<TestOneInfo> queryList(IPage<TestOneInfo> page ,
                                        @Param(Constants.WRAPPER) Wrapper<TestOneInfo> wrapper);
}


ITestOneService.java

package com.hk.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hk.entity.TestOneInfo;
import com.hk.entity.TestTwoInfo;

public interface ITestOneService extends IService<TestOneInfo> {
    boolean save(TestOneInfo t);
    TestOneInfo get(String id) throws Exception;
    boolean delete(TestOneInfo t) throws Exception;
    boolean deleteById(String id) throws Exception;

    /**
     * 操作本表并通过Service操作第二张表,代码设置除0操作,检查两张表上的事务一致性
     * @return
     * @throws Exception
     */
    boolean testTx1() throws Exception;

    /**
     * testTx2,TestTx3分别操作表1和表2,它们同在一个Service实现类上
     * 检查两张表上的事务一致性
     * @return
     * @throws Exception
     */
    boolean testTx2(TestOneInfo t) throws Exception;
    boolean testTx3(TestTwoInfo t) throws Exception;

    /**
     * testTx4是公共方法,其中调用私有方法testTx5,两个方法分别操作两个表,
     * 代码抛出异常,检查两张表上的事务一致性
     * @param t
     * @return
     * @throws Exception
     */
    boolean testTx4(TestOneInfo t) throws Exception;

    /**
     * 根据数据库列定制Where条件,分页查询
     * @param pageNo 页码
     * @param pageSize 每页显示记录数
     * @param name 查询列
     * @param orderColumn 排序列
     * @param order 升序或降序,其值为CommonEnum.ASC或CommonEnum.DESC
     * @return
     * @throws Exception
     */
    IPage<TestOneInfo> queryName(Integer pageNo, Integer pageSize,String name,
                                    String orderColumn, String order)
            throws Exception;

    /**
     * 根据数据库列定制Where条件,分页查询Mapper中定义的方法
     * @param pageNo 页码
     * @param pageSize 每页显示记录数
     * @param orderColumn 排序列
     * @param order 升序或降序,其值为CommonEnum.ASC或CommonEnum.DESC
     * @param queryWrapper 查询条件封装类
     * @return
     * @throws Exception
     */
    IPage<TestOneInfo> queryMethod(Integer pageNo, Integer pageSize,
               String orderColumn, String order,
               QueryWrapper<TestOneInfo> queryWrapper)
            throws Exception;
}


TestOneServiceImpl.java

package com.hk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hk.entity.TestOneInfo;
import com.hk.entity.TestTwoInfo;
import com.hk.mapper.TestOneMapper;
import com.hk.service.ITestOneService;
import com.hk.service.ITestTwoService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@Transactional(readOnly=false,rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public class TestOneServiceImpl extends ServiceImpl<TestOneMapper, TestOneInfo>
        implements ITestOneService
{
    @Autowired
    private ITestTwoService testTwoService;
    @Autowired
    private TestOneMapper testOneMapper;

    @Override
    public boolean save(TestOneInfo t) {
        try
        {
            return super.save(t);
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public TestOneInfo get(String id) throws Exception {
        try
        {
            return super.getById(id);
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public boolean delete(TestOneInfo t) throws Exception {
        try
        {
            return super.removeById(t.getId());
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public boolean deleteById(String id) throws Exception {
        try
        {
            return super.removeById(id);
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    /**
     * 测试回滚两个保存方法,其中一个方法是另外服务实例的方法
     * @return
     * @throws Exception
     */
    @Override
    public boolean testTx1() throws Exception {
        try
        {
            TestOneInfo one = new TestOneInfo();
            one.setId("1");
            one.setName("TestOne");
            save(one);
            TestTwoInfo two = new TestTwoInfo();
            two.setId("2");
            two.setName("TestTwo");
            testTwoService.save(two);
            int i=1/0;
            return false;
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    /**
     * 测试回滚两个保存方法,其中一个方法是调用另外服务实例中的方法
     * @param t
     * @return
     * @throws Exception
     */
    @Override
    public boolean testTx2(TestOneInfo t) throws Exception {
        try
        {
            save(t);
            TestTwoInfo two = new TestTwoInfo();
            two.setId("2");
            two.setName("TestTwo");
            testTx3(two);
            int i=1/0;
            return false;
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public boolean testTx3(TestTwoInfo t) throws Exception {
        try
        {
            testTwoService.save(t);
            return false;
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    /**
     * 测试回滚两个保存方法,其中一个方法是私有方法
     * @param t
     * @return
     * @throws Exception
     */
    @Override
    public boolean testTx4(TestOneInfo t) throws Exception {
        try
        {
            save(t);
            TestTwoInfo two = new TestTwoInfo();
            two.setId("2");
            two.setName("TestTwo");
            testTx5(two);
            int i=1/0;
            return false;
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    private boolean testTx5(TestTwoInfo t) throws Exception {
        try
        {
            testTwoService.save(t);
            return false;
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public IPage<TestOneInfo> queryName(Integer pageNo, Integer pageSize,
            String name, String orderColumn, String order) throws Exception
    {
        try
        {
            Page<TestOneInfo> p = new Page<TestOneInfo>(pageNo, pageSize);
            QueryWrapper wrapper = new QueryWrapper<TestOneInfo>();
            wrapper.like("name",name);
            return page(p,wrapper);
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

    @Override
    public IPage<TestOneInfo> queryMethod(Integer pageNo, Integer pageSize, String orderColumn, String order, QueryWrapper<TestOneInfo> queryWrapper) throws Exception {
        try
        {
            Page<TestOneInfo> p = new Page<TestOneInfo>(pageNo, pageSize);
            IPage<TestOneInfo> pageList = testOneMapper.queryList(p,queryWrapper);
            return pageList;
        }
        catch(Exception e)
        {
            log.error(e.getMessage(),e);
            throw e;
        }
    }

}


OptimisticLockTest.java

package com.hk.user;

import com.hk.Starter;
import com.hk.entity.TestOneInfo;
import com.hk.service.ITestOneService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,classes = Starter.class)
public class OptimisticLockTest {
    @Autowired
    private ITestOneService testOneServ;

    /**
     * 使用默认数据源,测试Mybatis乐观锁控制
     * @throws Exception
     */
    @Test
    public void testOptimisticLock() throws Exception {
        List<TestOneInfo> lst = testOneServ.list();
        for(TestOneInfo t:lst)
            testOneServ.delete(t);
        TestOneInfo one = new TestOneInfo();
        one.setId("1");
        one.setName("testone1");
        testOneServ.save(one);

        TestOneInfo saveOne = testOneServ.get("1");
        saveOne.setName("testone1-saveonce"+Math.random());
        testOneServ.saveOrUpdate(saveOne);
        //保存一次后检查版本是否变为1
        saveOne = testOneServ.get("1");
        System.out.println("saveOne.version========="+saveOne.getVersion());
        Assert.isTrue(saveOne.getVersion() == 1);

        //保存版本为0的对象,捕捉乐观锁异常
        try {
            //此时one版本为0,应该保存失败
            boolean b = testOneServ.saveOrUpdate(one);
            System.out.println("saveOne.b========="+b);
            Assert.isTrue(b,"数据记录版本冲突");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}
相关推荐
G探险者2 小时前
如何找到那些慢 SQL
java
迈巴赫车主2 小时前
错位排序算法
开发语言·数据结构·算法·排序算法
zzb15802 小时前
Agent记忆与检索
java·人工智能·python·学习·ai
野犬寒鸦2 小时前
Redis复习记录Day03
服务器·redis·后端·面试·bootstrap·mybatis
羊小猪~~2 小时前
【QT】-- 模型与视图简介
开发语言·数据库·c++·后端·qt·前端框架·个人开发
叶微信2 小时前
Qt相关面试题
开发语言·qt
种时光的人2 小时前
Java+AI 无缝衔接:Spring AI 聊天模型入门到精通
java·人工智能·spring·ai·spring ai
淼淼爱喝水2 小时前
OpenEuler 系统下 Ansible 环境部署与连通性测试完整步骤
linux·开发语言·php·openeuler
Memory_荒年3 小时前
Dubbo面试通关秘籍:从“小白”到“源码大神”的终极指南
java·后端·dubbo