mysql行級鎖:
- 數據庫引擎: InnerDB,其他的不支持行鎖
- 所在方法要加上事務註解, 必須加上: @Transactional(isolation = Isolation.READ_COMMITTED)
- 查詢sql舉例:
select * from global_lock where object=#{object} for update;
注意: - timeout必須設置,否則,一旦行鎖被鎖定,另一個調用的方法將永久的阻塞。加了超時後,如果行鎖被獲取,則超時提示
- 數據表必須加索引,否則,將採用表級鎖
- 行鎖可以重複調,只要不是同一行,可以跨表
例子如下:
數據庫:
CREATE TABLE `global_lock` (
`object` varchar(20) DEFAULT NULL,
**UNIQUE KEY `idx_global_lock_object` (`object`)**
) ENGINE=InnoDB DEFAULT CHARSET=utf8
項目:
GlobalLockController .java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sm.rowlock.mapper.GlobalLockMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class GlobalLockController {
private static Logger logger = LoggerFactory.getLogger(GlobalLockController.class);
@Autowired
private GlobalLockMapper globalLockMapper;
@RequestMapping("/getLock")
@Transactional(isolation = Isolation.READ_COMMITTED)
public void getLock() {
globalLockMapper.getLock("object");
System.out.println("111");
}
@RequestMapping("/getLock2")
@Transactional(isolation = Isolation.READ_COMMITTED)
public void getLock2() {
try {
globalLockMapper.getLock("object");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("111");
}
}
GlobalLockEntity .java
public class GlobalLockEntity {
private String object;
public String getObject() {
return object;
}
public void setObject(String object) {
this.object = object;
}
}
GlobalLockMapper .java
import org.apache.ibatis.annotations.Param;
public interface GlobalLockMapper {
void getLock(@Param("object")String object);
}
MainApp.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@tk.mybatis.spring.annotation.MapperScan(basePackages="org.sm.rowlock.mapper")
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
GlobalLockMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.sm.rowlock.mapper.GlobalLockMapper">
<resultMap id="BaseResultMap" type="org.sm.rowlock.entity.GlobalLockEntity">
<result column="object" property="object" jdbcType="VARCHAR"/>
</resultMap>
<select id="getLock" resultMap="BaseResultMap" timeout="2">
select * from global_lock where object=#{object} for update;
</select>
</mapper>
application.properties
server.port=8081
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://ip:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.username=user
spring.datasource.password=password
mybatis.type-aliases-package=org.sm.rowlock.entity
mybatis.mapper-locations=classpath:mappers/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
mapper.mappers=tk.mybatis.mapper.common.Mapper
mapper.not-empty=false
mapper.identity=MYSQL