Spring Transactional not working

夙愿已清 提交于 2019-12-08 09:39:05

问题


I'v setup a Spring/Hibernate backend based on following example using Spring 4.1 and Hibernate 4.3.6:

http://www.sivalabs.in/2011/02/springhibernate-application-with-zero.html

I basically got everything working so far, but there is one little configuration problem I can't overcome: If I try to save an Entity I get the following StackTrace:

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1135)
at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:620)
at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:617)
at org.springframework.orm.hibernate4.HibernateTemplate.doExecute(HibernateTemplate.java:340)
at org.springframework.orm.hibernate4.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:308)
at org.springframework.orm.hibernate4.HibernateTemplate.save(HibernateTemplate.java:617)
at com.test.database.dao.UserSecurityQuestionDAOImpl.save(UserSecurityQuestionDAOImpl.java:40)
at com.test.database.service.UserSecurityQuestionService.save(UserSecurityQuestionService.java:20)
at com.test.database.UserSecurityQuestionTest.basicCreationAndRetrievalTest(UserSecurityQuestionTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

My transactional directive is placed in the Service Bean and looks like this:

@Service
@Transactional
public class UserSecurityQuestionService implements UserSecurityQuestionDAO{

    @Autowired
    private UserSecurityQuestionDAO userSecurityQuerstionDAO;

    @Override
    @Transactional(readOnly=false)
    public void save(UserSecurityQuestion userSecurityQuestion) {
        userSecurityQuerstionDAO.save(userSecurityQuestion);        
    }

This is my DAO Implementation of the save Method:

@Repository
public class UserSecurityQuestionDAOImpl implements UserSecurityQuestionDAO {

    @Autowired
    private HibernateTransactionManager transactionManager; 

    public void save(UserSecurityQuestion userSecurityQuestion) {
        Session session = transactionManager.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        session.persist(userSecurityQuestion);
        tx.commit();
        session.close();
    }

Selecting from the Database works fine, but Inserts/Updates are refused throwing above Error Message. What am I missing?

UPDATE

UserSecurityQuestionDAOImpl:

public class UserSecurityQuestionDAOImpl implements UserSecurityQuestionDAO{

    @Autowired
    private SessionFactory sessionFactory;

    public void save(UserSecurityQuestion userSecurityQuestion) {
        this.sessionFactory.getCurrentSession().save(userSecurityQuestion);
    }

UserSecurityQuestionDAO / UserSecurityQuestionService - Interfaces:

public interface UserSecurityQuestionService {
    public void save(UserSecurityQuestion userSecurityQuestion);    
    public UserSecurityQuestion findById(Short id); 
    public List<UserSecurityQuestion> findAll();    
    public void delete(UserSecurityQuestion userSecurityQuestion);  
    public void deleteById(Short... id);    
}

Service Implementation:

@Service
public class UserSecurityQuestionServiceImpl implements UserSecurityQuestionService {

    @Autowired
    private UserSecurityQuestionDAO userSecurityQuestionDAO;    

    @Transactional
    public void save(UserSecurityQuestion userSecurityQuestion) {
        userSecurityQuestionDAO.save(userSecurityQuestion);     
    }

Unit test code Used for Testing:

public class UserSecurityQuestionTest {

    private AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();      
    private UserSecurityQuestionService usqService;

    @Before
    public void setUp(){
        //Setup App Context
        ctx.scan("com.test.database");
        ctx.refresh();

        //Initilize Service Bean
        usqService = ctx.getBean("userSecurityQuestionService",UserSecurityQuestionServiceImpl.class);
    }

New Problem: If I add @Autowired to the private UserSecurityQuestionService usqService; and omit the Setup-Part, I will get a Null pointer Exception. If I leave the code as it is, I get org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userSecurityQuestionService' is defined


回答1:


I can see that both you service class and your dao implements same interface, and that you autowire the dao in service by its class.

I assume your service is also autowired by its class in your controller. It would be better to have separate interfaces for service and dao to allow autowiring by type using an interface. That way, Spring will use a JDK proxy (the default) to implement the transactional proxy around your service bean.

The alternative would be to use <tx:annotation-driven proxy-target-class="true/>", but you then need to have CGLIB in your path.



来源:https://stackoverflow.com/questions/26121034/spring-transactional-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!