,自己设计一组两事务的并发控制运行过程,看事务的运行状态和结果,分析原因

用sql语句,有哪位大神能举个例子吗。如果能给过程,感激不尽谢谢谢谢!谢谢谢谢谢谢谢谢谢

用银行转账的列子非常好,同一个表,一个加一个减。通过事务实现。

可以, 我把我以前测试过的代码整理一下

技术springboot+mybatis-plus+mysql

这是前端时间我测试自旋锁的代码,有点乱

实体对应数据库中的表cs

package com.xm.officialaccounts.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 lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author 
 * @date created in 9:26 2021/5/8
 */
@Data
@Entity
@Table(name = "cs")
@TableName("cs")
public class compareAndSwap {
    @Id
    @TableId(value = "id")
    String id;

    Integer val;

    @Version
    Integer version;
}

接口

package com.xm.officialaccounts.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.xm.officialaccounts.entity.compareAndSwap;

/**
 * @author 
 * @date created in 9:55 2021/5/8
 */
public interface CsService extends IService<compareAndSwap> {
    public void updateById(String id);

    void selectForUpdate();

    void sub(String id);

    void save();

    compareAndSwap sel();
}

接口实现类,操作数据库的。

@Transactional(rollbackFor = Exception.class)这个注解是开启事物,可以用在类上面(全部)也可以用在具体某个方法上面
package com.xm.officialaccounts.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xm.officialaccounts.entity.compareAndSwap;
import com.xm.officialaccounts.mapper.csMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author 
 * @date created in 9:55 2021/5/8
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class CsServiceImpl extends ServiceImpl<csMapper, compareAndSwap> implements CsService{
    @Resource
    csMapper csMapper;

    @Override
    public void updateById(String id){
        String key = "cs" +id;
        synchronized (key.intern()){
            compareAndSwap cs = csMapper.selectById(id);
            System.out.println("初始id:"+id+"的version"+ cs.getVersion());
            cs.setVal(cs.getVal() + 10);
            int r = csMapper.updateById(cs);
        }
    }

    @Override
    public void selectForUpdate(){
        compareAndSwap cs = csMapper.selectByIdForUpdate(10);
        System.out.println("初始的version"+ cs.getVersion());
        int r = csMapper.update(cs.getId(),cs.getVal() + 10);
        if(r < 1){
            compareAndSwap cs2 = csMapper.selectByIdForUpdate(10);
            System.out.println("Thread:"+Thread.currentThread().getId()+" version错误,使用的version:"+cs.getVersion()+" " +
                    "正确的version:"+cs2.getVersion());
        }else {
            cs = csMapper.selectById(10);
            System.out.println("Thread:"+Thread.currentThread().getId()+" val:"+cs.getVal());
        }
    }

    @Override
    public void sub(String id) {
        csMapper.sub(id);
    }

    @Override
    public void save() {
        compareAndSwap cs2 = new compareAndSwap();
        baseMapper.insert(cs2);
        System.out.println(cs2.getId());
    }

    @Override
    public compareAndSwap sel() {
        return baseMapper.selectById("1394927127662084100");
    }
}

controller

代码用了线程池,开启多个线程。启动后,在浏览器中或者postman输入localhost:8080/cs/id,这个id是参数,你数据库中的id

package com.xm.officialaccounts.controller;

import com.xm.officialaccounts.entity.compareAndSwap;
import com.xm.officialaccounts.service.CsService;
import com.xm.officialaccounts.service.CsServiceImpl;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author lichao
 * @date created in 9:59 2021/5/8
 */
@RestController
public class testCompareAndSwapLock{

    @Resource
    CsService csService;

    @GetMapping("/sel")
    public Object sel(){
        return csService.sel();
    }


    @GetMapping("/cs")
    public void test(@RequestParam(required = false) String id){
        thr(csService,id);
    }

    public void thr(CsService csService,String id) {
        ExecutorService pool = new ThreadPoolExecutor(50,2000,2000, TimeUnit.MILLISECONDS,
                new SynchronousQueue<Runnable>(), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        for(int i=0;i<2000;i++) {
            pool.execute(new ThreadTask(csService,id));
        }

    }

    static class ThreadTask implements Runnable{
        CsService csService;
        String id;
        public ThreadTask(CsService csService,String id) {
            this.csService = csService;
            this.id = id;
        }
        @Override
        public void run(){
            csService.updateById(id);
        }
    }
}

配置文件

server.port=8080
#数据库相关配置
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8\
  &useSSL=false&autoReconnect=true
spring.datasource.username=root
spring.datasource.password=root

pom.xml依赖 maven管理

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xm</groupId>
    <artifactId>officialaccounts</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>officialaccounts</name>
    <description>official accounts project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.38</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>javax.persistence-api</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.5.15</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
CsServiceImpl这个里面的updateById方法我加锁了,是线程安全的

你可以改成下面这样试试

public void updateById(String id){
            // 没有加锁所以就可能读到修改前的,另外一个线程也在修改就错了
            compareAndSwap cs = csMapper.selectById(id);
            System.out.println("初始id:"+id+"的version"+ cs.getVersion());
            cs.setVal(cs.getVal() + 10);
            int r = csMapper.updateById(cs);
        
    }

另外如果是来多个线程去执行这样的,在xml当中定义的sql,update table set val = val +10 where id = ?,经过我测试是正确的,update是会加锁的

满意的话右上角采纳

您好,我是有问必答小助手,您的问题已经有小伙伴解答了,您看下是否解决,可以追评进行沟通哦~

如果有您比较满意的答案 / 帮您提供解决思路的答案,可以点击【采纳】按钮,给回答的小伙伴一些鼓励哦~~

ps:问答VIP仅需29元,即可享受5次/月 有问必答服务,了解详情>>>https://vip.csdn.net/askvip?utm_source=1146287632