新闻资讯

/News and information

基于MySql实现的数据库锁

所属分类:资讯中心
点击量:104
发布时间:2024-03-23 18:49:43

1.创建数据库表

-- ----------------------------

-- Table structure for t_lock

-- ----------------------------

DROP TABLE IF EXISTS `t_lock`;

CREATE TABLE `t_lock` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`lockName` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '锁名称',

`lockTime` datetime(0) NULL DEFAULT NULL COMMENT '最后一次锁时间',

`lockStatus` int(11) NULL DEFAULT 1 COMMENT '锁定状态 1:未锁定 2:已锁定',

PRIMARY KEY (`id`) USING BTREE,

UNIQUE INDEX `ct_lock_uk_lockName`(`lockName`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 74 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

2. 实体类

import java.util.Date;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

import lombok.Getter;

import lombok.Setter;

import com.fasterxml.jackson.annotation.JsonFormat;

/**

* s业务锁的处理,如果能够插入,则可以处理业务,否则不能处理业务

*

* s业务锁开启后一定要unlock,否则业务可能会不执行

*/

@Entity

@Getter

@Setter

@Table(name = "t_lock")

public class Lock implements java.io.Serializable

{

private static final long serialVersionUID = -3086582176340196045L;


//非锁定状态

public static final int LOCKSTATUS_UNLOCK = 1;


//锁定状态

public static final int LOCKSTATUS_LOCKED = 2;


@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Integer id;


@Column(name = "lockName")

private String lockName;


@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

@Column(name = "lockTime")

private Date lockTime;


@Column(name = "lockStatus")

private Integer lockStatus;

}

3. mapper.jar

import org.apache.ibatis.annotations.Param;

import com.sbux.agms.framework.MyBaseMapper;

import com.sbux.agms.pojo.Lock;

/**

* 业务锁信息表

*

* @author Administrator

*/

public interface LockMapper extends MyBaseMapper<Lock>

{

/**

* 尝试超时释放锁,如果释放成功,则返回处理的条数

* @param lockName

* @param lockReleaseTime

* @return

* @see [类、类#方法、类#成员]

*/

int lockOrTimeOut(@Param("lockName") String lockName, @Param("lockReleaseTime") Integer lockReleaseTime);


/**

* 释放锁定任务

* @param lockName

* @return

* @see [类、类#方法、类#成员]

*/

int unlock(@Param("lockName") String lockName);


/**

* 根据所名称

* @param lockName

* @return

* @see [类、类#方法、类#成员]

*/

Lock getLockBylockName(@Param("lockName") String lockName);

}

4.mapper.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="com.sbux.agms.dao.LockMapper">

<!-- 锁定任务,超时时锁定成功 -->

<update id="lockOrTimeOut" parameterType="map">

update t_lock set

lockTime = now(),lockStatus = 2

where

lockName=#{lockName}

<![CDATA[

and (lockStatus = 1 or DATE_ADD(lockTime,interval #{lockReleaseTime} second) <= now())

]]>

</update>

<update id="unlock" parameterType="String">

update t_lock set lockStatus =

1 where lockName=#{lockName}

</update>

<select id="getLockBylockName" parameterType="String"

resultType="com.sbux.agms.pojo.Lock">

SELECT * from t_lock where lockName=#{lockName}

</select>

</mapper>

5. LockService

/**

* s业务处理 方法,包括 lock 和unlock两个方法

* @author Administrator

*/

public interface LockService

{

/**

* s尝试锁定业务,锁定成功返回true;锁定失败,返回false

* @param lockName 锁的名称

* @param lockReleaseTime 锁释放时间(超时后允许获得锁),单位:秒

* @see [类、类#方法、类#成员]

*/

public boolean tryLock(String lockName, int lockReleaseTime);


/**

* s业务解锁,由业务侧决策是使用Unlock 或者releaseLock,两者效果一样,只是一个保留锁数据,一个不保留锁数据

* 【保留锁数据】

* @param lockName

* @see [类、类#方法、类#成员]

*/

public void unLock(String lockName);


/**

* 强制释放锁,直接删除业务锁,由业务侧决策是使用Unlock 或者releaseLock,两者效果一样,只是一个保留锁数据,一个不保留锁数据

* 【不保留锁数据】

* @param lockName

* @see [类、类#方法、类#成员]

*/

public void releaseLock(String lockName);

}

6.LockServiceImpl


import java.util.Date;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import tk.mybatis.mapper.entity.Condition;

import tk.mybatis.mapper.entity.Example.Criteria;

import com.sbux.agms.config.CommonUtil;

import com.sbux.agms.dao.LockMapper;

import com.sbux.agms.framework.BaseServiceSupport;

import com.sbux.agms.pojo.Lock;

import com.sbux.agms.service.LockService;

@Transactional

@Service(value = "lockService")

public class LockServiceImpl extends BaseServiceSupport<Lock> implements LockService

{

Logger logger = LoggerFactory.getLogger(LockServiceImpl.class);


@Autowired

private LockMapper lockMapper;


/**

* 利用数据库的行级锁来实现 t_lock表中增加了lockName的唯一约束,通过状态 + 超时时间的行级锁来判定是否能够获得锁

* s尝试锁定业务,锁定成功返回true;锁定失败,返回false

* @param lockName 锁的名称

* @param lockReleaseTime 锁释放时间(超时后允许获得锁),单位:秒

* @see [类、类#方法、类#成员]

*/

public boolean tryLock(String lockName, int lockReleaseTime)

{

if (CommonUtil.isNotEmpty(lockName))

{

//尝试获取锁,如果获取失败,则尝试创建锁

boolean result = lockMapper.lockOrTimeOut(lockName, lockReleaseTime) > 0;


if (!result)

{

//获取业务锁,如果也无所为空则尝试创建一个锁 (创建成功则说明可以执行,否则不可以执行)

Lock lock = lockMapper.getLockBylockName(lockName);


if (null == lock)

{

lock = new Lock();

lock.setLockName(lockName);

lock.setLockTime(new Date());

lock.setLockStatus(Lock.LOCKSTATUS_LOCKED);

try

{

lockMapper.insertSelective(lock);


result = true;

}

catch (Exception ex)

{

logger.error("创建业务锁【" + lockName + "】失败");

}

}

}

return result;

}


return false;

}


/**

* s业务解锁,直接删除对应的业务主键

* @param lockName

* @see [类、类#方法、类#成员]

*/

public void unLock(String lockName)

{

if (CommonUtil.isNotEmpty(lockName))

{

//释放锁

lockMapper.unlock(lockName);

}

}


/**

* 强制解锁,直接删除业务锁,由业务侧决策是使用unLock 或者releaseLock

* @param lockName

* @see [类、类#方法、类#成员]

*/

public void releaseLock(String lockName)

{

if (CommonUtil.isNotEmpty(lockName))

{

Condition condition = new Condition(Lock.class);

Criteria criteria = condition.createCriteria();

criteria.andEqualTo("lockName", lockName);

lockMapper.deleteByCondition(condition);

}

}

}

7.代码使用

LockService lockService = ServiceFactory.getBean(LockService.class);

try

{

if (null != lockService)

{

//尝试获得锁,如果或得到了锁,则允许执行,否则不允许执行

if (lockService.tryLock(taskName, taskReleaseTime))

{

//业务侧的任务实例执行

task.executet();

}

}

}

catch (Exception e)

{

timerlogger.error("任务【" + taskName + "】执行失败,信息异常:", e);

}

finally

{

//当业务执行完成后进行业务锁的释放,保障业务下次能够顺利执行

lockService.unLock(taskName);

}