将未提交的域对象从主线程共享到其他线程

时间:2018-09-29 01:41:34

标签: multithreading hibernate grails groovy gorm

我有一个简单的过程,可以在我的应用程序中上载和处理员工。我有两个域对象,一个 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会话。我该如何解决?

0 个答案:

没有答案