原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11608581.html

乐观锁适用于读多写少的应用场景 

乐观锁Version图示

Project Directory

Maven Dependency

 <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>HelloSpring</groupId>
<artifactId>org.fool.spring</artifactId>
<version>1.0-SNAPSHOT</version> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.22.RELEASE</version>
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
</exclusion>
</exclusions>
</dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.5</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>sql/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
</project>

application.properties

 server.port=

 spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver mybatis.type-aliases-package=org.fool.spring.model
mybatis.mapper-locations=classpath:mapper/**/*.xml

ddl.sql

 CREATE TABLE `goods` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`state` tinyint(4) unsigned NOT NULL COMMENT '1.正常;2.缺货',
`version` bigint(20) unsigned NOT NULL,
`create_time` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`update_time` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; insert into goods(name, state, version) values('iPhone', 1, 1);
insert into goods(name, state, version) values('iMac', 1, 1);
insert into goods(name, state, version) values('iPad', 1, 1);
insert into goods(name, state, version) values('iWatch', 1, 1);

generatorConfig.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry
location="/Users/${user.name}/.m2/repository/mysql/mysql-connector-java/5.1.48/mysql-connector-java-5.1.48.jar"/> <context id="test" targetRuntime="MyBatis3"> <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/> <commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator> <jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test"
userId="root"
password="123456">
</jdbcConnection> <javaModelGenerator targetPackage="org.fool.spring.model" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator> <javaClientGenerator targetPackage="org.fool.spring.dao.mapper" targetProject="src/main/java"
type="XMLMAPPER">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator> <table tableName="goods" domainObjectName="Goods"
enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false"
selectByExampleQueryId="false">
</table> </context> </generatorConfiguration>

自动生成model和mapper

 mybatis-generator:generate -e

Goods.java

 package org.fool.spring.model;

 import java.util.Date;

 public class Goods {
private Long id; private String name; private Byte state; private Long version; private Date createTime; private Date updateTime; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name == null ? null : name.trim();
} public Byte getState() {
return state;
} public void setState(Byte state) {
this.state = state;
} public Long getVersion() {
return version;
} public void setVersion(Long version) {
this.version = version;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public Date getUpdateTime() {
return updateTime;
} public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", name=").append(name);
sb.append(", state=").append(state);
sb.append(", version=").append(version);
sb.append(", createTime=").append(createTime);
sb.append(", updateTime=").append(updateTime);
sb.append("]");
return sb.toString();
}
}

GoodsMapper.java

 package org.fool.spring.dao.mapper;

 import org.fool.spring.model.Goods;

 public interface GoodsMapper {
int deleteByPrimaryKey(Long id); int insert(Goods record); int insertSelective(Goods record); Goods selectByPrimaryKey(Long id); int updateByPrimaryKeySelective(Goods record); int updateByPrimaryKey(Goods record);
}

GoodsMapper.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="org.fool.spring.dao.mapper.GoodsMapper">
<resultMap id="BaseResultMap" type="org.fool.spring.model.Goods">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="state" jdbcType="TINYINT" property="state" />
<result column="version" jdbcType="BIGINT" property="version" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
</resultMap>
<sql id="Base_Column_List">
id, name, state, version, create_time, update_time
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from goods
where id = #{id,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from goods
where id = #{id,jdbcType=BIGINT}
</delete>
<insert id="insert" parameterType="org.fool.spring.model.Goods">
insert into goods (id, name, state,
version, create_time, update_time
)
values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{state,jdbcType=TINYINT},
#{version,jdbcType=BIGINT}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}
)
</insert>
<insert id="insertSelective" parameterType="org.fool.spring.model.Goods">
insert into goods
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
name,
</if>
<if test="state != null">
state,
</if>
<if test="version != null">
version,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=BIGINT},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="state != null">
#{state,jdbcType=TINYINT},
</if>
<if test="version != null">
#{version,jdbcType=BIGINT},
</if>
<if test="createTime != null">
#{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="org.fool.spring.model.Goods">
update goods
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="state != null">
state = #{state,jdbcType=TINYINT},
</if>
<if test="version != null">
version = #{version,jdbcType=BIGINT},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="org.fool.spring.model.Goods">
update goods
set name = #{name,jdbcType=VARCHAR},
state = #{state,jdbcType=TINYINT},
version = #{version,jdbcType=BIGINT},
create_time = #{createTime,jdbcType=TIMESTAMP},
update_time = #{updateTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
</mapper>

GoodsMapperExt.java

 package org.fool.spring.dao.mapper.extension;

 import org.fool.spring.model.Goods;

 public interface GoodsMapperExt {
int casUpdateByPrimaryKey(Goods goods);
}

GoodsMapperExt.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="org.fool.spring.dao.mapper.extension.GoodsMapperExt">
<resultMap id="BaseResultMap" type="org.fool.spring.model.Goods">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="state" jdbcType="TINYINT" property="state"/>
<result column="version" jdbcType="BIGINT" property="version"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<sql id="Base_Column_List">
id, name, state, version, create_time, update_time
</sql>
<update id="casUpdateByPrimaryKey" parameterType="org.fool.spring.model.Goods">
update goods
set name = #{name,jdbcType=VARCHAR},
state = #{state,jdbcType=TINYINT},
version = version + 1
where id = #{id,jdbcType=BIGINT} and version = #{version,jdbcType=BIGINT}
</update>
</mapper>

