Hibernate整合进spring--使用hibernateTemplate.getSessionFactory().getCurrentSession()理解

1 单独使用hibernate处理事务

本来只用hibernate开发,从而可以省了DAO层实现数据库访问和跨数据库,也可以对代码进行更好的封装,当我们web中单独使用hibernate时,我们需要单独的处理hibernate的事务,我是使用filter来对事务进行控制的:

单独使用hibernate使用filter进行事务控制:

HibernateSessionFilter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class HibernateSessionFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
Session session = HibernateUtils.openSession();
Transaction tx = null ;
try {
tx = session.beginTransaction();
chain.doFilter(request, response);
tx.commit();
} catch (Exception e) {
if (tx != null ) {
tx.rollback();
}
throw new RuntimeException(e);
} finally {
HibernateUtils.closeAndRemoveSession();
}
}
public void init(FilterConfig arg0) throws ServletException {
}
}

web.xml

1
2
3
4
5
6
7
8
9
10
<filter>
<filter-name>hibernateSessionFilter</filter-name>
<filter- class > syx.jpkc.filter.HibernateSessionFilter</filter- class >
</filter>
<filter-mapping>
<filter-name>hibernateSessionFilter</filter-name>
<url-pattern>*.syx</url-pattern>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.eve</url-pattern>
</filter-mapping>

我主要在servlet(*.syx,*.eve)和jsp页面(没用struts)需要和数据库操作,所以需要使用事务处理。

上面我们还用到了一个 HibernateUtils的小工具类,主要为了获取Session对象和一点优化:

HibernateUitls.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class HibernateUtils {
private static Map<Thread, Session> sessionMap;
private static SessionFactory sessionFactory;
static {
sessionMap = new HashMap<Thread, Session>();
sessionFactory = new Configuration().configure().buildSessionFactory();
}
/**
* can only use in web filter, beause it should remove and clear resources
* @return
*/
public static Session openSession() {
System.out.println(Thread.currentThread().getStackTrace()[ 1 ] + " run in " + new Date());
Session session = sessionMap.get(Thread.currentThread());
if (session == null ) {
session = sessionFactory.openSession();
sessionMap.put(Thread.currentThread(), session);
}
return session;
}
public static Session getCurrentSession() {
return sessionMap.get(Thread.currentThread());
}
public static void closeAndRemoveSession() {
System.out.println(Thread.currentThread().getStackTrace()[ 1 ]+ " run in " + new Date()); //
Session session = sessionMap.remove(Thread.currentThread());
if (session != null ) {
session.close();
}
}
}

2 hibernate整合进spring后的事务处理

spring事物处理的方式有很多,详见:http://www.blogjava.net/robbie/archive/2009/04/05/264003.html

介绍常用的:

spring annotation声明式的事务管理

1) 事物处理层?

比如保存一个User,可以在Service层和DAOImpl层实现:

1
2
3
4
5
6
7
8
9
10
11
12
public void save(User u) {
userDAO.save(u);
}
public void save(User u) {
System.out.println( "save user from:" + this );
Session s = sessionFactory.openSession();
s.beginTransaction();
s.save(u);
s.getTransaction().commit();
s.close();
}

假如我们还有个日志记录,没保存一个User对象,要写入日志进入数据库。

而save(log) 和 save(user)必须处在同一事务中,所以不能放在DAOImpl层,事务处理在Service层。

2) 一般的事务处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
//do some work
//save(user);
//save(log);
...
tx.commit();
} catch (Exception e) {
if (tx!= null ) tx.rollback();
throw e;
} finally {
sess.close();
}

并且要在实现层中的save()方法中也要加入事务处理,如果出出现异常要throws给上级处理!

并且实现层中的session必须使用openCurrentSession()得到。

1
2
Session s = sessionFactory.getCurrentSession();
s.save(u);

3) spring annotation事务处理

Beans.xml中引入相应的xml命名空间和相应配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
http: //www.springframework.org/schema/tx
http: //www.springframework.org/schema/tx/spring-tx-3.0.xsd
<tx:annotation-driven transaction-manager= "txManager" />
<bean id= "txManager" class = "org.springframework.orm.hibernate3.HibernateTransactionManager" >
<property name= "sessionFactory" ref= "sessionFactory" />
</bean>
<bean id= "dataSource"
class = "org.apache.commons.dbcp.BasicDataSource"
destroy-method= "close" >
<property name= "driverClassName"
value= "${jdbc.driverClassName}" />
<property name= "url" value= "${jdbc.url}" />
<property name= "username" value= "${jdbc.username}" />
<property name= "password" value= "${jdbc.password}" />
</bean>
<bean id= "sessionFactory"
class = "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" >
<property name= "dataSource" ref= "dataSource" />
<property name= "annotatedClasses" >
<list>
<value>com.syx.model.User</value>
<value>com.syx.model.Log</value>
</list>
</property>
<property name= "hibernateProperties" >
<props>
<prop key= "hibernate.dialect" >org.hibernate.dialect.MySQLDialect</prop>
<prop key= "hibernate.show_sql" > true </prop>
<prop key= "current_session_context_class" >thread</prop>
</props>
</property>
</bean>
Save方法:
public void save(User u) {
Session s = sessionFactory.getCurrentSession();
s.save(u);
}
public void save(Log log) {
Session s = sessionFactory.getCurrentSession();
s.save(log);
}
Service层处理:
@Component ( "userService" )
public class UserService {
UserDAO userDAO = null ;
LogDAO logDAO = null ;
public LogDAO getLogDAO() {
return logDAO;
}
@Resource (name= "logDAOMySQLImpl" )
public void setLogDAO(LogDAO logDAO) {
this .logDAO = logDAO;
}
@Transactional
public void save(User u) {
userDAO.save(u);
Log log = new Log();
log.setMsg(u.getName() + " saved in " + new Date());
logDAO.save(log);
}
public UserDAO getUserDAO() {
return userDAO;
}
@Resource (name= "userDAOMySQLImpl" )
public void setUserDAO(UserDAO userDAO) {
this .userDAO = userDAO;
}
}

