我的Hibernate销售中遇到那些拦截方面的问题器不工作问题,怎么解决

Hibernate拦截器(Interceptor)与事件监听器(Listener)
由于项目中(S2SH框架)用到了memcache缓存服务器,考虑到同步问题是用每个bean变更时同时更新缓存还是用类似数据库trigger(触发器)去实现呢,答案当然是用类似trigger的方式了,其优点不言而喻,毕竟这么写一劳永逸。
经调查发现,hibernate有两种方式可以实现:
拦截器(Intercept):与Struts2的拦截器机制基本一样,都是一个操作穿过一层层拦截器,每穿过一个拦截器就会触发相应拦截器的事件做预处理或善后处理。
  监听器(Listener):其实功能与拦截器是相似的,但它实现原理不同,它是为每一个事件注册一个或多个监听器,一旦事件发生,则事件源通知所有监听该事件的监听器,然后监听器处理通知(观察者模式)。
拦截器具体实现:
类继承EmptyInterceptor是官方推荐做法。
PS:@Component为spring组件(bean)声明方式,用法类似&bean id="" class=""& beanid 默认为类名(第一个字母小写),使用@Component前需要先在srping配置文件中声明&!-- 配置注入信息的包 --&&context:component-scan base-package="*" /& 。
最后,Hibernate的拦截器有两种设置方式,一种是使用sessionFactory.openSession(Interceptor interceptor),这样的拦截器只会针对该session有效,又叫做局部拦截器。另一种是使用Configuration的setInterceptor(Interceptor interceptor)方法设置,这样的拦截器对每一个session都有效,又称之为全局拦截器,全局拦截器还有种配置方法是在sessionFactory bean中加
事件监听器实现:
配置方法:
在hibernate4中,查看LocalSessionFactroyBean源码去不支持EventListener。spring3.X 对hibernate4不支持这样的配置,hibernate4 改变了注册EventListener的方式,这里使用注解方式:
如果你的项目使用的是hibernate3+,建议在sessionFactory bean中配置eventListener。
实际效果:
两种方法实现过发现在本项目中只有save obj的时候才触发了事件(拦截器),一直不解,后来想到hibernate是基于对象操作的,而在项目中除了save方法外,其他的update、delete、等方法都是通过hql语句实现的,所有更新、删除的事件未触发。这样一来必须通过监听statement语句时通过判断该如果是更新还是删除等执行更新缓存了。
关于两种方式的更多细节可参考:http://www.cnblogs.com/otomedaybreak/archive//2328980.html
没有更多推荐了,spring mvc + hibernate项目中,注入方式采用的是注解,现在spring aop方法拦截器不起作用_百度知道
spring mvc + hibernate项目中,注入方式采用的是注解,现在spring aop方法拦截器不起作用
只能拦截到用bean方式注入的方法,而用注解注入的方法都拦截不到。 拦截器实现的是MethodInterceptor这个类。肿么办
我有更好的答案
你方法里头的切入点创建了么?可以创建一个空的方法作为切入点
为您推荐:
其他类似问题
mvc的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。atitit.springhibernate的事务机制spring不能保存对象的解决
在Spring中使用Hibernate,如果我们配置了TransactionManager,那么我们就不应该调用SessionFactory的openSession()来获得Sessioin,因为这样获得的Session并没有被事务管理。
采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会。
采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关闭。
使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
* 如果使用的是本地事务(jdbc事务)
&property name=&hibernate.current_session_context_class&&thread&/property&
* 如果使用的是全局事务(jta事务)
&property name=&hibernate.current_session_context_class&&jta&/property&
如果采用的时Hibernate4,使用getCurrentSession()必须配置事务,否则无法取到session
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回调:
使用Hibernate的大多数应用程序需要某种形式的&上下文相关的& session,特定的session在整个特定的上下文范围内始终有效。然而,对不同类型的应用程序而言,要为什么是组成这种&上下文&下一个定义通常 是困难的;不同的上下文对&当前&这个概念定义了不同的范围。在3.0版本之前,使用Hibernate的程序要么采用自行编写的基于 ThreadLocal的上下文session,要么采用HibernateUtil这样的辅助类,要么采用第三方框架(比如Spring或Pico), 它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关session。
从3.0.1版本开 始,Hibernate增加了SessionFactory.getCurrentSession()方法。一开始,它假定了采用JTA事务,JTA事务 定义了当前session的范围和上下文(scope and context)。Hibernate开发团队坚信,因为有好几个独立的JTA TransactionManager实现稳定可用,不论是否被部署到一个J2EE容器中,大多数(假若不是所有的)应用程序都应该采用JTA事务管理。 基于这一点,采用JTA的上下文相关session可以满足你一切需要。
更好的是,从3.1开 始,SessionFactory.getCurrentSession()的后台实现是可拔插的。因此,我们引入了新的扩展接口 (org.hibernate.context.CurrentSessionContext)和新的配置参数 (hibernate.current_session_context_class),以便对什么是&当前session&的范围和上下文(scope and context)的定义进行拔插。Hibernate拦截器(Interceptor)【转】
拦截器(Intercept):与Struts2的拦截器机制基本一样,都是一个操作穿过一层层拦截器,每穿过一个拦截器就会触发相应拦截器的事件做预处理或善后处理。
Hibernate为我们提供了实现拦截器的接口org.hibernate.Interceptor,它里面提供了许多拦截事件。通常不需要实现这个接口,因为我们实现自己的拦截器不可能每一个事件都是必须的。所以Hibernate为我们提供了org.hibernate.Interceptor接口的一个空实现类org.hibernate.EmptyIntercept,通常情况下我们只需继承这个空实现类,Override需要的事件方法即可。
拦截器的工作原理简易示意图:
设置拦截器后,相应的操作都会先穿过一层层相应的拦截器,让拦截器执行预处理或善后处理。
拦截器使用实例:
public class AutoUpdateTimeInterceptor extends EmptyInterceptor
private static final long serialVersionUID = -9889388L;
* entity - POJO对象
* id - POJO对象的主键
* state - POJO对象的每一个属性所组成的集合(除了ID)
* propertyNames - POJO对象的每一个属性名字组成的集合(除了ID)
* types - POJO对象的每一个属性类型所对应的Hibernate类型组成的集合(除了ID)
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types)
if (entity instanceof People)
for (int index=0;index&propertyNames.index++)
/*找到名为"checkinTime"的属性*/
if ("checkinTime".equals(propertyNames[index]))
/*使用拦截器将People对象的"checkinTime"属性赋上值*/
state[index] = new Timestamp(new Date().getTime());
public class Client
public static void main(String[] args)
/*为Session添加拦截器*/
Session session = HibernateUtil.getSessionFactory().openSession(new AutoUpdateTimeInterceptor());
Transaction tx =
tx = session.beginTransaction();
People people = new People();
people.setName("zhangsan");
session.save(people);
tx.commit();
catch (Exception e)
if(tx!=null)
tx.rollback();
e.printStackTrace();
session.close();
}场景类中并没有显示的设置了people对象的"checkinTime"的属性值,启动该场景类代码,现在来查看数据库信息:
可以看到checkin_time这列属性依然被赋值了,说明该赋值操作是拦截器帮助我们完成的。使用拦截器的时候需要注意拦截器的返回值,我以前一直以为拦截器的返回值会控制一个操作是否可以继续,通过实验发现,即使返回false操作也会继续执行的,只是返回false的话,拦截器的所有设置都是无效的,不会反应到数据库中。
返回false:
public class AutoUpdateTimeInterceptor extends EmptyInterceptor
private static final long serialVersionUID = -9889388L;
* entity - POJO对象
* id - POJO对象的主键
* state - POJO对象的每一个属性所组成的集合(除了ID)
* propertyNames - POJO对象的每一个属性名字组成的集合(除了ID)
* types - POJO对象的每一个属性类型所对应的Hibernate类型组成的集合(除了ID)
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types)
if (entity instanceof People)
for (int index=0;index&propertyNames.index++)
/*找到名为"checkinTime"的属性*/
if ("checkinTime".equals(propertyNames[index]))
/*使用拦截器将People对象的"checkinTime"属性赋上值*/
state[index] = new Timestamp(new Date().getTime());
}查看插入的数据:
可以看到数据依然保存到数据库中了,但拦截器的操作并没有反映到数据库中,拦截器的操作是无效的。但是比较奇怪的是Console输出的SQL语句:
Hibernate:
insert into people (name, checkin_time, id) values (?, ?, ?)
Hibernate:
people set name=?, checkin_time=? where id=?居然多了一条Update语句,我使用了p6spy显示了这两条SQL语句的绑定值:
1|0|0|statement|insert into people (name, checkin_time, id) values (?, ?, ?)|insert into people (name, checkin_time, id) values ('zhangsan', ' 15:41:47.45', '')
1|0|0|statement|update people set name=?, checkin_time=? where id=?|update people set name='zhangsan', checkin_time='' where id=''可以看到,拦截器的操作会直接反映到数据库中的,但是如果返回值是false的话,Hibernate会产生一条Update SQL语句将拦截器的操作结果取消了。
最后,Hibernate的拦截器有两种设置方式,一种是使用sessionFactory.openSession(Interceptor
interceptor),这样的拦截器只会针对该session有效,又叫做局部拦截器。另一种是使用Configuration的setInterceptor(Interceptor
interceptor)方法设置,这样的拦截器对每一个session都有效,又称之为全局拦截器。
没有更多推荐了,Hibernate拦截器和监听器
拦截器(Interceptors)
Interceptor接口提供了从会话(session)回调(callback)应用程序(application)的机制, 这种回调机制可以允许应用程序在持久化对象被保存、更新、删除或是加载之前,检查并(或)修改其 属性。一个可能的用途,就是用来跟踪审核(auditing)信息。例如:下面的这个拦截器,会在一个实现了 Auditable接口的对象被创建时自动地设置createTimestamp属性,并在实现了Auditable接口的对象被更新时,同步更新lastUpdateTimestamp属性。
你可以直接实现Interceptor接口,也可以(最好)继承自EmptyInterceptor。
package org.hibernate.
import java.io.S
import java.util.D
import java.util.I
import org.hibernate.EmptyI
import org.hibernate.T
import org.hibernate.type.T
public class AuditInterceptor extends EmptyInterceptor {
public void onDelete(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
// do nothing
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if ( entity instanceof Auditable ) {
updates++;
for ( int i=0; i & propertyNames. i++ ) {
if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
currentState[i] = new Date();
public boolean onLoad(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if ( entity instanceof Auditable ) {
public boolean onSave(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if ( entity instanceof Auditable ) {
creates++;
for ( int i=0; i&propertyNames. i++ ) {
if ( "createTimestamp".equals( propertyNames[i] ) ) {
state[i] = new Date();
public void afterTransactionCompletion(Transaction tx) {
if ( tx.wasCommitted() ) {
System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
updates=0;
creates=0;
拦截器可以有两种:Session范围内的,和SessionFactory范围内的。
当使用某个重载的SessionFactory.openSession()使用Interceptor作为参数调用打开一个session的时候,就指定了Session范围内的拦截器。
Session session = sf.openSession( new AuditInterceptor() );
SessionFactory范围内的拦截器要通过Configuration中注册,而这必须在创建SessionFactory之前。在这种情况下,给出的拦截器会被这个SessionFactory所打开的所有session使用了;除非session打开时明确指明了使用的拦截器。SessionFactory范围内的拦截器,必须是线程安全的,因为多个session可能并发使用这个拦截器,要因此小心不要保存与session相关的状态。
new Configuration().setInterceptor( new AuditInterceptor() );
事件系统(Event system)
如果需要响应持久层的某些特殊事件,你也可以使用Hibernate3的事件框架。 该事件系统可以用来替代拦截器,也可以作为拦截器的补充来使用。
基本上,Session接口的每个方法都有相对应的事件。比如 LoadEvent,FlushEvent,等等(查阅XML配置文件 的DTD,以及org.hibernate.event包来获得所有已定义的事件的列表)。当某个方 法被调用时,Hibernate Session会生成一个相对应的事件并激活所
有配置好的事件监听器。系统预设的监听器实现的处理过程就是被监听的方法要做的(被监听的方法所做的其实仅仅是激活监听器, “实际”的工作是由监听器完成的)。不过,你可以自由地选择实现 一个自己定制的监听器(比如,实现并注册用来处理处理LoadEvent的LoadEventListener接口), 来负责处理所有的调用Session的load()方法的请求。
监听器应该被看作是单例(singleton)对象,也就是说,所有同类型的事件的处理共享同一个监听器实例,因此监听器 不应该保存任何状态(也就是不应该使用成员变量)。
用户定制的监听器应该实现与所要处理的事件相对应的接口,或者从一个合适的基类继承(甚至是从Hibernate自带的默认事件监听器类继承, 为了方便你这样做,这些类都被声明成non-final的了)。用户定制的监听器可以通过编程使用Configuration对象 来注册,也可以在Hibernate的XML格式的配置文件中进行声明(不支持在Properties格式的配置文件声明监听器)。 下面是一个用户定制的加载事件(load event)的监听器:
public class MyLoadListener implements LoadEventListener {
// this is the single method defined by the LoadEventListener interface
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
throws HibernateException {
if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
throw MySecurityException("Unauthorized access");
你还需要修改一处配置,来告诉Hibernate,除了默认的监听器,还要附加选定的监听器。
&hibernate-configuration&
&session-factory&
&event type="load"&
&listener class="com.eg.MyLoadListener"/&
&listener class="org.hibernate.event.def.DefaultLoadEventListener"/&
&/session-factory&
&/hibernate-configuration&
看看用另一种方式,通过编程的方式来注册它。
Configuration cfg = new Configuration();
LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
cfg.EventListeners().setLoadEventListeners(stack);
通过在XML配置文件声明而注册的监听器不能共享实例。如果在多个&listener/&节点中使用 了相同的类的名字,则每一个引用都将会产生一个独立的实例。如果你需要在多个监听器类型之间共享 监听器的实例,则你必须使用编程的方式来进行注册。
为什么我们实现了特定监听器的接口,在注册的时候还要明确指出我们要注册哪个事件的监听器呢? 这是因为一个类可能实现多个监听器的接口。在注册的时候明确指定要监听的事件,可以让启用或者禁用对某个事件的监听的配置工作简单些。
本文出自:http://blog.csdn.net/gaowenming/article/details/5035043
没有更多推荐了,

我要回帖

更多关于 销售中遇到那些拦截方面的问题 的文章

 

随机推荐