Application.java

 package org.fool.spring;

 import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
@MapperScan("org.fool.spring.dao.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

ApplicationTest.java

 package org.fool.spring.test;

 import org.fool.spring.Application;
import org.fool.spring.dao.mapper.GoodsMapper;
import org.fool.spring.dao.mapper.extension.GoodsMapperExt;
import org.fool.spring.model.Goods;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@EnableAutoConfiguration
public class ApplicationTest {
@Autowired
private GoodsMapper goodsMapper; @Autowired
private GoodsMapperExt goodsMapperExt; @Test
public void testSelect() {
Goods result = goodsMapper.selectByPrimaryKey(1L);
assert 1 == result.getId();
} @Test
public void testUpdate() {
Goods goods1 = goodsMapper.selectByPrimaryKey(1L);
Goods goods2 = goodsMapper.selectByPrimaryKey(1L); goods1.setName("iPhone");
goods2.setName("iPhoneXR"); int result1 = goodsMapperExt.casUpdateByPrimaryKey(goods1);
assert 1 == result1;
int result2 = goodsMapperExt.casUpdateByPrimaryKey(goods2);
assert 0 == result2;
}
}

MySQL使用版本号实现乐观锁的更多相关文章

  1. 谈谈mysql的悲观和乐观锁

    悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.之前有写过一篇文章关于并发的处理思路和解决方案,这里我单独将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍一 ...

  2. MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解

    文章出处:https://www.souyunku.com/2018/07/30/mysql/?utm_source=tuicool&utm_medium=referral MySQL/Inn ...

  3. 通过版本号实现乐观锁(MVCC)

    乐观锁大多是基于数据版本记录的机制实现 , 如 , 为每一行数据增加一个整型版本标识(version) , 每次数据更新都把版本号+1 工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本 ...

  4. 使用mysql乐观锁解决并发问题

    案例说明: 银行两操作员同时操作同一账户.比如A.B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户扣除50元,A先提交,B后提交.最后实际账户余额为1000 ...

  5. 【数据库】mysql深入理解乐观锁与悲观锁

    转载:http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时 ...

  6. mysql悲观锁与乐观锁

    简介 数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 用途 乐观锁和悲观锁是并发控制主要采用的技术手段.无论是悲观 ...

  7. MySQL学习(四)深入理解乐观锁与悲观锁

    转载自:http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据 ...

  8. 面试官:小伙子,给我说一下mysql 乐观锁和悲观锁吧

    悲观锁介绍 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中, 将数据处于锁定状态.悲观锁的实现,往往依靠数据库 ...

  9. [数据库锁机制] 深入理解乐观锁、悲观锁以及CAS乐观锁的实现机制原理分析

    前言: 在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数据库都提供了锁机制,并引入了事务隔离级别的概念.数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务 ...

随机推荐

  1. PHP之导出CSV文件

    序言 Q1:什么是csv文件? A1:csv即 comma-separated values ,逗号分隔值.是一种通用的相对简单地文件格式,目前被较为广泛的使用.其最广泛的应用就是用来转移表数据. “ ...

  2. ceph-性能调优

    Ceph 参数性能调优https://blog.csdn.net/changtao381/article/details/49907115这篇文章对我的环境有较大帮助 ceph优化记录 ceph.co ...

  3. Kubernetes 对象管理的三种方式

    Kubernetes 中文文档 1. Kubernetes 对象管理的三种方式对比 Kubernetes 中的对象管理方式,根据对象配置信息的位置不同可以分为两大类: 命令式:对象的参数通过命令指定 ...

  4. C++ bitset的使用

    bitset 一般代替 bool 数组使用,常用于优化空间,因为 bitset 中一个元素只占 1 bit. bitset 的大小在定义使就需要确定.如果想要不定长的 bitset,就需要使用 vec ...

  5. (转载)如何在 Github 上发现优秀的开源项目?

    转载自:传送门 之前发过一系列有关 GitHub 的文章,有同学问了,GitHub 我大概了解了,Git 也差不多会使用了,但是还是搞不清 GitHub 如何帮助我的工作,怎么提升我的工作效率? 问到 ...

  6. jQuery 动态添加、删除css样式

    1.addClass css中: <style type="text/css">       .chColor {background: #267cb7;color:w ...

  7. servlet--禁用浏览器缓存

    禁用浏览器缓存:Cache-Control.pragma.expires response.setHeader("Cache-Control", "no-cache&qu ...

  8. (1)leetcode刷题Python笔记——两数之和

    题目如下: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数 ...

  9. 读取交货单拣配数量PIKMG(转)

    原文链接:https://www.591sap.com/thread-953-1-1.html SAP交货单交货数量在lips中直接读取,但是拣配数量lfimg,只存在vbfa中,且如果基本计量单位和 ...

  10. CentOS vim的使用

    安装vim工具 [root@bogon ~]# yum install -y vim-enhanced 卸载vim工具 [root@bogon ~]# yum remove -y vim* vim常用 ...