SpringMVC & Hibernate : CannotCreateTransactionExc

2020-07-17 05:39发布

问题:

I'm trying to set up and Spring MVC + Hibernate project but it's driving me nuts. I would also take in account suggestions to order the xml config files.

I have the following files:

  • web.xml

    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
        <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/root-context.xml</param-value>
        </context-param>
    
        <!-- Creates the Spring Container shared by all Servlets and Filters -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <!-- Processes application requests -->
        <servlet>
            <servlet-name>appServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>appServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
  • servlet-context.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/mvc"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    
        <context:annotation-config />
    
        <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
    
        <!-- Enables the Spring MVC @Controller programming model -->
        <annotation-driven />
        <tx:annotation-driven/>
    
        <context:component-scan base-package="es.landesoft.mvctesting" />
        <context:component-scan base-package="es.landesoft.mvctesting.service" />
        <context:component-scan base-package="es.landesoft.mvctesting.dao" />
    
        <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
        <resources mapping="/resources/**" location="/resources/" />
    
        <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
        <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <beans:property name="prefix" value="/WEB-INF/views/" />
            <beans:property name="suffix" value=".jsp" />
        </beans:bean>
    
            <!-- JDBC Data Source. It is assumed you have MySQL running on localhost port 3306 with 
           username root and blank password. Change below if it's not the case -->
          <beans:bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <beans:property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
            <beans:property name="url" value="jdbc:sqlserver://127.0.0.1:1433;databaseName=MyHome;instanceName=SQLEXPRESS;"/>       
            <beans:property name="username" value="sa"/>
            <beans:property name="password" value="sarednal1"/>
            <beans:property name="validationQuery" value="SELECT 1"/>
    
          </beans:bean>
    
    
          <beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <beans:property name="dataSource" ref="myDataSource"/>
            <beans:property name="configLocation">
                <beans:value>classpath:hibernate.cfg.xml</beans:value>
            </beans:property>     
            <beans:property name="packagesToScan" value="es.landesoft.mvctesting" />
            <beans:property name="hibernateProperties">
                <beans:props>
                    <beans:prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</beans:prop>
                    <beans:prop key="hibernate.show_sql">true</beans:prop>
                </beans:props> 
            </beans:property>
            </beans:bean>
    
          <beans:bean id="transactionManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <beans:property name="dataSource" ref="myDataSource" />
            <beans:property name="sessionFactory" ref="sessionFactory" />
        </beans:bean>
    

  • PersonController.java

      package es.landesoft.mvctesting;
    import java.util.List;
    import java.util.Locale;
    import javax.validation.Valid;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import es.landesoft.mvctesting.JavaBeans.Person;
    import es.landesoft.mvctesting.service.PersonService;
    
    /**
     * Handles requests for the application home page.
     */
    @Controller
    public class PersonController {
    
        //private static final Logger logger = LoggerFactory.getLogger(PersonController.class);
        @Autowired
        private PersonService personService;        
    
        @RequestMapping(value = "/person/json", method = RequestMethod.GET, produces="application/json")
        @ResponseBody 
        public List<Person> getPersonJson() {               
    
            return personService.listPerson();    
        }
    
    }
    
  • PersonDAO.java

    package es.landesoft.mvctesting.dao;

    import java.util.List;
    
    import es.landesoft.mvctesting.JavaBeans.Person;
    
    public interface PersonDAO {
    
        public void addContact(Person person);
        public List<Person> listPersons();
        public void removePerson(Integer id);
    }
    
  • PersonDaoClass.java

    package es.landesoft.mvctesting.dao;
    
    import java.util.List;
    
    import org.hibernate.SessionFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    
    import es.landesoft.mvctesting.JavaBeans.Person;
    
    @Repository
    public class PersonDaoClass implements PersonDAO {
    
        @Autowired
        private SessionFactory sessionFactory;
    
        @Transactional
        @Override
        public void addContact(Person person) {
    
            sessionFactory.getCurrentSession().save(person);
    
        }
    
        @Transactional
        @SuppressWarnings("unchecked")
        public List<Person> listPersons() {
    
            return sessionFactory.getCurrentSession()
                    .createQuery("From Person").list();
        }
    
        @Transactional
        public void removePerson(Integer id) {
    
            Person person = (Person) sessionFactory.getCurrentSession().load(Person.class, id);
            if (person != null)
            {
                sessionFactory.getCurrentSession().delete(person);          
            }
    
        }
    
    }
    
  • PersonService.java

    package es.landesoft.mvctesting.service;
    
    import java.util.List;
    
    import es.landesoft.mvctesting.JavaBeans.Person;
    
        public interface PersonService {
    
            public void addContact(Person person);
            public List<Person> listPerson();
            public void removePerson(Integer id);
        }
    
  • PersonService.java

        package es.landesoft.mvctesting.service;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import es.landesoft.mvctesting.JavaBeans.Person;
    import es.landesoft.mvctesting.dao.PersonDAO;
    
    @Service
    
    public class PersonServiceClass implements PersonService {
    
        @Autowired
        private PersonDAO personDAO;
    
        @Transactional  
        public void addContact(Person person) {
            personDAO.addContact(person);       
        }
    
        @Transactional  
        public List<Person> listPerson() {
    
            return personDAO.listPersons();
        }
    
        @Transactional
        public void removePerson(Integer id) {
    
            personDAO.removePerson(id);
    
        }
    
    }
    

I am getting this stacktrace error:

    SEVERE: Servlet.service() for servlet [appServlet] in context with path [/mvctesting] threw exception [Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.UnsupportedOperationException] with root cause
    java.lang.UnsupportedOperationException
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:136)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:447)
        at org.hibernate.service.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:141)
        at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292)
        at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214)
        at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157)
        at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:550)
        at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:354)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
        at com.sun.proxy.$Proxy30.listPerson(Unknown Source)
        at es.landesoft.mvctesting.PersonController.getPersonJson(PersonController.java:60)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

In addition, I would be glad if someone can give me some tips to help me organize the xml config files. I am .NET developer and all this maven + xml configurations are something new for me.

Thanks

回答1:

My solution was changing the bean class in Datasource from:

<beans:bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

to the spring Framework class:

 <beans:bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >


回答2:

I have the feeling you're using a version of commons-dbcp which is not compatible with the version of hibernate you're using... or that you have 2 versions of the commons-dbcp in your classpath.

Why?

Looking at the code from org.apache.commons.dbcp.PoolingDataSource, you can see that the method getConnetion(String uname, String passwd) only throws an exception (in the version in the link, the line is 127 rather than 136).

And from org.apache.commons.dbcp.BasicDataSource, you can see that it never calls PoolingDataSource.getConnection(username, password)

solution

  1. Check that you have only one copy of the classes above in your classpath
  2. Try using commons-dbcp version 1.4