2010-11-10 2 views
1

я написал этот простой пример:Весна и @transactional, это нормально?

//file TestController.java 
public interface TestController { 

    public List<Test> findAll(); 

} 

//file TestControllerImp.java 
@Controller 
public class TestControllerImp implements TestController{ 

    @Autowired 
    private SessionFactory sessionFactory; 

    public void setSessionFactory(SessionFactory sessionFactory) { 
     this.sessionFactory=sessionFactory; 
    } 

    public List<Test> findAll() { 
     return sessionFactory.getCurrentSession().createQuery("from Test").list(); 
    } 

} 

//file TestService.java 
@Service 
public class TestService { 

    @Autowired 
    private TestController controller; 

    public boolean flag=true; 

    public void setController(TestController controller){ 
     this.controller=controller; 
    } 

    @Transactional 
    public List<Test> useController(){ 
     flag=false; 
     return controller.findAll(); 
    } 

} 

И это моя попытка:

TestService s1=context.getBean(TestService.class); 
TestService s2=context.getBean(TestService.class); 
List<Test> list=s1.useController(); 
System.out.println(s1.flag+" "+s2.flag); 

Теперь странное поведение (им очень новый с пружиной):

  1. Если я объявляю @Transactional метод «useController()», выход: true true
  2. Если я переведу @Transactional от TestService - TestControllerImp, и я объявляю «findAll()» с @Transactional, вывод: false false.

Почему у меня такое поведение? Я знаю по умолчанию @Autowired классы одиночные, но почему в первом случае флаг по-прежнему остается верным?

Спасибо всем.

ответ

5

Механизм @Transactional работает на прокси-серверах JDK по умолчанию и работает только на интерфейсах.

Так что если вы дадите TestService быть интерфейсом и TestServiceImpl быть его реализацией, то приведенный выше код должен работать.

например. изменить объявление класса это:

@Service 
public class TestServiceImpl implements TestService { 

но тестовый код должен ссылаться на интерфейс, а не класс:

// this code remains unchanged 
TestService s1=context.getBean(TestService.class); 
TestService s2=context.getBean(TestService.class); 

Ссылка:

+0

Так что @Transactional работает, только если вы используете его в реализации интерфейса? – chzbrgla

+0

Да, если вы не используете ''. Затем CGLIB будет использоваться для создания динамических подклассов –

+0

@seanizer: Спасибо, поэтому для каждого класса сервиса я должен написать интерфейс и его реализацию? Могу ли я изменить механизм @Transactional по умолчанию? Вы говорите, что работа над JDK, но отладка s1 и s2 я вижу TestService $$ EnhancerByCGLIB $$ 51486891, поэтому я думаю, что это работает на CGLIB, а не правда? – blow

Смежные вопросы