1

We have several classes for writing to and reading from our database layer in a Command-Query-Separation fashion.

Each of these classes are annotated with @Transactional respectively with @Transactional(readOnly = true).

Now we've implemented a data import which is creating many objects and writing them to the database using our command-layer.

For now, each write of a single object is done within its own transaction, and I am pretty sure that's a major performance killer.

Is there a simple way to annotate the data import class in a way, that even though it calls many @Transactional annotated methods in the command layer many times, all would be done in a single transaction?

Is this even a valid approach for improving insertion-performance, or would you consider this a bad idea?

SebastianRiemer
  • 1,495
  • 2
  • 20
  • 33
  • 4
    Just annotate the parent method. The one that calls them all. Doing all this in an single transaction would in fact be preferable as then the whole lot will be done together... – Boris the Spider Sep 27 '16 at 16:10
  • I've already tried that, with seemingly no effect - isn't it so, that a \@Transactional method which calls \@Transactional method from another instance, that automatically leads to a new transaction being created? – SebastianRiemer Sep 27 '16 at 16:12
  • Depends. In your method in autowired through an `interface`? Are you using AspectJ weaving? – Boris the Spider Sep 27 '16 at 16:13
  • 3
    @SebastianRiemer You'd need to have `Propagation.REQUIRES_NEW` for new transactions to be created. By default it would join the existing transaction. – Kayaman Sep 27 '16 at 16:14
  • @BoristheSpider: No, all autowiring is done on concrete classes. I don't think we use AspectJ weaving, but I am not sure about that. We've got an aspect wrapping around each command-method, which logs the call to the database. Maybe this could have an impact on the transaction handling? furthermore on each write we generate a primary key for which we'll occasionally fetch the next free values from a lookup table in the db. for that, we create a separate connection. I think that could too interfere with my desire of having only a single transaction. – SebastianRiemer Sep 27 '16 at 16:32
  • I'll look into these things - so normally, annotating the parent caller class method is sufficient to let all annotated callee methods run in one transaction. Good to have that confirmed – SebastianRiemer Sep 27 '16 at 16:35
  • This sounds like a rather large ... mess. Not sure you can fix it. You could try manually creating a transaction and other methods should join it. You would have to set the isolation mode to "read uncommitted" or similar so that your other connection could see the data already written but not yet committed to determine new ids. Horrible. – Boris the Spider Sep 27 '16 at 16:35
  • 1
    @SebastianRiemer not normally at all. Only if Spring can inject code. If you autowire an `interface` then spring can easily create a proxy to do this; otherwise you need to use more exotic means - such as AspectJ load time weaving. All in all, wiring by `interface` is the only sensible way to use modern Spring. – Boris the Spider Sep 27 '16 at 16:36

1 Answers1

0

Mistake One: I used an ExecutorService, as I read in this post How to use spring transaction in multithread spring does not support multi-threading in combination with transactions.

Mistake Two: I replaced the ExecutorService, called the spring managed class method with the annotation @Transactional directly, but this time it didn't work since the class was nested within the calling class, thus it was not regarded as a call "from outside".

Community
  • 1
  • 1
SebastianRiemer
  • 1,495
  • 2
  • 20
  • 33