Spring 3.1 JPA не вставляет данные во время работы в Tomcat - PullRequest
2 голосов
/ 24 февраля 2012

Я потратил три дня, пытаясь найти решение этой проблемы, но безрезультатно.Я отчаянно пытаюсь понять это.У меня есть простое весеннее приложение, работающее в сервлете 2.5 с тегами jstl 1.2, работающее в tomcat с пружиной 3.1, использующее hibernate и реализацию hibernate jpa.

Я могу вывести данные со страницы, но не могу выполнить вставку.Запись возвращается, кажется, она прошла без проблем.Пока не происходит вставка.Я знаю, что есть другие подобные посты, но я просмотрел их все и нигде не смог найти решения.

Если я запускаю точно такой же код через класс MAIN, вставка работает нормально.Он просто не работает при запуске в качестве веб-приложения в tomcat.

Я попытался запустить это через основной, который работает, внутри контроллера, который я пропустил, вызывая сервисный уровень, пытаясь перейти непосредственно к интерфейсуКогда это не сработало, я попытался перейти непосредственно к классу реализации DAO, и это не сработало.Из журналов пружин выясняется, что менеджер сущностей создается и закрывается до того, как произойдет транзакция.

Пожалуйста, помогите мне.

Вот мой контекст приложения

            <beans xmlns="http://www.springframework.org/schema/beans" 
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xmlns:context="http://www.springframework.org/schema/context" 
                    xmlns:aop="http://www.springframework.org/schema/aop" 
                    xmlns:tx="http://www.springframework.org/schema/tx"
                    xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
                    http://www.springframework.org/schema/context 
                    http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                    http://www.springframework.org/schema/tx 
                    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
                    http://www.springframework.org/schema/aop 
                    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd" 
                    default-autowire="byName">

                <context:component-scan base-package="com.naturalbornliar.site"/>
                <tx:annotation-driven />
                <!-- Bean declarations go here-->

                <bean id="duke" class="com.naturalbornliar.site.entity.Admin">
                    <constructor-arg name="admin_id" type="Long" value="15" />
                    <constructor-arg name="admin_login" type="String" value="testUser" />
                    <constructor-arg name="admin_pwd" type="String" value="testPwd" />
                    <constructor-arg name="email_id" type="int" value="15" />
                    <constructor-arg name="quote" type="String" value="Something to say here" />    
                </bean>

            <!--    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> -->
            <!--        <property name="driverClassName" value="com.mysql.jdbc.Driver"/> -->
            <!--        <property name="url" value="jdbc:mysql://localhost:3306/nbl_db"/> -->
            <!--        <property name="username" value="web_user"/> -->
            <!--        <property name="password" value="web_pwd"/> -->
            <!--        <property name="initialSize" value="5"/> -->
            <!--        <property name="maxActive" value="10"/> -->
            <!--    </bean> -->

                <bean id="simpledataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/nbl_db"/>
                    <property name="username" value="web_user"/>
                    <property name="password" value="web_pwd"/>
                </bean>

                <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                    <constructor-arg ref="simpledataSource"/>
                </bean>

                <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                    <property name="persistenceUnitName" value="nblPersistenceUnit"/>
                    <property name="dataSource" ref="simpledataSource"/>
                    <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
                </bean>

            <!--    <bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> -->
            <!--        <property name="persistenceUnitName" value="nblPersistenceUnit"/> -->
            <!--        <property name="dataSource" ref="simpledataSource"/>-->
            <!--        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> -->
            <!--    </bean> -->

                <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                    <property name="entityManagerFactory" ref="emf"/>
                    <property name="jpaDialect" ref="jpaDialect"/>
                </bean>

                <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

                <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="database" value="MYSQL"/>
                    <property name="showSql" value="true"/>
                    <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
                </bean>

                <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

                <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

                <tx:advice id="txAdvice">
                    <tx:attributes>
                        <tx:method name="add*" propagation="REQUIRED"/>
                        <tx:method name="delete*" propagation="REQUIRED"/>
                        <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
                    </tx:attributes>
                </tx:advice>

                <aop:config>

                    <aop:advisor pointcut="execution(* *..CategoryDaoImpl.*(..))" advice-ref="txAdvice"/>

                </aop:config>

                </beans>

Вот мой контроллер:

            package com.naturalbornliar.site.mvc;

            import javax.inject.Inject;

            import org.apache.log4j.Logger;
            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 com.naturalbornliar.site.entity.Category;
            import com.naturalbornliar.site.entity.Link;
            import com.naturalbornliar.site.service.CategoryService;


            @Controller
            @RequestMapping("/categories")
            public class CategoryController {


                protected final Logger logger = Logger.getLogger(CategoryController.class);

                private final CategoryService categoryService;

                @Inject
                public CategoryController(CategoryService categoryService){
                    this.categoryService = categoryService;
                }

                @RequestMapping(value="/listCategories")
                public String listLinks(Model model){

                    model.addAttribute("categories", categoryService.getAllCategories());

                    return "categories";
                }

                @RequestMapping(method=RequestMethod.GET, params="new")
                public String showCreateCategoryForm(Model model){
                    model.addAttribute(new Category());
                    return "addcategory";
                }

                @RequestMapping(method=RequestMethod.POST)
                public String addCategoryFromForm(Category category, BindingResult bindingResult){
                    if(bindingResult.hasErrors()){
                        return"addcategory";
                        }
                    categoryService.addCategory(category);
                    return "redirect:/categories/listCategories";
                }
            }

