步骤

多个进程、多个线程访问共同组件数据库

通过select……for update 访问同一条数据

for update锁定数据,其他线程只能等待

先设计一张表
image.png
打开两个查询窗口

  1. SELECT @@autocommit;

查询事务,如果结果是1,那么就是事务还没有打开
我们需要打开事务,来进行后续的测试

  1. set @@autocommit = 0;

在两个窗口执行这个sql,你会发现第一个执行成功,但是第二个则会提示不成功!

  1. select * from distribute_lock where business_code = 'demo' for update;

只有另一查询commit后,才能执行。

  1. select * from distribute_lock where business_code = 'demo';

而我们执行这条sql,又不会出现锁住的情况。
这是因为for update 只是锁住这行数据不会被修改,而正常的查询仍然没有问题。

接着,我们用代码实现一下:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.1.3.RELEASE</version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-web</artifactId>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-data-jpa</artifactId>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.mybatis.spring.boot</groupId>
  18. <artifactId>mybatis-spring-boot-starter</artifactId>
  19. <version>2.2.2</version>
  20. </dependency>
  21. <dependency>
  22. <groupId>mysql</groupId>
  23. <artifactId>mysql-connector-java</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.projectlombok</groupId>
  27. <artifactId>lombok</artifactId>
  28. <scope>provided</scope>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-test</artifactId>
  33. <scope>test</scope>
  34. </dependency>
  35. </dependencies>
  36. <build>
  37. <plugins>
  38. <plugin>
  39. <groupId>org.mybatis.generator</groupId>
  40. <artifactId>mybatis-generator-maven-plugin</artifactId>
  41. <version>1.3.7</version>
  42. <dependencies>
  43. <dependency>
  44. <groupId>mysql</groupId>
  45. <artifactId>mysql-connector-java</artifactId>
  46. <version>8.0.15</version>
  47. </dependency>
  48. </dependencies>
  49. <executions>
  50. <execution>
  51. <id>Generate MyBatis Artifacts</id>
  52. <goals>
  53. <goal>generate</goal>
  54. </goals>
  55. </execution>
  56. </executions>
  57. <configuration>
  58. <!-- 输出详细信息 -->
  59. <verbose>true</verbose>
  60. <!-- 覆盖生成文件 -->
  61. <overwrite>true</overwrite>
  62. <!-- 定义配置文件 -->
  63. <configurationFile>${basedir}/src/main/resources/generator-configuration.xml</configurationFile>
  64. </configuration>
  65. </plugin>
  66. </plugins>
  67. <resources>
  68. <resource>
  69. <directory>src/main/java</directory><!--所在的目录-->
  70. <includes><!--包括目录下的.properties,.xml文件都会扫描到-->
  71. <include>**/*.yaml</include>
  72. <include>**/*.xml</include>
  73. </includes>
  74. <filtering>false</filtering>
  75. </resource>
  76. </resources>
  77. </build>
  1. spring:
  2. application:
  3. name: my-app
  4. datasource:
  5. url: jdbc:mysql://localhost:3306/fzs?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
  6. username: root
  7. password: 123456
  8. driver-class-name: com.mysql.cj.jdbc.Driver
  9. mybatis:
  10. mapper-locations: /mapper/*.xml
  11. jpa:
  12. # 数据库类型
  13. database: MySQL
  14. hibernate:
  15. ddl-auto: update
  16. # -控制台显示sql语句
  17. show-sql: true
  18. # 是否自动创建数据库表
  19. generate-ddl: true
  20. database-platform: org.hibernate.dialect.MySQL5InnoDBDialect

使用mybatis的代码生成器

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  3. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  4. <!-- 配置生成器 -->
  5. <generatorConfiguration>
  6. <context id="testTables" targetRuntime="MyBatis3">
  7. <property name="beginningDelimiter" value="`"/>
  8. <property name="endingDelimiter" value="`"/>
  9. <property name="javaFileEncoding" value="UTF-8"/>
  10. <!-- 生成注释配置 -->
  11. <commentGenerator>
  12. <!-- 是否去除自动生成的注释 true:是 : false:否 -->
  13. <property name="suppressAllComments" value="true"/>
  14. <property name="javaFileEncoding" value="UTF8"/>
  15. <!--生成的注释包含时间戳(避免重复提交SVN,设为true)-->
  16. <property name="suppressDate" value="true"/>
  17. </commentGenerator>
  18. <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
  19. <!--
  20. <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver"
  21. connectionURL="jdbc:oracle:thin:@150.16.17.22:1521/wsbs" userId="hr"
  22. password="hr123">
  23. </jdbcConnection>-->
  24. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
  25. connectionURL="jdbc:mysql://localhost:3306/fzs?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC"
  26. userId="root"
  27. password="123456">
  28. </jdbcConnection>
  29. <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
  30. NUMERIC 类型解析为java.math.BigDecimal -->
  31. <javaTypeResolver>
  32. <property name="forceBigDecimals" value="false"/>
  33. </javaTypeResolver>
  34. <!-- targetProject:生成PO类的位置 -->
  35. <javaModelGenerator targetPackage="com.hikktn.domain"
  36. targetProject="src\main\java">
  37. <!-- enableSubPackages:是否让schema作为包的后缀 -->
  38. <property name="enableSubPackages" value="false"/>
  39. <!-- 从数据库返回的值被清理前后的空格 -->
  40. <property name="trimStrings" value="true"/>
  41. </javaModelGenerator>
  42. <!-- targetProject:mapper.xml映射文件生成的位置 -->
  43. <sqlMapGenerator targetPackage="mapper"
  44. targetProject="src\main\resources">
  45. <!-- enableSubPackages:是否让schema作为包的后缀 -->
  46. <property name="enableSubPackages" value="false"/>
  47. </sqlMapGenerator>
  48. <!-- targetPackage:mapper.java接口生成的位置 -->
  49. <javaClientGenerator type="XMLMAPPER"
  50. targetPackage="com.hikktn.dao"
  51. targetProject="src\main\java">
  52. <!-- enableSubPackages:是否让schema作为包的后缀 -->
  53. <property name="enableSubPackages" value="false"/>
  54. </javaClientGenerator>
  55. <!-- 指定数据库表 -->
  56. <!-- enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
  57. enableSelectByExample="false" selectByExampleQueryId="false"-->
  58. <!--不生成example-->
  59. <!--<table tableName="items"></table> -->
  60. <table schema="distribute" tableName="distribute_lock" domainObjectName="DistributeLock"
  61. enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
  62. enableSelectByExample="false" selectByExampleQueryId="false">
  63. <!--下划线转驼峰命名-->
  64. <property name="useActualColumnNames" value="false"/>
  65. <!--指定自动生成主键的属性-->
  66. <generatedKey column="id" sqlStatement="MySql" identity="true"></generatedKey>
  67. <!--元素从将某些属性默认计算的值更改为指定的值。-->
  68. <!--<columnOverride column="message_content" javaType="List&lt;Teacher&gt;"></columnOverride >-->
  69. <!--忽略字段-->
  70. <!--<ignoreColumn column="file_id"></ignoreColumn>-->
  71. <!--<ignoreColumn column="lyric_id"></ignoreColumn>-->
  72. </table>
  73. </context>
  74. </generatorConfiguration>

点击按钮,自动生成
image.png
然后,在启动类配置一下,读取mapper:

  1. @SpringBootApplication
  2. @EnableTransactionManagement
  3. @MapperScan("com.hikktn.dao")
  4. public class Application {
  5. public static void main(String[] args) {
  6. SpringApplication.run(Application.class, args);
  7. }
  8. }

image.png
image.png
最后修改controller
image.png
在通过postman测试,访问两个应用,我们会发现当第一个请求到8080端口,数据库就会锁住,而第二个请求到8081端口时,这个数据就查询不出来,无法进行到下一步了。
甚至会出现数据库超时,从而造成报错!

image.png