问题
I'm debugging a java based web application. There is an issue reported from our production environment where multiple records were inserted in table, but other records was not valid
Production issue results:
Header Table
HDR_NO HDR_COL1 HDR_COL1 DOCUMENT_DATE
HDR44 68 327 6/6/2014 14:22
HDR45 68 327 6/6/2014 14:24--invalid data
HDR46 68 327 6/6/2014 14:24--invalid data
Detail Table
DTL_NO HDR_NO DTL_COL1 DTL_COL1
DTL76 HDR44 SR1439 4337
DTL77 HDR45 SR1439 4337--invalid data
DTL78 HDR46 SR1439 4337--invalid data
Production issue results:
(expected result: Only one record for each table).
I tried to replicate this issue in my local environment by sending three consecutive httpservletrequest.
Two requests were filtered in our validations, because it will try to insert three instance of
header with same HDR_NO as id.
One record inserted for each table in my testing. My question now is, what caused this bug?
My code looks like the code below. Please help.
Thanks in advance,
public class MyController extends SimpleFormController{
public ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,Object
private MyService myService
command, BindException errors){
BeanParam bean = buildBeanParam(request);
myService.doTransaction(bean);
}
}
public class MyService{
public void doTransaction(BeanParam bean){
try{
List Item items = getItems(bean);// query with one result
Header header = createHeader();//mysterious bug occur
populateDetails(header, items);//mysterious bug occur
} catch (GenerateIdException e) {
e.printStackTrace();
}
}
public Header createHeader(){
Header header = new Header();
// generates a number with common prefix
header.setHeaderNo(headerNumberGenerator());
header.setDocumentDate(new Date());
header.setHdrcol1("String 1");
header.setHdrcol2("String 2");
return headerDao.save(header);
}
public void populateDetails(Header header, List;Item; items){
for(Item item: items){
//items.size() == 1, so one record in Detail Table is expected
Detail detail = new Detail();
// generates a number with common prefix
detail.setDetailNo(detailNumberGenerator());
detail.setDocumentDate(new Date());
detail.setDtlcol1(item.getField1());
detail.setDtlcol2(item.getField2());
detail.setHeader(header);
detailDao.save(detail);
}
}
}
public class Header{
@Id
@Column(name = "HDR_NO", length = 20)
private String headerNo;
@Temporal(TemporalType.DATE)
@Column(name = "DOCUMENT_DATE")
private Date documentDate;
@Column(name = "HDR_COL1")
private String hdrcol1;
@Column(name = "HDR_COL2")
private String hdrcol2;
@OneToMany(mappedBy = "header")
@Cascade(value = { CascadeType.PERSIST, CascadeType.MERGE })
private List Details details;
//Getters and Setters
}
public class Details{
@Id
@Column(name = "DTL_NO")
private String detailNo;
@ManyToOne
@JoinColumn(name = "HDR_NO", referencedColumnName = "HDR_NO")
private Header header;
@Column(name = "DTL_COL1")
private String dtlcol1;
@Column(name = "DTL_COL2")
private String dtlcol2;
//Getters and Setters
}
public class Item{
@Column(name = "FIELD1")
private field1;
@Column(name = "FIELD2")
private field2;
//Getters and Setters
}
回答1:
It's not clear in your question how you are doing the "validation", but since the database allows duplicates it suggests that the validation is being done in the app layer, and that there are no primary/unique key constraints.
The trouble with doing with validation yourself is how do you that between the time you ran a SELECT to check for existence and when you INSERT, that someone else hasn't snook in and inserted? May only be a few milliseconds difference, which is why it will be difficult to replicate.
来源:https://stackoverflow.com/questions/24626103/why-does-oracle-java-creates-multiple-records-in-one-execution