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);
}