【发布时间】:2022-01-07 12:59:53
【问题描述】:
实体
@Entity
@Table(name = "v_CUSTOMER", uniqueConstraints = {@UniqueConstraint(columnNames = {"accno", "row"})})
@SequenceGenerator(
name = "sgb.CUSTOMER_SEQ",
sequenceName = "sgb.CUSTOMER_SEQ",
allocationSize = 1
)
@Getter
@Setter
@ToString
@FieldNameConstants
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sgb.CUSTOMER_SEQ")
@Column(name = "NEWLAB_CHRONO", nullable = true, insertable = true, updatable = true, precision = 0)
@CobolType(numeric = true,nullable = true)
private Integer newlabChrono;
@Basic
@Column(name = "ACCNO", nullable = false, insertable = true, updatable = true, length = 10)
@CobolType(numeric = true)
private String accno;
@Basic
@Column(name = "ROW", nullable = false, insertable = true, updatable = true, length = 2)
@CobolType(numeric = true)
private String row;
@Basic
@Column(name = "SHAKHS", nullable = true, insertable = true, updatable = true, length = 1)
@CobolType(numeric = true)
private String shakhs;
@Basic
@Column(name = "TAR_GAR", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true)
private String tarGar;
@Basic
@Column(name = "ID_ALT1", nullable = true, insertable = true, updatable = true, length = 12)
@CobolType(numeric = true)
private String idAlt1;
@Basic
@Column(name = "ID_ALT2", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true)
private String idAlt2;
@Basic
@Column(name = "ID_ALT3", nullable = true, insertable = true, updatable = true, length = 3)
@CobolType(numeric = true)
private String idAlt3;
@Basic
@Column(name = "MELLI_ALT", nullable = true, insertable = true, updatable = true, length = 12)
@CobolType(numeric = true)
private String melliAlt;
@Basic
@Column(name = "BRANCH_ID", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true, nullable = true)
private String branchId;
@Basic
@Column(name = "BRANCH", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true, nullable = true)
private String branch;
@Basic
@Column(name = "REGION", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true, nullable = true)
private String region;
@Basic
@Column(name = "SITE", nullable = true, insertable = true, updatable = true, length = 2)
@CobolType(numeric = true, nullable = true)
private String site;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer that = (Customer) o;
return Objects.equals(accno, that.accno) &&
Objects.equals(row, that.row);
}
@Override
public int hashCode() {
return Objects.hash(accno, row);
}
}
@Entity
@Table(name = "v_CUSTOMER_PERSON")
@SequenceGenerator(
name = "CUSTOMER_PERSON_SEQ",
sequenceName = "CUSTOMER_PERSON_SEQ",
allocationSize = 1
)
@Getter
@Setter
@ToString
@FieldNameConstants
public class CustomerPerson {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_PERSON_SEQ")
@Column(name = "NEWLAB_CHRONO", nullable = true, insertable = true, updatable = true, precision = 0)
@CobolType(numeric = true, nullable = true)
private Integer newlabChrono;
@Basic
@Column(name = "ACCNO", nullable = false, insertable = true, updatable = true, length = 10)
@CobolType(numeric = true)
private String accno;
@Basic
@Column(name = "ROW", nullable = false, insertable = true, updatable = true, length = 2)
@CobolType(numeric = true)
private String row;
@Basic
@Column(name = "SHAKHS", nullable = true, insertable = true, updatable = true, length = 1)
@CobolType(numeric = true)
private String shakhs;
@Basic
@Column(name = "TAR_GAR", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true)
private String tarGar;
@Basic
@Column(name = "SH_NO", nullable = true, insertable = true, updatable = true, length = 12)
@CobolType(numeric = true)
private String shNo;
@Basic
@Column(name = "BIRTH_DATE", nullable = true, insertable = true, updatable = true, length = 6)
@CobolType(numeric = true)
private String birthDate;
@Basic
@Column(name = "MAH_COD", nullable = true, insertable = true, updatable = true, length = 3)
@CobolType(numeric = true)
private String mahCod;
@Basic
@Column(name = "COD_ME", nullable = true, insertable = true, updatable = true, length = 12)
@CobolType(numeric = true)
private String codMe;
@Basic
@Column(name = "GRP1", nullable = true, insertable = true, updatable = true, length = 3)
@CobolType(numeric = true)
private String grp1;
@Basic
@Column(name = "BIL1", nullable = true, insertable = true, updatable = true, length = 1)
@CobolType(numeric = true)
private String bil1;
@Basic
@Column(name = "DUP1", nullable = true, insertable = true, updatable = true, length = 1)
@CobolType(numeric = true)
private String dup1;
@Basic
@Column(name = "NAME1", nullable = true, insertable = true, updatable = true, length = 60)
@CobolType(numeric = false)
private String name1;
@Basic
@Column(name = "FAMILI1", nullable = true, insertable = true, updatable = true, length = 80)
@CobolType(numeric = false)
private String famili1;
@Basic
@Column(name = "PERSON1", nullable = true, insertable = true, updatable = true, length = 1)
@CobolType(numeric = true)
private String person1;
@Basic
@Column(name = "FATHER", nullable = true, insertable = true, updatable = true, length = 60)
@CobolType(numeric = false)
private String father;
@Basic
@Column(name = "HOZE", nullable = true, insertable = true, updatable = true, length = 2)
@CobolType(numeric = true)
private String hoze;
@Basic
@Column(name = "CITY1", nullable = true, insertable = true, updatable = true, length = 40)
@CobolType(numeric = false)
private String city1;
@Basic
@Column(name = "TEL1", nullable = true, insertable = true, updatable = true, length = 13)
@CobolType(numeric = true)
private String tel1;
@Basic
@Column(name = "POST1", nullable = true, insertable = true, updatable = true, length = 10)
@CobolType(numeric = true)
private String post1;
@Basic
@Column(name = "ADDRS1", nullable = true, insertable = true, updatable = true, length = 160)
@CobolType(numeric = false)
private String addrs1;
@Basic
@Column(name = "E_MAIL", nullable = true, insertable = true, updatable = true, length = 40)
@CobolType(numeric = false)
private String eMail;
@Basic
@Column(name = "FAX1", nullable = true, insertable = true, updatable = true, length = 13)
@CobolType(numeric = true)
private String fax1;
//other fields...
@Transient
private Integer isForeign;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomerPerson that = (CustomerPerson) o;
return Objects.equals(accno, that.accno) &&
Objects.equals(row, that.row);
}
@Override
public int hashCode() {
return Objects.hash(accno, row);
}
}
该服务已在@Transactional 的外部服务中调用
@Service
@RequiredArgsConstructor
public class CustomerService {
@Value("${range.trackingCodeThreadLocalKey}")
private String trackingCodeKey;
@Value("${customer.sync.isNewRecord}")
private String isNewRecordKey;
private static final Logger log = LoggerFactory.getLogger(CustomerService.class);
private final CustomerRepository customerRepository;
private final CustomerPersonRepository customerPersonRepository;
private final CustomerCompanyRepository customerCompanyRepository;
private final AccountMapRepository accountMapRepository;
private final AccountTypeMapRepository accountTypeMapRepository;
private final CustomerMapper customerMapper;
private final CompositeCustomerMapper compositeCustomerMapper;
private final RangeService rangeService;
private final ThreadLocalUtil threadLocalUtil;
public String syncAccount(Long newAccountNumber, CustomerAccountResponseDto galaxyData) {
Optional<AccountMapEntity> optAccountMapEntity = accountMapRepository.findByNewAccountNo(newAccountNumber);
CustomerDto customerData = new CustomerDto();
List<CustomerPerson> customerPersonList = null;
List<Customer> customers = null;
CustomerCompany customerCompany = null;
CustomerDto mappedCompositeCustomerPersons;
boolean updateRecord = false;
if (optAccountMapEntity.isPresent()) {
customerData = getCustomerData(optAccountMapEntity.get());
}
String legacyAccountNumber = getLegacyAccountNumber(customerData, galaxyData);
legacyAccountNumber = StringUtil.addLeftLeadingZero(legacyAccountNumber, Constants.Legacy_ACCOUNTNO_MAX);
log.info("######legacyAccountNumber. {}", legacyAccountNumber);
if (CustomerUtil.isCompositePerson(galaxyData)) {
Customer zeroRowCustomer = null;
CustomerPerson zeroRowCustomerPerson = null;
if (!ObjectUtils.isEmpty(customerData.getCustomerList()) &&
!ObjectUtils.isEmpty(customerData.getCustomerPersonList()) &&
customerData.getCustomerList().stream().findFirst().isPresent() &&
customerData.getCustomerPersonList().stream().findFirst().isPresent()) {
updateRecord = true;
mappedCompositeCustomerPersons = compositeCustomerMapper.compositeInquiryToCustomerDto(galaxyData, customerData);
if (mappedCompositeCustomerPersons.getCustomerList().stream().findFirst().isPresent())
zeroRowCustomer = compositeCustomerMapper.toZeroRowCustomer(galaxyData, mappedCompositeCustomerPersons.getCustomerList().stream().findFirst().get());
if (mappedCompositeCustomerPersons.getCustomerPersonList().stream().findFirst().isPresent())
zeroRowCustomerPerson = compositeCustomerMapper.toZeroRowCustomerPeson(galaxyData, mappedCompositeCustomerPersons.getCustomerPersonList().stream().findFirst().get(), mappedCompositeCustomerPersons.getCustomerPersonList());
mappedCompositeCustomerPersons.getCustomerList().set(0, zeroRowCustomer);
mappedCompositeCustomerPersons.getCustomerPersonList().set(0, zeroRowCustomerPerson);
} else {
zeroRowCustomer = compositeCustomerMapper.toZeroRowCustomer(galaxyData, new Customer());
mappedCompositeCustomerPersons = compositeCustomerMapper.compositeInquiryToCustomerDto(galaxyData, null);
zeroRowCustomerPerson = compositeCustomerMapper.toZeroRowCustomerPeson(galaxyData, new CustomerPerson(), mappedCompositeCustomerPersons.getCustomerPersonList());
mappedCompositeCustomerPersons.getCustomerList().add(0, zeroRowCustomer);
mappedCompositeCustomerPersons.getCustomerPersonList().add(0, zeroRowCustomerPerson);
}
customers = mappedCompositeCustomerPersons.getCustomerList();
customerPersonList = mappedCompositeCustomerPersons.getCustomerPersonList();
if (!ObjectUtils.isEmpty(customers)) {
for (Customer customer : customers) {
customer.setAccno(legacyAccountNumber);
}
}
if (!ObjectUtils.isEmpty(customerPersonList)) {
for (CustomerPerson customerPerson : customerPersonList) {
customerPerson.setAccno(legacyAccountNumber);
}
}
} else if (CustomerUtil.isLegalPerson(galaxyData)) {
if (!ObjectUtils.isEmpty(customerData.getCustomerList()) &&
!ObjectUtils.isEmpty(customerData.getCustomerPersonList()) &&
!ObjectUtils.isEmpty(customerData.getCustomerCompany())) {
updateRecord = true;
customerPersonList = customerMapper.realPersonToCustomerPersonList(galaxyData, customerData.getCustomerPersonList());
customerCompany = customerMapper.legalPersonToCustomerCompany(galaxyData, customerData.getCustomerCompany());
customers = customerMapper.accountToCustomer(galaxyData, customerData.getCustomerList(), customerData.getCustomerPersonList(), customerCompany);
} else {
customers = customerMapper.accountToCustomer(galaxyData, new ArrayList<>(), new ArrayList<>(), new CustomerCompany());
customerPersonList = customerMapper.realPersonToCustomerPersonList(galaxyData, new ArrayList<>());
customerCompany = customerMapper.legalPersonToCustomerCompany(galaxyData, new CustomerCompany());
}
if (!ObjectUtils.isEmpty(customers)) {
for (Customer customer : customers) {
customer.setAccno(legacyAccountNumber);
}
}
if (!ObjectUtils.isEmpty(customerPersonList)) {
for (CustomerPerson customerPerson : customerPersonList) {
customerPerson.setAccno(legacyAccountNumber);
}
}
if (!ObjectUtils.isEmpty(customerCompany)) {
customerCompany.setAccno(legacyAccountNumber);
}
} else if (CustomerUtil.isRealPerson(galaxyData)) {
if (!ObjectUtils.isEmpty(customerData.getCustomerList()) &&
!ObjectUtils.isEmpty(customerData.getCustomerPersonList())) {
updateRecord = true;
customerPersonList = customerMapper.realPersonToCustomerPersonList(galaxyData, customerData.getCustomerPersonList());
customers = customerMapper.accountToCustomer(galaxyData, customerData.getCustomerList(), customerData.getCustomerPersonList(), null);
} else {
customers = customerMapper.accountToCustomer(galaxyData, new ArrayList<>(), new ArrayList<>(), null);
customerPersonList = customerMapper.realPersonToCustomerPersonList(galaxyData, new ArrayList<>());
}
if (!ObjectUtils.isEmpty(customers)) {
for (Customer customer : customers) {
customer.setAccno(legacyAccountNumber);
}
}
if (!ObjectUtils.isEmpty(customerPersonList)) {
for (CustomerPerson customerPerson : customerPersonList) {
customerPerson.setAccno(legacyAccountNumber);
}
}
}
if (!ObjectUtils.isEmpty(threadLocalUtil.getKey(isNewRecordKey)) && (Boolean) threadLocalUtil.getKey(isNewRecordKey))// todo it seems shoule be !isEmpty
saveAccountMap(newAccountNumber.toString(), legacyAccountNumber);
saveCustomers(updateRecord, customers, customerPersonList, customerCompany);
return legacyAccountNumber;
}
public void saveAccountMap(String newAccountNumber, String legacyAccountNumber) {
AccountMapEntity accountMapEntity = new AccountMapEntity();
accountMapEntity.setNewAccountNo(Long.valueOf(newAccountNumber));
accountMapEntity.setLegacyAccountNo(Long.valueOf(legacyAccountNumber));
boolean ifExist = accountMapRepository.existsByNewAccountNoOrLegacyAccountNo(Long.valueOf(newAccountNumber), Long.valueOf(legacyAccountNumber));
if (!ifExist) accountMapRepository.saveAndFlush(accountMapEntity);
}
//todo check below for save and flush of list
public void saveCustomers(Boolean updateRecord, List<Customer> customers, List<CustomerPerson> customerPersonList, CustomerCompany customerCompany) {
if (!ObjectUtils.isEmpty(updateRecord) && !ObjectUtils.isEmpty(customers) && !ObjectUtils.isEmpty(customerPersonList)) {
if (!updateRecord) {
customerRepository.saveAll(customers);
customerRepository.flush();
customerPersonRepository.saveAll(customerPersonList);
customerPersonRepository.flush();
} else {
for (Customer customer : customers) {
Optional<Customer> optCustomerById = customerRepository.findById(customer.getNewlabChrono());
if (optCustomerById.isPresent()) {
Customer customer1 = optCustomerById.get();
BeanUtils.copyProperties(customer, customer1);
boolean equals = customer1.equals(customer);
System.out.println(equals);
String s = customer1.toString();
customerRepository.saveAndFlush(customer1);
log.info("customer updated");
}
}
for (CustomerPerson customerPerson : customerPersonList) {
CustomerPerson cpSaved = customerPersonRepository.findCustomerPersonByNewlabChrono(customerPerson.getNewlabChrono());
BeanUtils.copyProperties(customerPerson, cpSaved);
boolean equals = cpSaved.equals(customerPerson);
System.out.println(equals);
// ###################
customerPersonRepository.saveAndFlush(cpSaved); //Error occurs here
// ###################
log.info("customer person updated");
}
}
if (customerCompany != null)
customerCompanyRepository.saveAndFlush(customerCompany);
}
}
public CustomerDto getCustomerData(AccountMapEntity accountMapEntity) {
List<Customer> customerByAccno = customerRepository.findAllByAccountNumber(String.valueOf(accountMapEntity.getLegacyAccountNo()));
List<CustomerPerson> customerPersonByAccno = customerPersonRepository.findAllByAccountNumber(String.valueOf(accountMapEntity.getLegacyAccountNo()));
CustomerCompany customerCompanyByAccno = customerCompanyRepository.findByAccountNumber(String.valueOf(accountMapEntity.getLegacyAccountNo()));
CustomerDto customerDto = new CustomerDto();
customerDto.setCustomerList(customerByAccno);
customerDto.setCustomerPersonList(customerPersonByAccno);
customerDto.setCustomerCompany(customerCompanyByAccno);
return customerDto;
}
private String getLegacyAccountNumber(CustomerDto customerData, CustomerAccountResponseDto galaxyData) {
String legacyAccountNumber = null;
if (!ObjectUtils.isEmpty(customerData) && !ObjectUtils.isEmpty(customerData.getCustomerList())) {
Optional<Customer> optCustomer = customerData.getCustomerList().stream().findFirst();
if (optCustomer.isPresent()) {
Customer customer = optCustomer.get();
legacyAccountNumber = customer.getAccno();
}
} else {
Optional<AccountTypeMap> optAccountTypeMap = accountTypeMapRepository.findByAccountTypeCodeAndAccountSubTypeCode(galaxyData.getAccount().getAccountTypeCode(), galaxyData.getAccount().getAccountSubTypeCode());
if (optAccountTypeMap.isPresent()) {
AccountTypeMap accountTypeMap = optAccountTypeMap.get();
String accountGroup = accountTypeMap.getAccountGroup();
String branchCode = galaxyData.getAccount().getAccountTypeCode();
String cbiDb = accountTypeMap.getCbiDb();
String cbiCr = accountTypeMap.getCbiCr();
String cbkDb = accountTypeMap.getCbkDb();
String cbkCr = accountTypeMap.getCbkCr();
GenerateAccountNumberResponse response = rangeService.generateAccountNumber(branchCode, accountGroup, cbiDb, cbiCr, " 25E", " 60A");
legacyAccountNumber = response.getResponse().getAccountNo().toString();
threadLocalUtil.addKey(trackingCodeKey, response.getResponse().getTrackingCode());
threadLocalUtil.addKey(isNewRecordKey, true);
}
}
log.warn("######### legacyAccountNumber {}", legacyAccountNumber);
return legacyAccountNumber;
}
}
当我调试或运行应用程序时,Customer 可以更新,但是当我想更新 CustomerPerson 时,它会在 PK 上抛出 ConstraintViolationException 以更新实体。有什么建议吗?我认为它与equals and hashCodes 有一些关系,但我写的equals and hashCodes 与Customer 相同。
外部服务是 SyncLegacyAccountServiceImpl
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class SyncLegacyAccountServiceImpl implements ISyncLegacyAccountService {
private static final Logger log = LoggerFactory.getLogger(GalaxyService.class);
@Value("${range.trackingCodeThreadLocalKey}")
private String trackingCodeKey;
@Value("${customer.sync.isNewRecord}")
private String isNewRecordKey;
private final IMQService iMQService;
private final IAccountRequestService iAccountRequestService;
private final CustomerService customerService;
private final GalaxyService galaxyService;
private final RangeService rangeService;
private final ThreadLocalUtil threadLocalUtil;
@Override
@Transactional
public void handleSyncRequest(Event event) {
try {
rangeCompensation();
Long newAccountNumber = Long.valueOf(event.getArgument().get(Constants.KEY_ACCOUNT_NO_MQ).toString());
CustomerAccountResponseDto galaxyData = galaxyService.getGalaxyData(String.valueOf(newAccountNumber));
String legacyAccountNumber = customerService.syncAccount(newAccountNumber, galaxyData);
log.info("legacy no {}",legacyAccountNumber);
iMQService.send(MQUtil.buildAccountChangeResponse(null, legacyAccountNumber, event.getMessageId()));
iAccountRequestService.saveSuccessfulAccountRequest(event);
log.info("saved succed");
updateRangeToFinal();
log.info("updateRangeToFinal");
} catch (Exception exception) {
log.error(exception.toString());
updateRangeToRevoke();
}
}
private void updateRangeToFinal() {
Boolean isNewRecord = (Boolean) threadLocalUtil.getKey(isNewRecordKey);
if (!ObjectUtils.isEmpty(isNewRecord)) {
if (isNewRecord) {
rangeService.updateToFinal(String.valueOf(threadLocalUtil.getKey(trackingCodeKey)));
removeFromThreadLocal(trackingCodeKey);
removeFromThreadLocal(isNewRecordKey);
}
}
}
private void updateRangeToRevoke() {
Boolean isNewRecord = (Boolean) threadLocalUtil.getKey(isNewRecordKey);
if (!ObjectUtils.isEmpty(isNewRecord)) {
if (isNewRecord) {
rangeService.updateToRevoke(String.valueOf(threadLocalUtil.getKey(trackingCodeKey)));
removeFromThreadLocal(trackingCodeKey);
removeFromThreadLocal(isNewRecordKey);
}
}
}
private void rangeCompensation() {
if (!ObjectUtils.isEmpty(threadLocalUtil.getKey(trackingCodeKey)) && !ObjectUtils.isEmpty(threadLocalUtil.getKey(isNewRecordKey))) {
updateRangeToRevoke();
}
}
private void removeFromThreadLocal(String key) {
threadLocalUtil.removeKey(key);
}
日志
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [SGB.C_PR_PK]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only
我知道在这种情况下 ViolationException 是什么。但这很奇怪,因为以同样的方式,Customer 实体会正确更新。但是当它想要更新 CustomerPerson 时,它会抛出这个异常。我检查了equals 方法以确保更新的对象与 Db 对象相同(ID-->newlabChrono)。
【问题讨论】:
-
A) 请在代码中指定发生错误的行,B) 请粘贴完整的堆栈跟踪,C) 如有必要,请查看休眠日志(启用调试),并粘贴 SQL 查询这个给您带来问题的特定请求。
-
对于A,我写了发生错误的那一行。但是这里不支持行号:(。
customerPersonRepository.saveAndFlush(cpSaved); //这里发生错误 -
我更新了帖子。
-
您是自己创建表还是 JPA?如果您自己,请出示 SQL 代码,我们需要看看是什么决定了您的 CustomerPerson 表与 Customer 的 PK。
-
其实是一个视图,不是我创建的。
标签: java spring spring-boot spring-data-jpa spring-data