这可能是Java线程还是Hibernate问题?

时间:2014-08-22 21:03:13

标签: java hibernate sequence

我面临下面的问题 - 无法在Performance或更低的环境中重现它,但只有在Prod使得调试有点困难,因此如果我能得到一些线索在这里发布。 试图让它尽可能短,但仍然很长..


问题: 在两步订单创建过程中,即创建客户+提交订单 - 我们将获得唯一约束违规,其中单个客户ID被分配给在多个位置创建的订单。

不确定哪里出错了。 我找不到的东西很少

  1. Oracle在生成序列方面是独一无二的
  2. Hibernate的默认分配大小为50,并且在术语上进行了相当优化 发放那50个序列
  3. 这让我觉得可能有一些线程在实体拷贝时劫持了这个序列 发生在某个地方,大约有下面两种方法。
  4. Pom Entry如下所示,Spring / Hibernate堆栈的版本,数据库是Oracle

    <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <spring.version>3.2.1.RELEASE</spring.version>
            <hibernate.version>4.1.10.Final</hibernate.version>
            <thymeleaf.version>2.1.0.RELEASE</thymeleaf.version>
            <tiles.version>2.2.2</tiles.version>
        </properties>
    

    客户对象如下

    @Entity
    @Table(name = "CUSTOMER")
    public class Customer implements Serializable {
        private static final long serialVersionUID = 1L;
    
        @SequenceGenerator(name="CUSTOMER_SEQUENCE_GENERATOR", 
            sequenceName="CUSTOMER_SEQ", allocationSize = 1)
    
        @Id
        @GeneratedValue(strategy=GenerationType.SEQUENCE, 
            generator="CUSTOMER_SEQUENCE_GENERATOR")
        @Column(name = "CUSTOMER_ID", unique = true, nullable = false)
        private Integer id;
    

    从3个控制器和2个服务方法等各个地方调用此代码片段 - 可以说遍布整个代码。

     Customer customer = createCustomerEntity(newcustomer);
     customer = customerManagementDAO.addUpdateCustomer(customer);
    

    以下两种方法的细节

    我不确定以下代码中的某些内容是否在线程处理点出现错误

        private Customer createCustomerEntity(CustomerBean newcustomer) 
                     throws InternalBusinessException {
              Customer customer = null;
                try{
                // If Loop1
                if(newcustomer.getInternalcustomerid() == null){
                     customer = new Customer();
                  customer.setCustomerNumber(newcustomer.getExternalSystemCustomerid());
                }
                // If Loop2
                if(newcustomer.getInternalcustomerid() != null){
                    //if a new customer going for new  enrollment , 
                    // we lookup up the customer in DB based on 
                    // InternalCustomerId and merge the customer.
                    Integer customerIdInternal = null;
                    // Below Call goes to Internal Database to find existing Customer
                    Customer customerEntity  = orderManagementDAO.findExistingCustomerByCustomerId(
                                    newcustomer.getEoecustomerid().toString());
                    if(customerEntity != null){
                    customer = new Customer();  
                    customer.setCustomerNumber(
                                    newcustomer.getExternalSystemCustomerid()); 
                    customerIdInternal = customerEntity.getId();
                    if (customerIdInternal != null) {
                         customer.setId(customerIdInternal);
                    }
                }
                //In case of customer look up if customer with same 
                // External System's id exists we merge the same customer.
                // If Loop3
    if(newcustomer.getExternalSystemCustomerid() != null) {   
                    // Below call goes to external System to find existing Customer Number
                    Customer customerEntity = orderManagementDAO.findExistingCustomerByCustomerNumber(
                                    newcustomer.getExternalSystemCustomerid().trim());
                    Integer customerIdInternal = null;
                    if(customerEntity != null) {
                        customer = new Customer();
                        customer.setCustomerNumber(
                                    newcustomer.getExternalSystemCustomerid());
                        customerIdInternal = customerEntity.getId();
                     }
                    if (customerIdInternal != null) {
                        customer.setId(customerIdInternal);
                    }            
                }
                // End of If loop3
                customer.setEmail(newcustomer.getEmail()); //<== We have null pointers at this point in logs
                customer.setFirstName(newcustomer.getFirstname());
                customer.setLastName(newcustomer.getLastname());
    
                } catch (RuntimeException e) {
                    throw new InternalBusinessException("createCustomerEntityForEOE failed", e);
                }
                return customer;
            }
    
    • 日志显示在第2循环和第2循环中打印相同的客户ID。 Loop3在具有不同线程的多个实例中

    • 在customer.setEmail的Loop3结束时出现空指针

    Dao Code如下

    @SuppressWarnings("unchecked")
        @Override
        public Customer addUpdateCustomer(Customer customer) 
                throws InternalDataAccessException {
            if (customer.getId() != null && customer.getId() != 0)
                saveMerge(customer);
            else
                save(customer);
            return customer;
        }
    

    如果您觉得代码的其他部分可以为此问题增加清晰度,请告诉我。

1 个答案:

答案 0 :(得分:0)

此问题最终成为业务案例场景问题,并在整个创建客户流程移至Oracle DB中的存储产品时得到解决

我们有一个Table Cust #Reinquished从一个Range中取出Active Customer No,如果消耗了它们,则设置一些新的范围或者增加no并执行SaveMerge()

这3个Hibernate查询步骤已更改为One Stored Proc,它运行正常。