4) @Transactional详解

什么时候rollback

运行期异常,非运行期异常不会触发rollback

必须uncheck (没有catch)

不管什么异常,只要你catch了,spring就会放弃管理

事务传播特性:propagation_required

image

propagation默认是 REQUIRED ,意思是有我们就用现成的,没的我们就创造一个,其他详细见文档

spring xml声明式的事务管理

配置环境和annotation版本一致,只是在用@Transactional处注释调用,在beans.xml中加入如下配置:

<!-- spring tranception xml config -->
	<aop:config>
		<aop:pointcut id="serviceOperation"
			expression="execution(* com.syx.service..*.*(..))" />
		<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
	</aop:config>

	<tx:advice id="txAdvice"  transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="getUser" read-only="true" />
			<tx:method name="save" /><!-- 相当于在上面切面pointcut@Transactional效果 -->
		</tx:attributes>
	</tx:advice>

3 hibernateTemplate.getSessionFactory().getCurrentSession()

我们使用spring和hibernate结合,操作数据库最常用可能是HibernateTemplate,HibernateTemplate中集成了很多使用的方法,可惜的是没的createQuery方法,也许我们使用hibernate的时候喜欢使用Query,我们可能会封装hibernateTemplate.getSessionFactory().getCurrentSession()方法得到Session,session创建Query,这是一个方法,但你应该会得到异常 “createQuery without an active transaction”,因为使用hibernateTemplate.getSessionFactory().getCurrentSession(),你是使用的hibernate的事务管理,而你指望spring管理的事务是hibernateTemplate,所以你会提示没有打开事务的异常,解决方法:1)使用hibernate事务处理,就像上面单独使用hibernate一样,但这也许不是你想要的。2)使用hibernateTemplate的HibernateCallBack回调:

return hibernateTemplate.executeWithNativeSession(
	new HibernateCallback<List<T>>() {
	public  List<T> doInHibernate(Session session) 
	throws HibernateException, SQLException {
		return session.createQuery
		("FROM " + entityClass.getName() + " WHERE id IN (:ids)")//
		.setParameterList("ids", idList).list();
	}

实际上hibernateTemplate中封装的find方法也很强大,如果熟练使用完全可以替代createQuery的。

备注:

如果出现异常:对同一个集合处理不能使用2个session,这是因为getCurrentSession方法出错,导致打开一个新的session,检查配置文件,如果使用tomcat+spring+hibernate 配置hibernate.current_session_context_class 最好为thread,虽然支持jta,配置比较麻烦,而且jta支持多个sessionFactory,即可以跨数据库,比较强大!

如果hibernate+spring出现session没有提交情况,应该是你让spring负责事务处理,而你有使用了hibernate的session,从而脱离spring事务处理,即没的begintransaction和commit之类的操作了。

作者: syxChina
出处: http://syxchina.cnblogs.comhttp://hi.baidu.com/syxcs123
本文版权归作者、博客园和百度空间共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则作者会诅咒你的。
如果您阅读了我的文章并觉得有价值请点击此处,谢谢您的肯定1。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61) at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46) at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:68) at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298) at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:41) at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:969) at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1690) at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142) at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:152) at com.sinosoft.sysframework.persistence.HibernateSQLQuery.doInHibernate(HibernateSQLQuery.java:118) at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:366) at org.springframework.orm.hibernate3.HibernateTemplate.executeFind(HibernateTemplate.java:338) at com.sinosoft.sysframework.persistence.BaseDaoHibernateImpl.queryList(BaseDaoHibernateImpl.java:224) at com.sinosoft.application.reins.persistence.hibernate.base.GrRePlanItemDaoHibernateImplBase.find(GrRePlanItemDaoHibernateImplBase.java:127) at com.sinosoft.application.reins.service.spring.GrTrialServiceSpringImpl.endorTrialDataSurrender(GrTrialServiceSpringImpl.java:9536) at com.sinosoft.application.reins.service.
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值