我有一个简单的过程,可以在我的应用程序中上载和处理员工。我有两个域对象,一个 public Connection getConnection(){
try {
String url = "amqp://log_uploader:HuaweiMsdp2018!@10.193.17.19:5672/%2f";
mFactory = new ConnectionFactory();
mFactory.setAutomaticRecoveryEnabled(true);
mFactory.setHandshakeTimeout(1000000000);
mFactory.setRequestedHeartbeat(600);
//mFactory.useSslProtocol();
mFactory.setUri(url);
mConnection = mFactory.newConnection();
if(mConnection == null)
return null;
return mConnection;
} catch (IOException | NoSuchAlgorithmException | URISyntaxException | TimeoutException | KeyManagementException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public void setup() throws IOException, TimeoutException, NoSuchAlgorithmException, KeyManagementException, URISyntaxException {
mConnection = getConnection();
// Create a channel from the factory
mChannel = mConnection.createChannel();
mChannel.exchangeDeclare(RABBITMQ_EXCHANGE, "topic", true);
// Create a queue declare
mChannel.queueDeclare(GZ_QUEUE, true, false, false, null);
mChannel.queueDeclare(CSV_QUEUE, true, false, false, null);
mChannel.queueDeclare(PLAINTEXT, true, false, false, null);
return;
}
和一个Employee
。协会是一对多的。
这是我的域对象
Company
此过程是class Employee {
String id
String firstName
String lastName
String email
Company company
static mapping = {
table name: "employee"
id column: "employee_id", generator:"assigned"
version false
}
}
class Company {
String id
String name
static hasMany = [employees:Employee]
static mapping = {
table name: "company"
id column: "company_id", generator:"assigned"
autoImport false
version false
}
}
上载包含User
的文件并指定一个新的Employees
。我的Company
创建了Service
,然后通过Company
创建了10个线程来处理解析和保存ExecutorService
。
我的控制器
Employees
我的class CompanyController {
static scope = "singleton"
CompanyService companyService
def createCompany(CreateCompanyCommand createCompanyCmd){
companyService.createCompany(createCompanyCmd)
render(status: 200)
}
}
负责创建CompanyService
,然后调用Company
创建EmployeeService
。
Employees
我的class CompanyService {
EmployeeService employeeService
SessionFactory sessionFactory
public void createCompany(createCompanyCmd){
Company company = saveCompany(createCompanyCmd)
employeeService.createEmployees(company.id, createCompanyCmd.employeeFile)
}
public Company saveCompany(createCompanyCmd){
Company company = new Company()
company.id = createCompanyCmd.id
company.name = createCompany.name
// NOTE: flushing here
company.save(flush: true, failOnError: true)
return company
}
}
通过多个线程创建员工。
EmployeeService
这给了我以下错误:
class EmployeeService {
public void createEmployees(companyId, employees){
// Find the new created company - this is on the main thread
Company company = Company.findById(companyId)
def lines = parseEmployees(employeeFile) // Method not shown, but it returns a List that contains info about each employee to create the Employee Object
ExecutorService executor = Executors.newFixedThreadPool(10)
List futures = new ArrayList()
lines.each { line ->
final def fLine = line // found this necessary to make the field actually final. Have a SO question regarding this, but don't believe it is related to my problem here.
Future future = executor.submit(new Callable() {
public def call() throws Exception {
def employee = saveEmployee(fLine, company)
return employee
}
});
futures.add(future)
}
executor.shutdown()
for(Future future : futures){
def employee = future.get()
println employee
}
}
public Employee saveEmployee(line, company) {
Employee employee = new Employee()
employee.firstName = line.firstName
employee.lastName = line.lastName
employee.email = employee.email
employee.id = line.id
employee.company = company //ERROR HERE
}
}
我相信我了解这个问题。即使我在保存Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Not-null property references a transient value - transient instance must be saved before current operation : com.example.Employee.company -> com.example.Company; nested exception is org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : com.example.Employee.company -> com.example.Company
时“刷新”会话,也没有提交事务。因此,正在保存Company
对象的线程认为尚未保存与其相关的Employee
对象。我该如何解决?如果我不执行任何多线程操作,而是将雇员保存在主线程中,则它可以正常工作。
这有效:
Company
此外,如果我尝试在保存def lines = parseEmployees(employeeFile)
lines.each { line ->
saveEmployee(line, company) // saving on the Main Thread
}
之前从数据库中获取新的Company
对象,它将返回null。
Employee
这对我来说很有意义,因为线程没有使用相同的Hibernate会话,并且感觉到public Employee saveEmployee(line, company) {
Company companyFromDB = Company.findById(company.id) // returns null
Employee employee = new Employee()
employee.firstName = line.firstName
employee.lastName = line.lastName
employee.email = employee.email
employee.id = line.id
employee.company = companyFromDB
}
对象已刷新,但是事务未提交,线程看不到它。
所以我相信我理解为什么它不起作用,但是我不确定如何解决这个问题。我想将所有事务都放在一个事务下(在一个事务下创建公司和员工),但是我不确定如何从Main线程与其他线程共享Hibernate会话。我该如何解决?