我在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;
}
}
答案 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。