1、导入hibernate的包和Spring的包
1.1、导入Spring的依赖包 1.2、导入Log4j的依赖包 1.3、导入dbcp的依赖包 1.4、导入Hibernate3的依赖包(hibernate3.jar,required文件中的所有,slf4j-api.jar,)
2、创建SpringBean.xml 2.1、使用DBCP创建dataSource, 和集成JDBC一样
2.2、创建Hibernate的的sessionFactory
2.2.1、首先我们看一下以前的hibernate.cfg.xml配置,创建sessionFactory
官网有介绍19.3.1 SessionFactory setup in a Spring container ,
下面为实际配置package com.chb.spring_hibernate.dao;
import java.util.List;
import com.chb.spring_hibernate.model.User;
public class UserHibernateDao implements IUserDao{
...//实现IUserDao的方法
}
4.2、在相应的Dao中注入相应的SessionFactory
package com.chb.hbUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static Session session;
private static SessionFactory getFactory() {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
return sessionFactory;
}
public static Session getSession() {
if (session == null) {
session = getFactory().openSession();
}
return session;
}
public static void close() {
if (session != null) {
session.close();
}
}
}
4.2.2、如果通过Spring来管理相应的SessionFactory,不再使用factory.openSession()开启session,而应该是使用facotry.getCurrentSession来打开Session,这个Session就会被Spring所管理,此时开发人员不用进行事务控制,也不用关闭Session,全部有Spring容器来完成
/**
* 获取Session,
* 注意: 没有使用openSession(), 而是getCurrentSession()才能被Spring所管理
* @return
*/
private Session getSession() {
return sessionFactory.getCurrentSession();
}
4.3、为Group创建基于Hibernate的Dao, 同样注入sessionFactory, 通过session来进行相应的操作。
package com.chb.spring_hibernate.dao;
import javax.annotation.Resource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.chb.spring_hibernate.model.Group;
public class GroupHibernateDao implements IGroupDao{
//注入sessionFactory
private SessionFactory sessionFactory;
//提供相应的getter setter
@Resource(name="mySessionFactory")//注入sessionFactory
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* 获取Session,
* 注意: 没有使用openSession(), 而是getCurrentSession()才能被Spring所管理
* @return
*/
private Session getSession() {
return sessionFactory.getCurrentSession();
}
public void addGroup(Group group) {
}
}
4.4、sessionFactory注入的优化
每多一个实体类, 我们都要注入SessionFactory, 这部分代码功能都是一样的, 我们如果每个Dao中重复写这部分代码就是做重复工作, 我们可以将这部分代码提取出来, 写一个BaseDao类
package com.chb.spring_hibernate.dao;
import javax.annotation.Resource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class BaseDao {
//注入sessionFactory
private SessionFactory sessionFactory;
//提供相应的getter setter
@Resource(name="mySessionFactory")//注入sessionFactory
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* 获取Session,
* 注意: 没有使用openSession(), 而是getCurrentSession()才能被Spring所管理
* @return
* //使用protected权限,只有子类可以使用
*/
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}
这样, GroupHibernateDao, UserHibernateDao 只需要继承BaseDao, 代码就简洁多了。
5、测试: 添加一哥group
package com.chb.spring_hibernate.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.chb.spring_hibernate.dao.GroupHibernateDao;
import com.chb.spring_hibernate.dao.IGroupDao;
import com.chb.spring_hibernate.model.Group;
public class Test {
@org.junit.Test
public void testHibernateAdd(){
ApplicationContext context = new ClassPathXmlApplicationContext("SpringBean.xml");
IGroupDao groupDao = context.getBean(GroupHibernateDao.class);
Group group = new Group();
group.setGroupName("计算机系");
groupDao.addGroup(group);
}
}
报错1、
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userHibernateDao': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mySessionFactory': Failed to introspect bean class [org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean] for lookup method metadata: could not find class that it depends on; nested exception is java.lang.NoClassDefFoundError: [Lorg/hibernate/engine/FilterDefinition;
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.
原因: Spring整合Hibernate 使用注解类出错, 在Hibernate3可以使用AnnotationSessionFactoryBean来创建sessionFactory,但是,Hibernate4已经不支持这个了。Hibernate 只能使用org.springframework.orm.hibernate4.LocalSessionFactoryBean
, 那么要怎么配置注解形式的model呢?很简单,因为LocalSessionFactoryBean里面已经整合了annotation,
public void setPackagesToScan(String... packagesToScan) {
this.packagesToScan = packagesToScan;
}
报错2、
原因: 配置Spring事务处理,只有配置了事务处理之后,Spring才能有效的管理事务
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
六、配置Spring事务处理,只有配置了事务处理之后,Spring才能有效的管理事务
参考: 20.4.3 Transaction management
Spring是通过aop来实现事务处理
java.lang.ClassCastException: com.sun.proxy.$Proxy20 cannot be cast to com.chb.spring_hibernate.dao.UserHibernateDao
java.lang.ClassCastException: com.sun.proxy.$Proxy20 cannot be cast to com.chb.spring_hibernate.dao.UserHibernateDao
at com.chb.spring_hibernate.test.Test.testHibernateAdd(Test.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
解决参照: http://blog.csdn.net/danchaofan0534/article/details/53575106
继续报错4、java.lang.ClassNotFoundException: org.hibernate.engine.transaction.spi.TransactionContext
本项目是Spring4 + Hibernate5 , 但是在设置事务管理器时参考的是HIberrnate4的文档,导致出错。
java.lang.IllegalStateException: No value for key [org.hibernate.internal.SessionFactoryImpl@5226e402] bound to thread [main]
我他妈要疯了
java.lang.IllegalStateException: No value for key [org.hibernate.internal.SessionFactoryImpl@5226e402] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:210)
at org.springframework.orm.hibernate5.HibernateTransactionManager.doCleanupAfterCompletion(HibernateTransactionManager.java:649)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1017)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:883)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:830)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:522)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:286)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy19.addGroup(Unknown Source)
at com.chb.spring_hibernate.test.Test.testHibernateAdd(Test.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
碰巧和上面一样, 在注入sessionFactory时,
public Group load(int id) {
return getSession().load(Group.class, 1);
}
测试
@org.junit.Test
public void testLoad(){
ApplicationContext context = new ClassPathXmlApplicationContext("SpringBean.xml");
IGroupDao groupDao = (IGroupDao)context.getBean("groupHibernateDao");
System.out.println(groupDao.load(1));
}
测试结果: 报错7、org.hibernate.LazyInitializationException: could not initialize proxy - no Session
报错是一个懒加载异常,是在session(hibernate里的session)关闭后使用group对象的未加载变量,也就是说session已经关闭,然而该实例变量却还没有被初始化,就使用了该实例变量,导致该异常。
下面给出三种解决办法,个人认为第二种比较好
1、把lazy设成false。这个是最简单的办法,个人认为也是比较笨的方法。因为这是在用效率作为代价。
2、使用OpenSessionInViewFilter。这种方法是将session交给servlet filter来管理,每当一个请求来之后就会开启一个session,只有当响应结束后才会关闭。如下:
3、将hibernate的抓起策略改为join。也就是是left join fetch或inner join fetch语法。就是在
我们会在后续中考虑OpenSessionInViewFilter, 本节先不处理, 将load改为get