Что не так в этом приложении Hibernate / Spring (автономно)? - PullRequest
0 голосов
/ 13 марта 2011

Я искал в Google автономные приложения Hibernate / Spring, но не нашел ни одного полезного примера. Кажется, что большинство людей используют его только для веб-приложений.

Вот что у меня есть:

Основной класс:

@Component
public class App {

    @Inject
    SessionFactory sessionFactory;

    Fruit apple;
    Serializable appleId;

    @Transactional
    void testCreate() {
        apple = new Fruit();
        apple.setName("Apple");
        apple.setPrice(10);

        HibernateTemplate template = new HibernateTemplate(sessionFactory);
        appleId = template.save(apple);
        System.out.println("New Apple: " + apple);
    }

    @Transactional
    void testReload() {
        HibernateTemplate template = new HibernateTemplate(sessionFactory);

        final Fruit reload = template.load(Fruit.class, appleId);

        Session session = SessionFactoryUtils.getSession(sessionFactory, true);

        System.out.println("Update");
        session.update(reload);

        System.out.println("Reload: " + reload);
    }

    public void run()
            throws Exception {
        testCreate();
        testReload();
    }

    public static void main(String[] args)
            throws Exception {
        new ClassPathXmlApplicationContext("context.xml").getBean(App.class).run();
    }

}

В этом примере после успешной вставки нового Apple в базу данных функция reload () подпоследовательности выдает:

Выход:

Hibernate: 
    /* insert my.hibernate.Fruit
        */ insert 
        into
            Food
            (id, rank, version, name, price, DTYPE) 
        values
            (null, ?, ?, ?, ?, 'Fruit')
DEBUG [main] (HibernateAccessor.java:389) - Eagerly flushing Hibernate session
New Apple: 1, Apple
DEBUG [main] (HibernateAccessor.java:389) - Eagerly flushing Hibernate session
Update
Hibernate: 
    /* load my.hibernate.Fruit */ select
        fruit0_.id as id0_0_,
        fruit0_.rank as rank0_0_,
        fruit0_.version as version0_0_,
        fruit0_.name as name0_0_,
        fruit0_.price as price0_0_ 
    from
        Food fruit0_ 
    where
        fruit0_.id=? 
        and fruit0_.DTYPE='Fruit'

Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [my.hibernate.Fruit#1]
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:419)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:154)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:143)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at my.hibernate.Fruit_$$_javassist_0.toString(Fruit_$$_javassist_0.java)
at java.lang.String.valueOf(String.java:2902)
at java.lang.StringBuilder.append(StringBuilder.java:128)
at my.hibernate.App.testReload(App.java:86)

Кажется, testCreate() ничего не совершал. Есть идеи?

EDIT

context.xml:

<?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:context="http://www.springframework.org/schema/context"
    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
        ">

    <context:component-scan base-package="my" />

</beans>

И сессионный заводской конфиг:

@Component
public class TestH2DataSource
        extends BasicDataSource {

    public TestH2DataSource() {
        setDriverClassName("org.h2.Driver");

        setUrl("jdbc:h2:target/testdb;DB_CLOSE_ON_EXIT=FALSE");
        setUsername("sa");
        setPassword("");
        setDefaultAutoCommit(false);
    }

}

@Component
public class TestSessionFactory
        extends AnnotationSessionFactoryBean {

    @Inject
    DataSource dataSource;

    public TestSessionFactory() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.show_sql", "true");
        properties.setProperty("hibernate.format_sql", "true");
        properties.setProperty("hibernate.use_sql_comments", "true");
        properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");

        this.setHibernateProperties(properties);

        this.setAnnotatedClasses(new Class<?>[] { Fruit.class });
    }

    @Override
    public void afterPropertiesSet()
            throws Exception {

        this.setDataSource(dataSource);

        super.afterPropertiesSet();
    }

}

@Configuration
public class OtherContextConfiguration {

    @Inject
    SessionFactory sessionFactory;

    @Bean
    public HibernateInterceptor hibernateInterceptor() {
        HibernateInterceptor hibernateInterceptor = new HibernateInterceptor();
        hibernateInterceptor.setSessionFactory(sessionFactory);
        return hibernateInterceptor;
    }

    @Bean
    public HibernateTransactionManager hibernateTransactionManager() {
        HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
        hibernateTransactionManager.setSessionFactory(sessionFactory);
        return hibernateTransactionManager;
    }

}

Ответы [ 2 ]

1 голос
/ 14 марта 2011

На самом деле это не должно быть проблемой, вы можете безопасно аннотировать метод с помощью @Transactional, а Spring Container может позаботиться о транзакции, только вы должны быть осторожны, чтобы вызывать транзакционные методы на экземплярах прокси класса, содержащего методы, а не фактический экземпляр класса при использовании Spring-AOP, поскольку Spring может перехватывать только прокси-экземпляры классов для управления транзакциями. Самый простой способ убедиться, что всегда используется внедренный экземпляр класса. Кроме того, убедитесь, что вы делаете правильную настройку для своего приложения, определяя надлежащие компоненты для управления транзакциями. Сущность пружины заключается в инжекции зависимостей, и вы можете использовать всю мощность контейнера пружины, только если полностью используете инжекцию зависимостей. Избегайте использования ключевого слова new в любом месте кода, если вы не уверены в том, что делаете. Класс, который содержит транзакционные методы, должен быть внедрен в ваш сервис или веб-уровень в зависимости от характера вашего приложения. Если вы хотите вызывать транзакционные методы для фактического экземпляра класса, т.е. класса, созданного с использованием 'new', то вы должны использовать AspectJ для AOP. В весенней документации объясняется, как настроить AspectJ для вашего весеннего приложения.

1 голос
/ 13 марта 2011

В базе данных нет фиксации. Как вы вызываете функцию testCreate (). Я полагаю, вы используете spring-aop для @Transactional. Spring AOP может перехватывать @Transactional только на прокси-объектах, а не на фактическом экземпляре класса. Поэтому, если ваш класс App не является проксимальным прокси, он не сможет зафиксировать базу данных. Более того, внутренние вызовы закрытого метода внутри класса также не будут вызывать @Transactional. Итак, вы должны внедрить класс App в ваш класс сервисного уровня, который затем вызовет метод testCreate () для внедренного экземпляра App.class. Поскольку внедренный экземпляр класса App будет прокси, Spring будет заботиться о транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...