原创转载请注明出处: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. 字符串(一):char 数组

    字符串使用方法整理 系列: 字符串(一):char 数组 字符串(二):string 1. 声明 如下是一个例子(=> 表示表达式等价): char a[20] = "abcd&quo ...

  2. HTML中<input>和<textarea>的区别

    在HTML中有两种方式表达文本框 一个是<input>元素的单行文本框 一种是<textarea>的多行文本框. <input>元素: 1.一定要指定type的值为 ...

  3. (转)Installing Cloudera Manager and CDH

    转:https://blog.csdn.net/qq_26222859/article/details/79976506 译自官网: Installing Cloudera Manager and C ...

  4. Docker容器日常操作命令

    在Docker的运用中,从下载镜像,启动容器,在容器中输入命令来运行程序,这些命令都是手工一条条往里输入的,无法重复利用,而且效率很低.所以就需要一 种文件或脚本,我们把想执行的操作以命令的方式写入其 ...

  5. Dos.ORM(原Hxj.Data)- 目录、介绍

    引言: Dos.ORM(原Hxj.Data)于2009年发布.2015年正式开源,该组件已在数百个成熟项目中应用,是目前国内用户量最大.最活跃.最完善的国产ORM.初期开发过程中参考了NBear与My ...

  6. UML 类图快速入门

    UML 图形 官方定义 UML 类图(Class Diagram) UML 时序图(Sequence Diagram) 领域 UML 类图和实现 UML 类图 领域 UML 类图 实现 UML 类图 ...

  7. Unity3D移动端电量与wifi信号的获取

    移动端游戏中无法看到电量与wifi信号对于玩家来说是很困扰的事. 关于这个问题安卓与iOS有不同的方法 电量 安卓 安卓获取电量有两种方法,一种是读取安卓手机里的一个文件,一种是利用安卓与Unity互 ...

  8. U盘修复教程--使用量产工具和芯片检测工具

    U盘修复教程(金士顿DT101) 本教程使用量产工具(量产可理解为强制恢复出厂设置),量产有风险(U盘彻底报废),根据教程所造成所有损失均与本文作者无关. ·第一步:下载ChipGenius_v4_0 ...

  9. File类的相关方法

    java.io.File类 文件和路径名的抽象表达形式 java把电脑中的文件和文件夹(目录)封装了一个File类,我们可以使用File类对文件和文件夹进行如下操作 创建一个文件/文件夹 删除 获取 ...

  10. java虚拟机笔记-1

    java虚拟机学习笔记 Java技术的核心就是Java虚拟机,因为所有的Java程序都在虚拟机上运行.Java程序的运行需要Java虚拟机.Java API和Java Class文件的配合.Java虚 ...