1

I have a similar piece of code inside a @Service:

@Autowired
private MyDAO myDAO;

@Transactional
@Override
public void m(...) {
    Integer i = null; // this is just to simulate a NPE
    myDAO.saveX(...);
    i.toString(); // throws NullPointerException
    myDAO.saveY(...);
}

This piece of code throws a NPE which is not catched by Spring and so my code is not rolled back. Any idea why is this happening?

I have the same configuration as in other places in my app and in those places it works as expected.

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
tzortzik
  • 4,993
  • 9
  • 57
  • 88
  • You are calling `toString` on a null object. Stop doing that. Also, duplicate of: http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it/218510#218510 – The Head Rush Mar 10 '17 at 14:36
  • 1
    Is it an internal call? Are you sure the bean is managed by Spring? – galusben Mar 10 '17 at 14:37
  • @TheHeadRush This is just a simulation. In my real case I use an `ImmutableMap` from `commons` and somehow a parameters is `null` and so it throws a NPE. Let's focus on the actual problem. – tzortzik Mar 10 '17 at 14:38
  • Maybe `myDAO.saveX` commit transaction or transaction manager not pick up @Transactional annotation in that file – user1516873 Mar 10 '17 at 14:39
  • @user1516873 I believe the second one may be the issue but I don't know how can I see if this is the real reason. – tzortzik Mar 10 '17 at 14:40
  • 2
    You can mark transaction with @Transactioanal(read-only=true), if you get exception like 'cannot modify data in read-only transaction', transaction manager configured properly. – user1516873 Mar 10 '17 at 14:43
  • I did the read-only=true test and everything worked like before, so it seems my @Transactional is not taken into consideration. But I can't figure out why. – tzortzik Mar 10 '17 at 14:47
  • @tzortzik how you configure transaction manager? Please add config to question, just in case. – user1516873 Mar 10 '17 at 15:18

3 Answers3

4

Possible reasons:

  1. Your bean is not managed by Spring, a.k.a created with new instead of taken from the application context.

  2. you're calling the m() method in another method of the same class/bean. By default Spring uses proxies to manage declarative transactions and internal calls are not supported.

  3. you're throwing checked exception and not using @Repository on the dao. Declarative transactions work only for runtime exceptions. @Reposiotry "fixes" that by wrapping all exceptions in a DataAccessException. (probably not the case since NPE is runtime)

Ismael Padilla
  • 5,246
  • 4
  • 23
  • 35
Evgeni Dimitrov
  • 21,976
  • 33
  • 120
  • 145
  • My service is registered is Spring and not created with `new` meaning that I can debug my code using IDE. The `m()` method is called from my `@RestController` and my DAO is a `@Repository`. I believe it may be something related to the configuration of Spring but... I don't know... – tzortzik Mar 13 '17 at 06:28
  • @tzortzik Are you using Spring Boot or you configuring the datasource and teh transaction manager by yourself (if so, can you please add the configuration to the question). – Evgeni Dimitrov Mar 13 '17 at 07:34
  • They are manually configured. I am updating the initial post. – tzortzik Mar 13 '17 at 07:36
1

Try adding rollbackFor parameter to @Transactional annotation

@Transactional(rollbackFor=NullPointerException.class)
Pavoletto
  • 140
  • 10
1

I found the solution here. I have multiple contexts and some of them didn't have <tx:annotation-driven />.

Community
  • 1
  • 1
tzortzik
  • 4,993
  • 9
  • 57
  • 88