如何为 Spring/OpenJPA 中的更新行锁定重新创建 select 1
How to recreate select for update row locking in Spring/OpenJPA 1
我需要不允许在我的 Spring/OpenJPA 1 应用程序中同时使用相同的确认代码。我们决定使用 select 作为更新策略,因此我们创建了 table AdmissionLock(id, Confirmation_Code, Terminal).
单独的示例 JDBC 应用程序适用于此策略。允许同时处理不同的确认码,不允许同时处理相同的确认码。请查看下面的示例代码:
线程代码:
conn.setAutoCommit(false);
long retId = Util.lockBySelectUpdate(conn, threadName, terminalCode, confNumber);
Util.updateConfCode(conn, threadName, terminalCode, confNumber);
conn.commit();
主程序代码:
String confCode1 = "21";
String confCode2 = "22";
String terminalCode1 = "10";
String terminalCode2 = "11";
Connection conn1 = Util.getNewConnection();
Connection conn2 = Util.getNewConnection();
AdmissionThread admissionThread1=new AdmissionThread(terminalCode1, conn1, confCode1, "Thread1", 10);
AdmissionThread admissionThread2=new AdmissionThread(terminalCode2, conn2, confCode2, "Thread2", 0);
admissionThread1.start();
Thread.sleep(2000);
admissionThread2.start();
SQL:
"SELECT * FROM ADMISSIONLOCK WHERE CONFIRMATION_CODE=? FOR UPDATE"
"update ADMISSIONLOCK set CONFIRMATION_CODE=? where TERMINAL_SERIAL_NUMBER=?;";
由于我们的应用程序是 Spring/OpenJPA 1 我需要将这个想法合并到 Spring/OPenJPA 1 代码中。因此,我使用以下简化代码创建了服务:
@Transactional
public void processAdmissionLock (String terminalSerialNumber, String confirmationCode){
AdmissionLock admissionLock = new AdmissionLock(terminalSerialNumber, confirmationCode);
query = entityManager.createNativeQuery(SQL_LOCK_STRING);
entityManager.lock(admissionLock, LockModeType.READ);
query.setParameter(1, confirmationCode).getResultList();
if(isEntityPersistent(admissionLock)) {
admissionLock = entityManager.merge(admissionLock);
} else {
entityManager.persist(admissionLock);
}
}
AdmissionLock 实体:
@Entity
@Table (name = SdiAdmissionLock.TABLE_NAME)
public class SdiAdmissionLock extends AbstractEntityImpl {
private static final long serialVersionUID = 1L;
private long uidpk;
private String terminalSerialNumber;
private String confirmationCode;
private Date createdDate;
public static final String TABLE_NAME = "SDIADMISSIONLOCK";
...
}
我的问题是这段代码没有锁定任何东西。具有相同确认码的两个并发线程都通过
我最终使用了与 JDBC 应用程序中相同的本机查询。一个重要区别 - 开始事务 ("START TRANSACTION") 和提交 ("COMMIT") 转移到 MYSQL 本身并由 JDBC executeUpdate() 方法调用。
我需要不允许在我的 Spring/OpenJPA 1 应用程序中同时使用相同的确认代码。我们决定使用 select 作为更新策略,因此我们创建了 table AdmissionLock(id, Confirmation_Code, Terminal).
单独的示例 JDBC 应用程序适用于此策略。允许同时处理不同的确认码,不允许同时处理相同的确认码。请查看下面的示例代码:
线程代码:
conn.setAutoCommit(false);
long retId = Util.lockBySelectUpdate(conn, threadName, terminalCode, confNumber);
Util.updateConfCode(conn, threadName, terminalCode, confNumber);
conn.commit();
主程序代码:
String confCode1 = "21";
String confCode2 = "22";
String terminalCode1 = "10";
String terminalCode2 = "11";
Connection conn1 = Util.getNewConnection();
Connection conn2 = Util.getNewConnection();
AdmissionThread admissionThread1=new AdmissionThread(terminalCode1, conn1, confCode1, "Thread1", 10);
AdmissionThread admissionThread2=new AdmissionThread(terminalCode2, conn2, confCode2, "Thread2", 0);
admissionThread1.start();
Thread.sleep(2000);
admissionThread2.start();
SQL:
"SELECT * FROM ADMISSIONLOCK WHERE CONFIRMATION_CODE=? FOR UPDATE"
"update ADMISSIONLOCK set CONFIRMATION_CODE=? where TERMINAL_SERIAL_NUMBER=?;";
由于我们的应用程序是 Spring/OpenJPA 1 我需要将这个想法合并到 Spring/OPenJPA 1 代码中。因此,我使用以下简化代码创建了服务:
@Transactional
public void processAdmissionLock (String terminalSerialNumber, String confirmationCode){
AdmissionLock admissionLock = new AdmissionLock(terminalSerialNumber, confirmationCode);
query = entityManager.createNativeQuery(SQL_LOCK_STRING);
entityManager.lock(admissionLock, LockModeType.READ);
query.setParameter(1, confirmationCode).getResultList();
if(isEntityPersistent(admissionLock)) {
admissionLock = entityManager.merge(admissionLock);
} else {
entityManager.persist(admissionLock);
}
}
AdmissionLock 实体:
@Entity
@Table (name = SdiAdmissionLock.TABLE_NAME)
public class SdiAdmissionLock extends AbstractEntityImpl {
private static final long serialVersionUID = 1L;
private long uidpk;
private String terminalSerialNumber;
private String confirmationCode;
private Date createdDate;
public static final String TABLE_NAME = "SDIADMISSIONLOCK";
...
}
我的问题是这段代码没有锁定任何东西。具有相同确认码的两个并发线程都通过
我最终使用了与 JDBC 应用程序中相同的本机查询。一个重要区别 - 开始事务 ("START TRANSACTION") 和提交 ("COMMIT") 转移到 MYSQL 本身并由 JDBC executeUpdate() 方法调用。