東莞公司建設網(wǎng)站如何在百度上推廣自己
設計思路:
利用數(shù)據(jù)庫表記錄鎖標識:通過唯一標識符(如方法名 + 參數(shù)),我們可以在數(shù)據(jù)庫中插入一條記錄,表示當前方法正在執(zhí)行。這條記錄需要記錄插入時間。
注解:通過注解標識哪些方法需要加鎖,我們可以動態(tài)生成唯一標識符。
AOP:使用 AOP 切面處理方法調用邏輯,確保在進入目標方法之前判斷是否已經(jīng)有其他線程持有鎖。如果有,則阻塞當前線程,直到鎖被釋放。
事務:利用事務的隔離性,保證在同一時刻,只有一個線程能夠執(zhí)行某個方法,其他線程需要等待。
超時檢測:如果在某個時間點鎖沒有被釋放(例如,鎖存在時間超過10分鐘),則認為發(fā)生了死鎖,自動清理相關記錄。
步驟及代碼實現(xiàn)
- 數(shù)據(jù)庫表設計
首先,我們需要一個數(shù)據(jù)庫表來存儲鎖的狀態(tài)。表的結構大致如下:
CREATE TABLE method_lock (id BIGINT AUTO_INCREMENT PRIMARY KEY,lock_key VARCHAR(255) NOT NULL, -- 鎖的唯一標識(方法名+參數(shù))created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 鎖的創(chuàng)建時間updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 最后更新時間status VARCHAR(50) DEFAULT 'LOCKED', -- 鎖的狀態(tài),LOCKED 表示鎖定,RELEASED 表示釋放expired BOOLEAN DEFAULT FALSE -- 是否過期,10分鐘未釋放的鎖算死鎖
);
- 創(chuàng)建鎖的注解
接下來,我們定義一個注解來標識需要加鎖的方法。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLock {String value(); // 鎖的標識(如方法名 + 參數(shù)的唯一標識符)
}
- 實現(xiàn) AOP 切面
在切面中,我們要通過 @Around 來攔截帶有 @MethodLock 注解的方法,獲取方法的唯一標識,并在數(shù)據(jù)庫中插入或查詢鎖的狀態(tài)。
@Aspect
@Component
public class MethodLockAspect {@Autowiredprivate LockRepository lockRepository; // 用于查詢和操作數(shù)據(jù)庫的 repository@Around("@annotation(methodLock)") // 攔截帶有 @MethodLock 注解的方法public Object around(ProceedingJoinPoint joinPoint, MethodLock methodLock) throws Throwable {String lockKey = methodLock.value() + getMethodSignature(joinPoint); // 生成鎖的唯一標識符// 獲取當前時間戳long currentTime = System.currentTimeMillis();// 嘗試獲取鎖if (tryAcquireLock(lockKey, currentTime)) {try {// 如果獲取到鎖,則執(zhí)行目標方法return joinPoint.proceed();} finally {// 目標方法執(zhí)行完畢后釋放鎖releaseLock(lockKey);}} else {// 如果無法獲取到鎖,則阻塞當前線程或者拋出異常throw new RuntimeException("Unable to acquire lock, try again later.");}}private boolean tryAcquireLock(String lockKey, long currentTime) {// 查詢數(shù)據(jù)庫中是否存在該鎖記錄LockEntity lockEntity = lockRepository.findByLockKey(lockKey);if (lockEntity == null) {// 如果不存在鎖記錄,則插入新的鎖記錄LockEntity newLockEntity = new LockEntity();newLockEntity.setLockKey(lockKey);newLockEntity.setCreatedTime(new Timestamp(currentTime));lockRepository.save(newLockEntity);return true;} else {// 如果鎖存在,檢查鎖是否已經(jīng)過期(超過10分鐘)long lockAge = currentTime - lockEntity.getCreatedTime().getTime();if (lockAge > 10 * 60 * 1000) {// 如果鎖超時超過10分鐘,認為是死鎖,清理并重新獲取鎖lockRepository.deleteByLockKey(lockKey); // 刪除死鎖記錄LockEntity newLockEntity = new LockEntity();newLockEntity.setLockKey(lockKey);newLockEntity.setCreatedTime(new Timestamp(currentTime));lockRepository.save(newLockEntity);return true;}// 如果鎖沒有過期,則阻塞當前線程return false;}}private void releaseLock(String lockKey) {// 釋放鎖:刪除數(shù)據(jù)庫中的鎖記錄lockRepository.deleteByLockKey(lockKey);}private String getMethodSignature(ProceedingJoinPoint joinPoint) {// 獲取方法簽名(例如方法名 + 參數(shù))String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();StringBuilder signature = new StringBuilder(methodName);for (Object arg : args) {signature.append("-").append(arg != null ? arg.toString() : "null");}return signature.toString();}
}
- LockRepository 示例
假設使用的是 Spring Data JPA 來進行數(shù)據(jù)庫操作,我們可以定義一個簡單的 Repository 來操作 method_lock 表。
public interface LockRepository extends JpaRepository<LockEntity, Long> {LockEntity findByLockKey(String lockKey);void deleteByLockKey(String lockKey);
}
- LockEntity 實體類
LockEntity 對應數(shù)據(jù)庫中的 method_lock 表:
@Entity
@Table(name = "method_lock")
public class LockEntity {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String lockKey;@Column(name = "created_time")private Timestamp createdTime;@Column(name = "updated_time")private Timestamp updatedTime;private String status;private Boolean expired;// Getters and Setters
}
- 使用示例
現(xiàn)在,我們可以在需要加鎖的方法上使用 @MethodLock 注解,示例如下:
@Service
public class MyService {@MethodLock("uniqueLockKey")@Transactionalpublic void executeTask(String param) {// 執(zhí)行需要加鎖的邏輯System.out.println("Executing task with param: " + param);}
}
關鍵點總結:
鎖的唯一標識:通過方法名和參數(shù)生成一個唯一的標識符 lockKey。
數(shù)據(jù)庫表記錄鎖:通過表記錄鎖的狀態(tài),保證只有一個線程能獲取到鎖。
AOP 和注解結合:使用 AOP 和注解對方法進行攔截,判斷是否已經(jīng)有其他線程在執(zhí)行,若沒有則獲取鎖,若有則阻塞或拋出異常。
事務特性:保證同一時刻,只有一個線程能夠執(zhí)行目標方法,其他線程需要等待,。
死鎖處理:在鎖存在超過 10 分鐘時認為是死鎖,進行清理。
通過這種方式,可以實現(xiàn)基于事務的排他鎖,確保多個線程訪問同一資源時進行排隊執(zhí)行
解釋:
例如,多個接口調用一個方法,要求多個線程調用該方法時,這些線程排隊執(zhí)行,該方法使用注解,aop切面,通過該注解上的特定字符串和方法名,組成唯一標識,將該標識插入表中,并且記錄插入時間,并且該標識是唯一的,當有線程調用該方法時,先組裝唯一標識,查詢表中是否有該標識的數(shù)據(jù),并判斷是否時間距離現(xiàn)在是否超過了10分鐘,如果超過10分鐘就是死鎖了,直接刪除該標識的所有記錄,如果沒有查到就插入一條記錄,如果該方法沒有執(zhí)行完,就在一個事務里面,該事務沒有結束,當有其他方法調用該方法時,就回去查詢并插入,由于前一個事務未結束,導致當前唯一標識一致,卡在插入數(shù)據(jù)時,從而達到阻塞的目的,最后方法結束后將該數(shù)據(jù)刪除。