Domanda

I'm using a UnitOfWork in a background task method (operated by Quartz) with Guice-persist on top of hibernate. The background task call a service, which need to commit the current transaction in the middle of it's task - and continue on another transaction. How can I commit the current UnitOfWork and create a new one?

class BackgroundJob {
    @Inject UnitOfWork unitOfWork;
    @Inject MyService myService;
    public void run() {
        try {
            unitOfWork.begin();
            myService.foo();
        } finally {
            unitOfWork.end();
}   }   }

class MyServiceImpl implements MyService {
    @Override public void foo() {
        foo1();
        // I would like to commit here and start a new transaction
        foo2();
}   }

The service is also managed by Guice, but is a singleton, and do not have access to the caller UnitOfWork as is.

Ideally I do not want to change service signature. A workaround is for the caller to give two UnitOfWork as parameters to foo(), but this seems a bit hacked.

EDIT: For ease of use of future fellow reader, here is my implementation of the solution given by ColinD, which fits the bill nicely:

class BackgroundJob {
    @Inject UnitOfWork unitOfWork;
    @Inject MyService myService;
    public void run() {
        try {
            unitOfWork.begin();
            myService.foo();
        } finally {
            unitOfWork.end();
}   }   }

class MyServiceImpl implements MyService {
    @Override public void foo() {
        foo1();
        foo2();
    }
    @Transactional private void foo1() { ... }
    @Transactional private void foo2() { ... }
}
È stato utile?

Soluzione

If I recall correctly, a unit of work in Guice Persist is not a single transaction. Rather, it represents a single unit of work such as a single web request or, in your case, a single background job. I believe that a single database connection is used for a whole unit of work, but that unit of work may have multiple distinct transactions. In fact, I think that just starting and ending a unit of work will not cause any transactions to be started or ended.

I think what you want to do is to annotate both foo1() and foo2() (but not foo()) with @Transactional. As long as there's no outer transaction wrapping both calls, they'll each run in a separate transaction.

Altri suggerimenti

This may fit the bill.

class BackgroundJob {
    @Inject UnitOfWork unitOfWork;
    @Inject MyService myService;

    public void run() {
        try {
            unitOfWork.begin();
            myService.foo1();
            unitOfWork.end();
           unitOfWork.begin();
            myService.foo2();
            unitOfWork.end();
        } finally {
            unitOfWork.end();
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top