public interface AccountDao extends JpaRepository<TAccount, String> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
- @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
@Query("select a from TAccount a where a.accno = ?1")
TAccount getByAccnoForUpdate(String accno);
@Query("select a from TAccount a where a.accno = ?1")
TAccount getByAccnoForUpdateNowait(String accno);
-
TAccount findByUserid(String userid);
+
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @Query("select a from TAccount a where a.userid = ?1")
+ TAccount getByUseridForUpdate(String userid);
+
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+ @Query("select a from TAccount a where a.userid = ?1")
+ TAccount getByUseridForUpdateNowait(String userid);
}
TUserdtl findByRefno(String refno);
@Lock(LockModeType.PESSIMISTIC_WRITE)
- @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="0")})
@Query("select dtl from TUserdtl dtl where dtl.refno = ?1")
TUserdtl findByRefnoForUpdate(String refno);
+
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="0")})
+ @Query("select dtl from TUserdtl dtl where dtl.refno = ?1")
+ TUserdtl findByRefnoForUpdateNowait(String refno);
}
@Query(value = "from TPeriod t where t.periodYear=:periodyear and t.periodMonth=:periodmonth ")
TPeriod getPeriod(@Param("periodyear") Integer periodyear, @Param("periodmonth") Integer periodmonth);
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "from TPeriod t where t.periodYear=:periodyear and t.periodMonth=:periodmonth ")
TPeriod getTPeriodWithLock(@Param("periodyear") Integer periodyear, @Param("periodmonth") Integer periodmonth);
}
import com.supwisdom.dlpay.framework.data.ExistBean;
import com.supwisdom.dlpay.framework.domain.TShopacc;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
+import javax.persistence.LockModeType;
import javax.persistence.QueryHint;
import java.util.List;
TShopacc findByShopid(Integer shopid);
- @Query(value = "select s from TShopacc s where s.shopid = ?1")
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="0")})
- TShopacc getShopAccForUpdate(Integer shopid);
+ @Query("select a from TShopacc a where a.shopid=?1")
+ TShopacc getShopaccWithLockNowait(Integer shopid);
+
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
+ @Query("select a from TShopacc a where a.shopid=?1")
+ TShopacc getShopaccWithLock(Integer shopid);
}
@Query(value = "select t.* from TB_SHOPACCBAL t left join (select shopaccno from TB_SHOPACCDAY where accdate=:lastsettday ) a on t.shopaccno=a.shopaccno where a.shopaccno is null ", nativeQuery = true)
List<TShopaccbal> getUnsettleShopacc(@Param("lastsettday") String lastsettday);
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "from TShopaccbal where shopaccno=:shopaccno ")
TShopaccbal getTShopaccbalByIdWithLock(@Param("shopaccno")String shopaccno);
@Query(value = "select subjname from TSubject where subjno=:subjno ")
String getSubjectname(@Param("subjno") String subjno);
+
+ TSubject findBySubjno(String subjno);
}
@Query(value = "select case when :balflag=1 then sum(drbal) else sum(crbal) end as amount from tb_subjectbal where subjno in (select subjno from tb_subject where endflag=1 and balflag=:balflag )",nativeQuery = true)
Double getSumEndsubjectBalByEndflag(@Param("balflag")Integer balflag);
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("from TSubjectbal where subjno=:subjno ")
TSubjectbal getTSubjectbalBySubjnoWithLock(@Param("subjno")String subjno);
}
@Repository
public interface TaskLockDao extends JpaRepository<TTaskLock, String> {
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select a from TTaskLock a where a.taskcode=:taskcode")
TTaskLock getTaskLockWithLock(@Param("taskcode") String taskcode);
import com.supwisdom.dlpay.framework.domain.TTranstype;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+@Repository
public interface TranstypeDao extends JpaRepository<TTranstype, Integer> {
-
+ TTranstype findByTranstype(Integer transtype);
}
@Query(value="delete from TB_VOUCHER where POSTFLAG=0 ",nativeQuery = true)
void deleteUnpostVoucher();
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "from TVoucher where postflag=0 order by voucherid ")
List<TVoucher> getSettleVouchers();
@Query(value = "select sum(va.dramt) as dramt, sum(va.cramt) as cramt from TB_VOUCHERENTRY va,TB_VOUCHER vb where va.voucherid=vb.voucherid and vb.voucherdate=:voucherdate and va.subjno=:subjno ", nativeQuery = true)
MerchBean getSettleSuminfo(@Param("voucherdate") Integer voucherdate, @Param("subjno") String subjno);
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "from TVoucher where voucherid=:voucherid ")
TVoucher findByVoucheridWithLock(@Param("voucherid") String voucherid);
}
@Query(value = "from TVoucherEntry where voucherid in (select voucherid from TVoucher where voucherdate=:voucherdate) order by subjno,accno,voucherid ")
List<TVoucherEntry> getVoucherEntryByVoucherdate(@Param("voucherdate") Integer voucherdate);
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "from TVoucherEntry t where t.voucherid=:voucherid ")
List<TVoucherEntry> getVoucherEntryByVoucherid(@Param("voucherid")String voucherid);
}
@Query(value = "update TB_VOUCHERNOCTL set PERIOD_MONTH=:peridmonth,VOUCHERNO=:voucherno where VOUCHERTYPE=1 ", nativeQuery = true)
void updateVoucherno(@Param("peridmonth") int peridmonth, @Param("voucherno") int voucherno);
- @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT)
+ @Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(value = "from TVouchernoCtl where vouchertype=1 ")
TVouchernoCtl getVoucherno();
}
public class TTranstype {
@Id
@Column(name = "TRANSTYPE", nullable = false, precision = 4)
- private Integer TRANSTYPE;
+ private Integer transtype;
@Column(name = "DRSUBJNO", length = 10)
- private String DRSUBJNO;
+ private String drsubjno;
@Column(name = "CRSUBJNO", length = 10)
- private String CRSUBJNO;
+ private String crsubjno;
@Column(name = "SUMMARY", length = 200)
- private String SUMMARY;
+ private String summary;
- public Integer getTRANSTYPE() {
- return TRANSTYPE;
+ public Integer getTranstype() {
+ return transtype;
}
- public void setTRANSTYPE(Integer TRANSTYPE) {
- this.TRANSTYPE = TRANSTYPE;
+ public void setTranstype(Integer transtype) {
+ this.transtype = transtype;
}
- public String getDRSUBJNO() {
- return DRSUBJNO;
+ public String getDrsubjno() {
+ return drsubjno;
}
- public void setDRSUBJNO(String DRSUBJNO) {
- this.DRSUBJNO = DRSUBJNO;
+ public void setDrsubjno(String drsubjno) {
+ this.drsubjno = drsubjno;
}
- public String getCRSUBJNO() {
- return CRSUBJNO;
+ public String getCrsubjno() {
+ return crsubjno;
}
- public void setCRSUBJNO(String CRSUBJNO) {
- this.CRSUBJNO = CRSUBJNO;
+ public void setCrsubjno(String crsubjno) {
+ this.crsubjno = crsubjno;
}
- public String getSUMMARY() {
- return SUMMARY;
+ public String getSummary() {
+ return summary;
}
- public void setSUMMARY(String SUMMARY) {
- this.SUMMARY = SUMMARY;
+ public void setSummary(String summary) {
+ this.summary = summary;
}
}
import com.supwisdom.dlpay.framework.domain.*;
import com.supwisdom.dlpay.framework.service.DayendSettleService;
import com.supwisdom.dlpay.framework.service.SystemUtilService;
-import com.supwisdom.dlpay.framework.util.DateUtil;
-import com.supwisdom.dlpay.framework.util.MoneyUtil;
-import com.supwisdom.dlpay.framework.util.StringUtil;
-import com.supwisdom.dlpay.framework.util.TradeDict;
+import com.supwisdom.dlpay.framework.util.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//明细
for (TVoucherEntry entry : entryList) {
- if (TradeDict.SUBJNO_SHOP.equals(entry.getSubjno())) {
+ if (Subject.SUBJNO_MACHANT_INCOME.equals(entry.getSubjno())) {
TShopaccbal tShopaccbal = shopaccbalDao.getTShopaccbalByIdWithLock(entry.getAccno());
if (null == tShopaccbal) {
throw new Exception("商户表商户账号[" + entry.getAccno() + "]不存在");
--- /dev/null
+package com.supwisdom.dlpay.framework.util;
+
+public class APIRequest {
+ private String app_id;
+ private String sign;
+ private String sign_method;
+ private String timestamp;
+
+ public String getApp_id() {
+ return app_id;
+ }
+
+ public void setApp_id(String app_id) {
+ this.app_id = app_id;
+ }
+
+ public String getSign() {
+ return sign;
+ }
+
+ public void setSign(String sign) {
+ this.sign = sign;
+ }
+
+ public String getSign_method() {
+ return sign_method;
+ }
+
+ public void setSign_method(String sign_method) {
+ this.sign_method = sign_method;
+ }
+
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+}
-package com.supwisdom.dlpay.util;
-
-import com.supwisdom.dlpay.framework.util.DateUtil;
+package com.supwisdom.dlpay.framework.util;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public static final int SHOP_NOT_EXISTS = 10007;
/**
- * 商户不存在
+ * 科目不存在
* */
public static final int SUBJECT_NOT_EXISTS = 10008;
* */
public static final int TRANSDTL_STATUS_NOT_INIT = 10013;
+ /**
+ * 账户交易繁忙
+ * */
+ public static final int ACCOUNT_TRADE_BUSY = 10014;
+
+ /**
+ * 非等待锁查询超时异常
+ * */
+ public static final int LOCK_READ_TIMEOUT = 10015;
+
}
import com.supwisdom.dlpay.consume.bean.SupYktResp
import com.supwisdom.dlpay.consume.domain.TUserdtl
import com.supwisdom.dlpay.framework.util.MoneyUtil
-import com.supwisdom.dlpay.util.HmacUtil
+import com.supwisdom.dlpay.framework.util.HmacUtil
/**
* Created by shuwei on 2019/4/11.
@Suppress("UNCHECKED_CAST", "IMPLICIT_CAST_TO_ANY")
fun <T> get(): T {
return when (idType) {
- IDTYPE_PERSON -> builder.accountUtil.readAccount(accountId)
+ IDTYPE_PERSON -> builder.accountUtil.readAccountForUpdateNowait(accountId)
IDTYPE_SHOP -> builder.accountUtil.readShopAcc(accountId.toInt())
IDTYPE_SUBJECT -> builder.accountUtil.readSubject(accountId)
IDTYPE_TRANSTYPE -> builder.accountUtil.readTranstype(accountId.toInt())
@Suppress("UNCHECKED_CAST", "IMPLICIT_CAST_TO_ANY")
fun <T> withLock(nowait: Boolean): T {
return when (idType) {
- IDTYPE_PERSON -> builder.accountUtil.readAccountForUpdate(accountId, true)
- IDTYPE_SHOP -> builder.accountUtil.readShopAccForUpdate(accountId.toInt(), true)
- IDTYPE_SUBJECT -> builder.accountUtil.readSubjectForUpdate(accountId, true)
+ IDTYPE_PERSON -> builder.accountUtil.readAccountForUpdateNowait(accountId)
+ IDTYPE_SHOP -> builder.accountUtil.readShopAcc(accountId.toInt())
+ IDTYPE_SUBJECT -> builder.accountUtil.readSubject(accountId)
IDTYPE_TRANSTYPE -> builder.accountUtil.readTranstype(accountId.toInt())
else -> throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "账户类型未知type<$idType>")
} as T
import com.supwisdom.dlpay.consume.domain.TUserdtl
import com.supwisdom.dlpay.consume.service.AccountUtilServcie
import com.supwisdom.dlpay.consume.service.PersonBalancePayService
+import com.supwisdom.dlpay.exception.TransactionException
import com.supwisdom.dlpay.exception.TransactionProcessException
import com.supwisdom.dlpay.framework.dao.ShopaccDao
import com.supwisdom.dlpay.framework.dao.SubjectDao
import com.supwisdom.dlpay.framework.domain.TTranstype
import com.supwisdom.dlpay.framework.service.SystemUtilService
import com.supwisdom.dlpay.framework.util.*
+import org.hibernate.exception.LockTimeoutException
import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.dao.CannotAcquireLockException
import org.springframework.stereotype.Service
import javax.persistence.EntityManager
import javax.persistence.PersistenceContext
@Service
class AccountUtilServcieImpl : AccountUtilServcie {
+
@Autowired
lateinit var accountDao: AccountDao
lateinit var transtypeDao: TranstypeDao
- override fun readAccountForUpdate(userid: String, nowait: Boolean): TAccount {
- return accountDao.getByAccnoForUpdateNowait(userid)
- }
-
- override fun readAccount(userid: String): TAccount {
- accountDao.findByUserid(userid).let {
- if (null != it) {
- return it
+ override fun readAccountForUpdateNowait(userid: String): TAccount {
+ return try {
+ accountDao.getByUseridForUpdateNowait(userid)
+ ?: throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账户<$userid>不存在")
+ } catch (ex: Exception) {
+ when (ex) {
+ is CannotAcquireLockException, is LockTimeoutException -> throw TransactionException(TradeErrorCode.ACCOUNT_TRADE_BUSY, "账户<$userid>交易繁忙,请稍后再试")
+ else -> throw ex
}
- throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账户<$userid>不存在")
}
}
- override fun readShopAccForUpdate(shopId: Int, nowait: Boolean): TShopacc {
- return shopaccDao.getShopAccForUpdate(shopId)
+ override fun readAccount(userid: String): TAccount {
+ return accountDao.findByUserid(userid)
+ ?: throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账户<$userid>不存在")
}
override fun readShopAcc(shopId: Int): TShopacc {
- shopaccDao.findByShopid(shopId).let {
- if (null != it) {
- return it
- }
- throw TransactionProcessException(TradeErrorCode.SHOP_NOT_EXISTS, "商户<$shopId>不存在")
- }
- }
-
- override fun readSubjectForUpdate(subjno: String, nowait: Boolean): TSubject {
- return subjectDao.getOne(subjno)
+ return shopaccDao.findByShopid(shopId)
+ ?: throw TransactionProcessException(TradeErrorCode.SHOP_NOT_EXISTS, "商户<$shopId>不存在")
}
override fun readSubject(subjno: String): TSubject {
- return subjectDao.getOne(subjno)
+ return subjectDao.findBySubjno(subjno)
+ ?: throw TransactionProcessException(TradeErrorCode.SUBJECT_NOT_EXISTS, "科目<$subjno>不存在")
}
override fun readTranstype(transtype: Int): TTranstype {
- return transtypeDao.getOne(transtype)
+ return transtypeDao.findByTranstype(transtype)
+ ?: throw TransactionProcessException(TradeErrorCode.SUBJECT_NOT_EXISTS, "交易类型<$transtype>未配置")
}
}
private fun getlockAccount(accno: String): TAccount {
- //TODO 等待锁
- return accountDao.getOne(accno)
+ return accountDao.getByAccnoForUpdate(accno)
+ ?: throw throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账号<$accno>不存在")
}
private fun getlockAccountNowait(accno: String): TAccount {
- //TODO 等待锁
- return accountDao.getOne(accno)
+ return try {
+ accountDao.getByAccnoForUpdateNowait(accno)
+ ?: throw throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账号<$accno>不存在")
+ } catch (ex: Exception) {
+ when (ex) {
+ is CannotAcquireLockException, is LockTimeoutException -> throw TransactionException(TradeErrorCode.ACCOUNT_TRADE_BUSY, "账号<$accno>交易繁忙,请稍后再试")
+ else -> throw ex
+ }
+ }
}
private fun getLockUserdtlNowait(refno: String): TUserdtl {
- userdtlDao.findByRefnoForUpdate(refno).let {
- if (null != it) {
- return it
+ return try {
+ userdtlDao.findByRefnoForUpdateNowait(refno)
+ ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易参考号<$refno>不存在")
+ } catch (ex: Exception) {
+ when (ex) {
+ is CannotAcquireLockException, is LockTimeoutException -> throw TransactionException(TradeErrorCode.LOCK_READ_TIMEOUT, "交易参考号<$refno>被锁定,请稍后再试")
+ else -> throw ex
}
- throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易参考号<$refno>不存在")
}
}
private fun getLockUserdtl(refno: String): TUserdtl {
return userdtlDao.findByRefnoForUpdate(refno)
+ ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易参考号<$refno>不存在")
}
private fun checkOuttradenoExist(outtradeno: String): Boolean {
if (!overdraft && account.checkOverdraft())
throw TransactionProcessException(TradeErrorCode.SHORT_BALANCE_ERROR, "账户<$accno>余额不足")
- account.tac = account.generateTac()
return accountDao.save(account) //入库更新
}
import com.supwisdom.dlpay.framework.domain.TShopacc
import com.supwisdom.dlpay.framework.domain.TSubject
import com.supwisdom.dlpay.framework.domain.TTranstype
+import org.springframework.transaction.annotation.Propagation
+import org.springframework.transaction.annotation.Transactional
interface AccountUtilServcie {
- fun readAccountForUpdate(userid: String, nowait: Boolean): TAccount
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+ fun readAccountForUpdateNowait(userid: String): TAccount
+
+
fun readAccount(userid: String): TAccount
- fun readShopAccForUpdate(shopId: Int, nowait: Boolean): TShopacc
fun readShopAcc(shopId: Int): TShopacc
- fun readSubjectForUpdate(subjno: String, nowait: Boolean): TSubject
fun readSubject(subjno: String): TSubject
fun readTranstype(transtype: Int): TTranstype
/**
* 一步完成交易
*/
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
fun process(builder: PersonTransBuilder): TUserdtl
/**
* 两步交易,交易初始化方法,检查交易参数,记录交易流水
*/
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
fun init(builder: PersonTransBuilder): TUserdtl
/**
* 两步交易,完成交易过程,包括更新交易状态(成功、失败),更新借贷双方余额
*/
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
fun finish(paydtl: TUserdtl, status: String, businessData: Map<String, String>?): TUserdtl
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
fun finish(refno: String, status: String, businessData: Map<String, String>?): TUserdtl
/**
* 如果交易记录被锁,立刻抛出异常
* @throws TransactionProcessException
*/
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
fun wip(paydtl: TUserdtl): TUserdtl
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
fun wip(refno: String): TUserdtl
-
}
\ No newline at end of file