这个Hibernate / Spring应用程序(独立)有什么问题?

时间:2011-03-13 05:29:59

标签: java spring hibernate

我在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()没有提交任何内容。有什么想法吗?

修改

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 个答案:

答案 0 :(得分:1)

数据库中没有提交。你如何调用函数testCreate()。我想你正在为@Transactional使用spring-aop。 Spring AOP只能在代理对象上拦截@Transactional,而不能拦截类的实际实例。因此,如果您的App类不是Spring代理,那么它将无法提交到数据库。对类内私有方法的内部调用也不会触发@Transactional。因此,您应该将App类注入到服务层类中,然后该类将在注入的App.class实例上调用testCreate()方法。由于App类的注入实例将是一个代理,因此spring将负责该事务。

答案 1 :(得分:1)

实际上这应该不是问题,你可以使用@Transactional安全地注释方法,而spring容器可以处理事务,只有你应该小心你在包含该类的类的代理实例上调用事务方法。使用spring-aop时,方法而不是类的实际实例,因为spring只能截取类的代理实例来管理事务。确保最简单的方法是始终使用类的注入bean实例。此外,请确保为应用程序进行正确配置,为事务管理定义正确的bean。 Spring的本质是依赖注入,如果你完全使用依赖注入,你只能利用弹簧容器的全部功能。除非您确定自己在做什么,否则不要在代码中的任何位置使用“new”关键字。根据应用程序的性质,应将包含事务方法的类注入服务或Web层。如果要在类的实际实例上调用事务方法,即使用“new”创建的方法,则应使用AspectJ进行AOP。 spring文档介绍了如何为spring应用程序配置AspectJ。