Вот мой сервис, вызываемый из контроллера:

            package com.naturalbornliar.site.service;

            import java.util.Collection;

            import javax.inject.Inject;

            import org.springframework.stereotype.Service;

            import com.naturalbornliar.site.entity.Category;
            import com.naturalbornliar.site.i.ICategoryDao;

            @Service
            public class CategoryService {

                private ICategoryDao iCategoryDao;

                @Inject
                public CategoryService(ICategoryDao iCategoryDao){
                    this.iCategoryDao = iCategoryDao;
                }

                public Collection<Category> getAllCategories(){
                    return iCategoryDao.getAllCategories();
                }

                public Collection<Category> getCategoriesByType(String type) {
                    return iCategoryDao.getCategoriesByType(type);
                }

                public Category getCategoryById(Long id) {
                    throw new UnsupportedOperationException();
                }

                public void deleteCategory(Category category) {
                    throw new UnsupportedOperationException();
                }

                public void updateCategory(Category category) {
                    throw new UnsupportedOperationException();
                }

                public void inactivateCategory(Category category){
                    throw new UnsupportedOperationException();
                }

                public void addCategory(Category category){
                    iCategoryDao.addCategory(category);
                }
            }

Вот мой реализующий DAO:

            package com.naturalbornliar.site.dao;

            import java.util.Collection;
            import java.util.List;

            import javax.persistence.EntityManager;
            import javax.persistence.PersistenceContext;

            import org.apache.log4j.Logger;
            import org.springframework.stereotype.Repository;
            import org.springframework.transaction.annotation.Transactional;

            import com.naturalbornliar.site.entity.Content;
            import com.naturalbornliar.site.i.IContentDao;

            @Transactional
            @Repository
            public class ContentDaoImpl implements IContentDao {

                protected final Logger logger = Logger.getLogger(ContentDaoImpl.class);

                @PersistenceContext
                private EntityManager em;

                public EntityManager getEm() {
                    return em;
                }


                public void setEm(EntityManager em) {
                    this.em = em;
                }

                @Override
                public void addContent(Content content) {
                    // TODO Auto-generated method stub
                    em.persist(content);
                }

                @Override
                public void deleteContent(Content content) {
                    // TODO Auto-generated method stub
                    em.remove(content);

                }

                @Override
                public void inactivateContent(Content content) {
                    // TODO Auto-generated method stub

                }

                @Override
                public Content getContentById(Long id) {
                    // TODO Auto-generated method stub
                    return null;
                }

                @Override
                public Content getContentByName(String name) {
                    // TODO Auto-generated method stub
                    return null;
                }

                @Override
                public Collection<Content> getAllObjects() {
                    List<Content> resultList = em.createQuery("FROM Content", Content.class).getResultList();
                    return resultList;
                }

            }

Вот интерфейс (на всякий случай)

            package com.naturalbornliar.site.i;

            import java.util.Collection;

            import com.naturalbornliar.site.entity.Content;

            public interface IContentDao {

                public void addContent(Content content);
                public void deleteContent(Content content);
                public void inactivateContent(Content content);
                public Content getContentById(Long id);
                public Content getContentByName(String name);
                public Collection<Content> getAllObjects();

            }

Ответы [ 4 ]

2 голосов
/ 27 февраля 2012

Ну, я на самом деле решил проблему.Вот решение, возникла еще одна проблема, связанная с переполнением стека:

Spring @Transaction не запускает транзакции

В основном все, что было необходимо для корректного запуска транзакций, было длямне добавить:

<tx:annotation-driven proxy-target-class="true"/>

в мой сервлет xml.Я полагаю, если он есть в приложении config.xml, он работает только при работе в основном классе (как в автономном режиме), если вам нужно запустить его в контейнере, вы должны также объявить аннотации транзакций в сервлете.

2 голосов
/ 24 февраля 2012

Джереми, с этим может быть много проблем, и у меня была похожая проблема.

В моем случае я использовал tomcat и мне нужно было добавить пружинного ткача в tomcat (эта проблема описана здесь: http://asrijaffar.blogspot.com/2007/02/spring-jpa-tomcat.html).

В моем случае мне нужно было:

<tx:annotation-driven proxy-target-class="true" />

В конфигурации DispatcherServlet.

Дополнительно в конфигурации db-context:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="jpatest" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
0 голосов
/ 23 мая 2014

У меня тоже была такая же проблема, я провел пару ночей в поисках - решения alex спасли меня - в сервлете xml я изменил контекст: компонентное сканирование для сканирования только пакета с веб-контроллером. Пример с этой страницы должен выглядеть как

<context:component-scan base-package="com.naturalbornliar.site.mvc"/>
0 голосов
/ 16 июля 2013

Я также потратил несколько часов, пытаясь выяснить, где проблема, хотя мое предыдущее приложение с тем же стеком работает нормально, и я не смог понять разницу.

И ....ошибка была в теге в spring-servlet.xml - он был определен для сканирования корневого пакета со всеми веб-контроллерами, классами репозитория и т. д.

После изменения, чтобы выполнить сканирование пакета только с веб-контроллерами,проблема исчезла ..

Только для вас (и для меня), если вы можете столкнуться с той же проблемой, просто дополнительная подсказка

...