我在保存具有oneToOne / oneToMany / ManyToMany类型关系的实体“employee”时遇到此问题。
我使用Spring引导+ Spring Data JPA与Hibernate和postgres作为db。
请查看以下课程。
员工类 -
@Entity
@Table(name = "Employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "emp_id")
private int emp_id;
@Column(name = "emp_name")
private String emp_name;
@Column(name = "d_o_b")
private Date date_of_birth;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "community_employee_mapping", joinColumns = { @JoinColumn(name = "employee_id") }, inverseJoinColumns = { @JoinColumn(name = "community_id") })
private List<Community> listOfCommunities = new ArrayList<>();
@OneToOne(cascade = CascadeType.ALL)
private Department dept;
@OneToOne(cascade = CascadeType.ALL)
private Address address;
DepartMent课程 -
@Entity
@Table(name = "department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int dept_id;
@Column(name = "dept_name")
private String departmentName;
@Column(name = "dept_desc")
private String departmentDesc;
@OneToMany(mappedBy = "dept", cascade = CascadeType.ALL)
private List<Employee> lemp = new ArrayList<>();
社区类 -
@Entity
@Table(name = "community")
public class Community {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "com_id")
private int community_id;
@Column(name = "name")
private String community_name;
@ManyToMany(mappedBy = "listOfCommunities", cascade = CascadeType.ALL)
private List<Employee> listOfEmployees = new ArrayList<>();
@Column(name = "description")
private String description;
地址类 -
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private int add_id;
@Column(name = "state")
private String state;
@Column(name = "city")
private String city;
@Column(name = "zip_code")
private String zip_code;
@Column(name = "country")
private String country;
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL)
private Employee emp;
以下是我的春季启动@test方法 -
@Autowired
private EmployeeRepo erepo;
@Autowired
private CommunityRepo crepo;
@Autowired
private DeptRepo drepo;
@Autowired
private AddressRepo arepo;
@Test
public void contextLoads() {
int max = 1 * 1000 * 100;
Date date = new GregorianCalendar(1992, 06, 18).getTime();
long start = System.currentTimeMillis();
for (int index = 0; index < 50000; index++) {
Employee emp0 = new Employee();
Employee emp1 = new Employee();
Employee emp2 = new Employee();
emp0.setEmp_name(RandomStringUtils.randomAlphabetic(10) + " " + RandomStringUtils.randomAlphabetic(5));
emp0.setDate_of_birth(DateUtils.addDays(date, MathUtil.nextInt(0, 5000)));
emp1.setEmp_name(RandomStringUtils.randomAlphabetic(10) + " " + RandomStringUtils.randomAlphabetic(5));
emp1.setDate_of_birth(DateUtils.addDays(date, MathUtil.nextInt(0, 5000)));
emp2.setEmp_name(RandomStringUtils.randomAlphabetic(10) + " " + RandomStringUtils.randomAlphabetic(5));
emp2.setDate_of_birth(DateUtils.addDays(date, MathUtil.nextInt(0, 5000)));
Community comm0 = new Community();
comm0.setCommunity_name(RandomStringUtils.randomAlphabetic(10) + " " + RandomStringUtils.randomAlphabetic(6));
comm0.setDescription(RandomStringUtils.randomAlphabetic(20));
Community comm1 = new Community();
comm1.setCommunity_name(RandomStringUtils.randomAlphabetic(10) + " " + RandomStringUtils.randomAlphabetic(6));
comm1.setDescription(RandomStringUtils.randomAlphabetic(20));
List<Employee> lemp = new ArrayList<>();
lemp.add(emp0);
lemp.add(emp1);
comm0.setListOfEmployees(lemp);
List<Community> lcomm = new ArrayList<>();
lcomm.add(comm0);
emp0.setListOfCommunities(lcomm);
emp1.setListOfCommunities(lcomm);
List<Employee> lemp2 = new ArrayList<>();
lemp2.add(emp2);
comm1.setListOfEmployees(lemp2);
List<Community> lcomm2 = new ArrayList<>();
lcomm2.add(comm1);
emp2.setListOfCommunities(lcomm2);
Department dept0 = new Department();
dept0.setDepartmentDesc(RandomStringUtils.randomAlphabetic(25));
dept0.setDepartmentName(RandomStringUtils.randomAlphabetic(5));
Department dept1 = new Department();
dept1.setDepartmentDesc(RandomStringUtils.randomAlphabetic(25));
dept1.setDepartmentName(RandomStringUtils.randomAlphabetic(5));
List<Employee> lempp = new ArrayList<>();
lempp.add(emp0);
lempp.add(emp1);
dept0.setLemp(lemp);
emp0.setDept(dept0);
emp1.setDept(dept1);
List<Employee> lempp2 = new ArrayList<>();
lempp2.add(emp2);
dept1.setLemp(lempp2);
emp2.setDept(dept1);
Address add0 = new Address(RandomStringUtils.randomAlphabetic(7), RandomStringUtils.randomAlphabetic(5), String.valueOf(MathUtil.nextInt(999999, 9999999)),
RandomStringUtils.randomAlphabetic(5), emp0);
Address add1 = new Address(RandomStringUtils.randomAlphabetic(7), RandomStringUtils.randomAlphabetic(5), String.valueOf(MathUtil.nextInt(999999, 9999999)),
RandomStringUtils.randomAlphabetic(5), emp1);
Address add2 = new Address(RandomStringUtils.randomAlphabetic(7), RandomStringUtils.randomAlphabetic(5), String.valueOf(MathUtil.nextInt(999999, 9999999)),
RandomStringUtils.randomAlphabetic(5), emp2);
emp0.setAddress(add0);
emp1.setAddress(add1);
emp2.setAddress(add2);
// erepo.save(emp0);
// erepo.save(emp1);
// erepo.save(emp2);
List<Employee> saveEmp = new ArrayList<>();
saveEmp.add(emp0);
saveEmp.add(emp1);
saveEmp.add(emp2);
erepo.saveAll(saveEmp);
}
long end = System.currentTimeMillis();
long elapsedTime = end - start;
System.out.println("elapsed : " + (elapsedTime) + " mili sec.........");
System.out.println("done writing to db ======================================================================");
}
我在每个关系中都使用CascadeType.ALL,所以只保留父实体,即Employee。
当我在下面做的时候,整个代码完全正常。这种方法的问题是它很慢,因为我们在后面打开三个会话并关闭,而我们有saveAll(可迭代的args)方法,可以在单个会话中完成。
// erepo.save(emp0);
// erepo.save(emp1);
// erepo.save(emp2);
不写
erepo.saveAll(saveEmp);
然而,当我从erepo写saveAll时,它会创建一个我们将其作为可迭代参数传递的所有项的arrayList。下面是Spring框架的SimpleJPArepository类的代码片段。
@Transactional
public <S extends T> List<S> saveAll(Iterable<S> entities) {
Assert.notNull(entities, "The given Iterable of entities not be null!");
List<S> result = new ArrayList<S>();
for (S entity : entities) {
result.add(save(entity));
}
return result;
}
我想在这里确认两件事......
1)因为我没有将任何ID附加到任何实体并让它在运行时使用@GeneratedValue生成。虽然持久化实体hibernate试图将id附加到实体,从而改变其状态并导致ConcurrentModificationException。
2)我可以通过使用CopyOnWriteArrayList使其工作,但这将再次消耗堆中的空间,因为它将克隆整个对象图,因此性能肯定会有所偏差。
有没有办法可以坚持使用saveAll()而不会有任何性能损失。
如果我在任何地方都错了,请纠正我。