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();
...
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:
http:
<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
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之类的操作了。
分享到:
相关推荐
HibernateTemplate所属的架包是spring-orm-4.3.2.RELEASE.jar
Spring整合hibernate(2)之基于HibernateTemplate的整合,jar需要自己添加!
Spring2.5和Hibernate3集成 采用声明式事务 1.声明式事务的配置 * 配置sessionFactory * 配置事务管理器 * 配置事务的传播特性 * 配置哪些类哪些方法使用事务 2.编写业务逻辑方法 * 继承...
HibernateTemplate.saveOrUpdate时出现\xE7\x84十六进制之类的字符串,连接数据库字符串,数据库字符集,汉字乱码的问题集合,还有我熬3夜的血泪经历
Spring+hibernate整合源代码 结束Sping+hibernate 的使用方法 包括演示示例
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 ...
Spring和Hibernate源码下载 Spring_Spring_Hibernate_HibernateTemplate
application.xml配置 ... <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </beans>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <!-- Spring AOP ...
Spring提供了org.springframework.orm.hibernate3.HibernateTemplate类和org.springframework.orm.hibernate3.HibernateCallback接口来方便和Hibernate整合。 HibernateTemplate类封装了Hibernate的主要类,它提供了...
Spring_2000_Spring_Hibernate_HibernateTemplate,Spring_2000_Spring_Hibernate_HibernateTemplate
6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...
6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...
spring和hibernate整合示例,以一张表的业务操作,来简要说明hibernate和spring的整合,说明spring对HibernateTemplate和调用
TfileDAOHibernate通过扩展Spring提供的Hibernate支持类HibernateDaoSupport而建立,HibernateDaoSupport封装了HibernateTemplate,而HibernateTemplate封装了Hibernate所提供几乎所有的的数据操作方法,如execute...
Spring 整合 Hibernate 时启用二级缓存实例详解 写在前面: 1. 本例使用 Hibernate3 + Spring3; 2. 本例的查询使用了 HibernateTemplate; 1. 导入 ehcache-x.x.x.jar 包; 2. 在 applicationContext.xml ...
6.5 Spring整合Hibernate 6.6 Spring提供的DAO支持 6.5.2 管理Hibernate的SessionFactory 6.5.3 使用HibernateTemplate 6.5.4 使用HibernateCallBack 6.5.6 使用IoC容器组装各种组件 6.5.7启动web容器读取xml配置...