второе действие БД останавливает выполнение транзакции - PullRequest
1 голос
/ 23 августа 2011

мы боролись с этим в течение нескольких недель.

первый код,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" 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/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
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.nmsc" />
    <tx:annotation-driven proxy-target-class="true"/>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

</beans>

мой класс дао

@SuppressWarnings("unused")
@Repository("com.nmsc.hibernateDAO.SSOUserDAO")
@Transaction
public class SSOUserDAO implements SSOUserDAOSPI{
    private static Logger logger = Logger.getLogger(SSOUserDAO.class);

    @Autowired(required=true)
    private SessionFactory sessionFactory;

    @Transactional
    public Integer saveUpdate(SSOUser user) {
        sessionFactory.getCurrentSession().saveOrUpdate(user);

        return user.getIdUser();
    }

хорошо, теперьесли в моем junit я делаю это

@Test
    @Transaction
    public void testStoreRetrieve() {
        SSOUserDAOSPI userDAO = ServiceProviderContext.find(SSOUserDAOSPI.class);

        System.out.println("test");
        userDAO.deleteAllInUserTable();
        SSOUser user = buildTestUser();

        Integer id = userDAO.saveUpdate(user);

        user.setIdUser(id);

        // retrieve the user from the database
        SSOUser retrievedUser = userDAO.getByID(id);

        checkResults(user, retrievedUser);
    }

удаление пользователей работает просто найти, но когда это делает saveupdate, выполнение просто зависает.без ошибок, без ничего, просто зависает, пока вы не убьете процесс.

аналогично, если я сделаю

Integer id = userDAO.saveUpdate(user);

, он будет отлично работать и вставит пользователя, но если я сделаю

Integer id = userDAO.saveUpdate(user);
Integer id2 = userDAO.saveUpdate(user2);

вставит первого пользователя и остановит второго.он сделал нечто подобное, прежде чем мы попытались реализовать пружинные транзакции (что мы должны были сделать для других частей системы), только он вставил бы пользователя, но не user2, но файл журнала гибернации показал бы, что он действительно вставил второго пользователя,

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

РЕДАКТИРОВАТЬ ПОПРОБОВАТЬ ДВА

хорошо, вот мой класс дао

@SuppressWarnings("unused")
@Repository
public class SSOUserDAO implements SSOUserDAOSPI{
    private static Logger logger = Logger.getLogger(SSOUserDAO.class);

    @Autowired(required=true)
    private SessionFactory sessionFactory;

    public Integer saveUpdate(SSOUser user) {
        sessionFactory.getCurrentSession().saveOrUpdate(user);
        return user.getIdUser();
    }
public void deleteAllInUserTable() {
        // delete everything in the table to run the test
        logger.debug("beginning delete");
        if (sessionFactory == null){
            logger.debug("session factory null");
        } else
            logger.debug("sessionfactory not null");

        Query q = sessionFactory.getCurrentSession().createQuery("delete from SSOUser");
        q.executeUpdate();
    }

и я изменил свой тест на этот

@Test
    @Transactional(propagation=Propagation.REQUIRED)
    public void testStoreRetrieve() {

        SSOUserDAOSPI userDAO = ServiceProviderContext.find(SSOUserDAOSPI.class);

        System.out.println("test");
        userDAO.deleteAllInUserTable();
        SSOUser user = buildTestUser();

        Integer id = userDAO.saveUpdate(user);

        user.setIdUser(id);

        // retrieve the user from the database
        SSOUser retrievedUser = userDAO.getByID(id);

        checkResults(user, retrievedUser);
    }

, который, если я правильно вас понимаю, это именно то, что вы делаете (за исключением того факта, что его джунт запускает его), но я получаю то же самоеисключение.мы, вероятно, перейдем к весенним тестам в будущем, но на данный момент мне нужно запустить существующие тесты, все 300 или около того.

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)
    at com.nmsc.hibernateDAO.SSOUserDAO.deleteAllInUserTable(SSOUserDAO.java:121)
    at com.nmsc.hibernateDAO.SSOUserDAO_Test.testStoreRetrieve(SSOUserDAO_Test.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    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.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    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)

часть, которая сводит меня с ума, - моя инициализацияжурнал показывает это

 Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
1651 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor  - Autowiring by type from bean name 'SSOUserDAO' to bean named 'sessionFactory'
1651 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
1653 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory  - Finished creating instance of bean 'SSOUserDAO'

, которое говорит мне, что Spring полностью знает, что компонент управляется менеджером транзакций.поэтому, когда я получаю экземпляр bean-компонента, менеджер транзакций должен это знать, но, похоже, он этого не знает.

EDIT TRY THREE

ок, я изменилсямой тест на это

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =
{
    "classpath:transaction-service.xml"
})
public class SSOUserDAO_Test extends JunitHelperClass {
    private static Logger logger = Logger.getLogger(SSOUserDAO_Test.class);

    @Resource
    SSOUserDAOSPI userDAO;

    @Test
    @Transactional(propagation=Propagation.REQUIRED)
    public void testStoreRetrieve() {

        //SSOUserDAOSPI userDAO = ServiceProviderContext.find(SSOUserDAOSPI.class);

        System.out.println("test");
        userDAO.deleteAllInUserTable();
        SSOUser user = buildTestUser();

        Integer id = userDAO.saveUpdate(user);

        user.setIdUser(id);

        // retrieve the user from the database
        SSOUser retrievedUser = userDAO.getByID(id);

        checkResults(user, retrievedUser);
    }

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

1 Ответ

1 голос
/ 23 августа 2011

Я не уверен, что такое @Transaction, но между этим @Transactional, который вы разбросали по всему, было бы не слишком удивительно, если бы у вас были транзакции в тупике.Если специально не предусмотрено иное, определенная цепочка вызовов методов, соответствующая запросу пользователя, обычно должна происходить в пределах ровно одной транзакции, и транзакция должна происходить не на уровне DAO, а на некотором уровне выше нее.Транзакция, как правило, должна начинаться с момента, когда пользователь запрашивает какое-либо действие по всей загрузке из базы данных, бизнес-логике и сохранению в базе данных, необходимой для выполнения этого действия, и завершаться только тогда, когда запрос определенного пользователя на какое-либо действие или другое был удовлетворен.,Уточните управление транзакциями, и ваша проблема, скорее всего, будет решена.

Редактировать: Например, где-то у вас должен быть метод, который должен выглядеть примерно так:

@Transactional
public void modifyUser(int userId, User newUser) {
    validateInput(newUser);
    User existingUser = userDao.load(userId);
    copyUpdateableProperties(newUser, existingUser);
}

Обратите внимание, что

  • Это не DAO.Он использует DAO.
  • Транзакция устанавливается здесь, а не в DAO.
  • Нет явного вызова "save", как, например, когда объект загружается и изменяется в рамках транзакции.изменения сохраняются при фиксации транзакции.

Кроме того, несмотря на то, что это может способствовать возникновению проблемы, строка userDAO.deleteAllInUserTable(); в вашем тесте представляет собой отчетливый запах кода.Во-первых, нечто подобное относится к методу настройки, так как он готовит среду для вашего теста.Во-вторых, более понятный подход - запускать каждый тест в транзакции, откат которой выполнен в конце теста, - функциональность, которую вы получаете бесплатно при использовании Spring test framework .

.
...