2011-03-13 71 views
0

我已经搜索谷歌独立的Hibernate/Spring应用程序,但没有找到任何有用的示例。似乎大多数人只将它用于网络应用程序。这个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到数据库中,子重载()函数抛出:

输出:

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; 
    } 

} 
+0

您的AOP和代理设置如何?你所做的不会与JDK代理一起工作。 sessionFactory的配置是什么? – Affe 2011-03-13 07:08:07

+0

@Affe:我已经更新了这个问题。但是,如何设置AOP和代理? – 2011-03-13 07:54:34

回答

1

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

+0

谢谢,但我不知道如何设置Spring AOP,你能详细说明一下吗?如你所见,App实例可能已经被注入了,因为它是一个'@ Component'并通过'ApplicationContext.getBean()'实例化。 – 2011-03-13 11:47:40

+0

@Lenik在applicationContext.xml文件中添加标签并定义一个相同的transactionManager bean。您应该阅读Spring框架文档中关于事务管理的章节,它解释了关于设置事务管理器和@Transactional注释的所有内容。之后,你应该对applicationContext.getBean()很好。获取服务类中的App类bean,然后继续使用testCreate()方法。 – 2011-03-13 12:03:19

+0

谢谢。我试着添加'',但不幸的是它仍然不起作用。在深入了解Spring源代码之后,我发现我必须提供一个TransactionInterceptor bean来启用编织器。 – 2011-03-13 17:15:57

1

这实际上不应该是一个问题,你可以安全地使用@Transactional注释一个方法,并且spring容器可以处理事务,只有你应该小心地调用包含该类的代理实例的事务方法在使用spring-aop时,这些方法并不是类的实际实例,因为spring只能拦截用于管理事务的类的代理实例。确保始终使用该类的注入bean实例的最简单方法。另外,请确保您为应用程序进行适当的配置,为事务管理定义合适的bean。 Spring的本质是依赖注入,如果完全使用依赖注入,则只能利用Spring容器的全部功能。除非您确定自己在做什么,否则请远离在代码中的任何位置使用“新”关键字。包含事务方法的类应根据应用程序的性质注入到服务或Web层中。如果你想在类的实际实例上调用事务方法,即使用'new'创建的方法,那么你应该使用AspectJ for AOP。 Spring文档解释了如何为Spring应用程序配置AspectJ。