我的Hibernate拦截器是什么不工作问题,怎么解决

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拦截器hibernate 拦截器 - ITeye问答
我用EmptyInterceptor拦截器,为什么无法拦截Query的executeUpdate操作呢,但是打印的hibernate sql都有执行删除啊
this.baseDAO.getQuery(
"delete from Abrelation where articleid=:articleid")
.setString("articleid", a.getId()).executeUpdate();
无法拦截,
问题补充:大哥 我说的是hibernate 高级java工程师 写道
简单看一下这个
struts2.0拦截器SessionAware Execute and Wait Interceptor 的使用
Execute and Wait Interceptor 的使用
在引入了webwork-default.xml的前提下
xwork.xml 配置 :
1、增加拦截器
&interceptor-ref name="execAndWait"&
&!-- 等待时间,执行时间没有超过此值,将不显示等待画面 (毫秒)--&
&param name="delay"&1000&/param&
&!-- 间隔检查时间,检查后台进程有没有执行完毕,如果完成了它就立刻返回,不用等到等待,用户不会看到等待画面 --&
&param name="delaySleepInterval"&50&/param&
&/interceptor-ref&
此拦截器必须放在所有拦截器的最后。
2、增加result
&result name="wait"&wait.jsp&/result&
如果没有找到"wait"结果,WebWork会自动生成一个wait结果(\com\opensymphony\webwork\interceptor\wait.ftl).这个结果是用FreeMarker做的,所以需要Freemarker支持才能正常工作。如果你不想在程序中加入FreeMarker,那就必须自己实现一个wait结果。这一般来说是有必要的,因为默认的wait页面很简单。
3、Action实现SessionAware接口
因为这个action将会以单独的线程执行,所以你不能用ActionContext,因为它是ThreadLocal.这也就是说如果你要访问session数据,你必须实现 SessionAware结构而不是调用ActionContext.getSesion() 。
public interface SessionAware{
public void setSession(Map map);
public abstract class AbsBasicAction extends ActionSupport implements SessionAware{
/** 当前 Session */
protected M
public void setSession(Map session) {
this.session =
4、实现 wait 结果 映射的 wait.jsp
必须设置该页面的meta信息,每隔5秒,重新请求一次前面的action。
&meta http-equiv="refresh" content="5;url="&ww:url includeParams="'all'" /&"&
简单看一下这个
struts2.0拦截器SessionAware Execute and Wait Interceptor 的使用
Execute and Wait Interceptor 的使用
在引入了webwork-default.xml的前提下
xwork.xml 配置 :
1、增加拦截器
&interceptor-ref name="execAndWait"&
&!-- 等待时间,执行时间没有超过此值,将不显示等待画面 (毫秒)--&
&param name="delay"&1000&/param&
&!-- 间隔检查时间,检查后台进程有没有执行完毕,如果完成了它就立刻返回,不用等到等待,用户不会看到等待画面 --&
&param name="delaySleepInterval"&50&/param&
&/interceptor-ref&
此拦截器必须放在所有拦截器的最后。
2、增加result
&result name="wait"&wait.jsp&/result&
如果没有找到"wait"结果,WebWork会自动生成一个wait结果(\com\opensymphony\webwork\interceptor\wait.ftl).这个结果是用FreeMarker做的,所以需要Freemarker支持才能正常工作。如果你不想在程序中加入FreeMarker,那就必须自己实现一个wait结果。这一般来说是有必要的,因为默认的wait页面很简单。
3、Action实现SessionAware接口
因为这个action将会以单独的线程执行,所以你不能用ActionContext,因为它是ThreadLocal.这也就是说如果你要访问session数据,你必须实现 SessionAware结构而不是调用ActionContext.getSesion() 。
public interface SessionAware{
public void setSession(Map map);
public abstract class AbsBasicAction extends ActionSupport implements SessionAware{
/** 当前 Session */
protected M
public void setSession(Map session) {
this.session =
4、实现 wait 结果 映射的 wait.jsp
必须设置该页面的meta信息,每隔5秒,重新请求一次前面的action。
&meta http-equiv="refresh" content="5;url="&ww:url includeParams="'all'" /&"&
已解决问题
未解决问题Hibernate 拦截器Interceptor使用
如果想在DAO层对插入,更新,读取数据进行过滤更改,可以使用EmptyInterceptor。用法如下:
public class VideoServerInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 8183911L;
public boolean onFlushDirty(
Object entity,
Serializable id,
Object[] state,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if (entity instanceof VideoServer) {
boolean modified =
for (int i = 0; i & propertyNames. i++) {
if ("adslPassword".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssEncrypt(state[i].toString());
} else if ("tr069Password".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssEncrypt(state[i].toString());
} else if ("loginPassword".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssEncrypt(state[i].toString());
public boolean onLoad(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
if (entity instanceof VideoServer) {
boolean modified =
for (int i = 0; i & propertyNames. i++) {
if ("adslPassword".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssDecrypt(state[i].toString());
} else if ("tr069Password".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssDecrypt(state[i].toString());
} else if ("loginPassword".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssDecrypt(state[i].toString());
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
if (entity instanceof VideoServer) {
boolean modified =
for (int i = 0; i & propertyNames. i++) {
if ("adslPassword".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssEncrypt(state[i].toString());
} else if ("tr069Password".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssEncrypt(state[i].toString());
} else if ("loginPassword".equals(propertyNames[i])) {
if (null != state[i]) {
modified =
state[i] = VissEncode.vssEncrypt(state[i].toString());
这样就实现了对属性的更改,当然也可以作为实体类的日志记录。。。这里转一下其他文章转自http://www.yihaomen.com/article/java/464.htm
===============================================================================================
开发应用程序的过程中,经常会对一些比较重要的数据修改都需要写日志。在实际工作的工程中,这些数据都是存在表中的, 一个常见的做法是用触发器,在增删改的时候,用触发器将数据写入到另一张表中去,但个人不推荐这么做,原因如下:
1. 如果有多个表,得写很多触发器。
2. 触发器与数据库特性关联太紧,不同的数据库,虽然思路一样,但语法却不太一样。
对数据库表操作的日志记录,完全可以利用Hibernate的Interceptor特性来实现,也就是拦截器。下面用一个具体的例子来说明如何使用Hibernate的Interceptor。创建一个表,用来记录日志的表
Create TABLE
`auditlog` (
`AUDIT_LOG_ID` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`ACTION` VARCHAR(100) NOT NULL,
`DETAIL` text NOT NULL,
`CreateD_DATE` DATE NOT NULL,
`ENTITY_ID` BIGINT(20) UNSIGNED NOT NULL,
`ENTITY_NAME` VARCHAR(255) NOT NULL,
PRIMARY KEY (`AUDIT_LOG_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
创建这个表对应的实体类:
@Table(name = "auditlog")
public class AuditLog implements java.io.Serializable {
private Long auditLogId;
private Date createdD
private long entityId;
private String entityN
public AuditLog() {
public AuditLog(String action, String detail, Date createdDate,
long entityId, String entityName) {
this.action =
this.detail =
this.createdDate = createdD
this.entityId = entityId;
this.entityName = entityN
@GeneratedValue(strategy = IDENTITY)
@Column(name = "AUDIT_LOG_ID", unique = true, nullable = false)
public Long getAuditLogId() {
return this.auditLogId;
.... 余下部分可以参考提供下载的源代码.
创建一个接口,所有实现了这个接口的实体类,都会写日志
package com.mkyong.
//market interface
public interface IAuditLog {
public Long getId();
public String getLogDeatil();
这里有两个方法,getId,getLogDetail 需要实现类去实现具体的方法,也就是要被写入到日志表中的详细记录.创建一个类实现了IAuditLog 接口,并给出接口方法的具体实现
@Table(name="stock")
public class Stock implements java.io.Serializable,IAuditLog
private static final long serialVersionUID = 1L;
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="STOCK_ID")
private Integer stockId;
@Column(name="STOCK_CODE", length=10)
private String stockC
@Column(name="STOCK_NAME", length=20)
private String stockN
public Stock() {
public Stock(String stockCode, String stockName) {
this.stockCode = stockC
this.stockName = stockN
....省略部分getter,setter。
@Transient
public Long getId(){
return this.stockId.longValue();
@Transient
public String getLogDeatil(){
StringBuilder sb = new StringBuilder();
sb.append(" Stock Id : ").append(stockId)
.append(" Stock Code : ").append(stockCode)
.append(" Stock Name : ").append(stockName);
return sb.toString();
创建记录日志的工具类,所有写日志公用
public class AuditLogUtil{
public static void LogIt(String action,
IAuditLog entity){
Session tempSession = HibernateUtil.getSessionFactory().openSession();
tempSession.getTransaction().begin();
AuditLog auditRecord = new AuditLog(action,entity.getLogDeatil()
, new Date(),entity.getId(), entity.getClass().toString());
tempSession.save(auditRecord);
tempSession.getTransaction().commit();
} finally {
tempSession.close();
创建 Hibernate interceptor 拦截器,这是重点,这里拦截所有需要记录日志的类,并处理
public class AuditLogInterceptor extends EmptyInterceptor{
private Set inserts = new HashSet();
private Set updates = new HashSet();
private Set deletes = new HashSet();
public void setSession(Session session) {
this.session=
public String onPrepareStatement(String sql) {
System.out.println("execute sql: " + sql);
return super.onPrepareStatement(sql);
public boolean onSave(Object entity,Serializable id,
Object[] state,String[] propertyNames,Type[] types)
throws CallbackException {
System.out.println("onSave");
if (entity instanceof IAuditLog){
inserts.add(entity);
public boolean onFlushDirty(Object entity,Serializable id,
Object[] currentState,Object[] previousState,
String[] propertyNames,Type[] types)
throws CallbackException {
System.out.println("onFlushDirty");
if (entity instanceof IAuditLog){
updates.add(entity);
public void onDelete(Object entity, Serializable id,
Object[] state, String[] propertyNames,
Type[] types) {
System.out.println("onDelete");
if (entity instanceof IAuditLog){
deletes.add(entity);
//called before commit into database
public void preFlush(Iterator iterator) {
System.out.println("preFlush");
//called after committed into database
public void postFlush(Iterator iterator) {
System.out.println("postFlush");
for (Iterator it = inserts.iterator(); it.hasNext();) {
IAuditLog entity = (IAuditLog) it.next();
System.out.println("postFlush - insert");
AuditLogUtil.LogIt("Saved",entity);
for (Iterator it = updates.iterator(); it.hasNext();) {
IAuditLog entity = (IAuditLog) it.next();
System.out.println("postFlush - update");
AuditLogUtil.LogIt("Updated",entity);
for (Iterator it = deletes.iterator(); it.hasNext();) {
IAuditLog entity = (IAuditLog) it.next();
System.out.println("postFlush - delete");
AuditLogUtil.LogIt("Deleted",entity);
} finally {
inserts.clear();
updates.clear();
deletes.clear();
这里面有几个比较常用的方法:
onSave – 保存数据的时候调用,数据还没有保存到数据库.
onFlushDirty – 更新数据时调用,但数据还没有更新到数据库
onDelete – 删除时调用.
preFlush – 保存,删除,更新 在提交之前调用 (通常在 postFlush 之前).
postFlush – 提交之后调用(commit之后)写测试例子, 添加数据,更新数据,然后再删掉
public class App {
public static void main(String[] args) {
Session session =
Transaction tx =
AuditLogInterceptor interceptor = new AuditLogInterceptor();
session = HibernateUtil.getSessionFactory().withOptions().interceptor(interceptor).openSession();
//session = HibernateUtil.getSessionFactory().openSession();
//interceptor.setSession(session);
//test insert
tx = session.beginTransaction();
Stock stockInsert = new Stock();
stockInsert.setStockCode("1111");
stockInsert.setStockName("yihaomen");
session.saveOrUpdate(stockInsert);
tx.commit();
//test update
tx = session.beginTransaction();
Query query = session.createQuery("from Stock where stockCode = '1111'");
Stock stockUpdate = (Stock)query.list().get(0);
stockUpdate.setStockName("yihaomen-update");
session.saveOrUpdate(stockUpdate);
tx.commit();
//test delete
tx = session.beginTransaction();
session.delete(stockUpdate);
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
} catch (RuntimeException rbe) {
// log.error("Couldn抰 roll back transaction", rbe);
} finally {
if (session != null) {
session.close();
运行结果如下:
execute sql: insert into stock (STOCK_CODE, STOCK_NAME) values (?, ?)
Hibernate: insert into stock (STOCK_CODE, STOCK_NAME) values (?, ?)
postFlush - insert
Hibernate: insert into auditlog (ACTION, CreateD_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) values (?, ?, ?, ?, ?)
execute sql: select stock0_.STOCK_ID as STOCK_ID1_1_, stock0_.STOCK_CODE as STOCK_CO2_1_, stock0_.STOCK_NAME as STOCK_NA3_1_ from stock stock0_ where stock0_.STOCK_CODE='1111'
Hibernate: select stock0_.STOCK_ID as STOCK_ID1_1_, stock0_.STOCK_CODE as STOCK_CO2_1_, stock0_.STOCK_NAME as STOCK_NA3_1_ from stock stock0_ where stock0_.STOCK_CODE='1111'
onFlushDirty
execute sql: update stock set STOCK_CODE=?, STOCK_NAME=? where STOCK_ID=?
Hibernate: update stock set STOCK_CODE=?, STOCK_NAME=? where STOCK_ID=?
postFlush - update
Hibernate: insert into auditlog (ACTION, CreateD_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) values (?, ?, ?, ?, ?)
execute sql: delete from stock where STOCK_ID=?
Hibernate: delete from stock where STOCK_ID=?
postFlush - delete
Hibernate: insert into auditlog (ACTION, CreateD_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) values (?, ?, ?, ?, ?)
另外查看 auditLog 这张表, 可以看到日志成功写入
另外,如果是在SPRING 容器中使用,应该将这个interceptor 注入进去
&bean id="hibermateInterceptor" class="com.yihaomen.interceptor.AuditLogInterceptor"/&
&bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"&
&property name="dataSource"&
&ref local="dataSource_jdbc"/&
&/property&
&property name="entityInterceptor" ref="hibermateInterceptor"/&
..............
这样就能实现对整个项目中需要记录日志的实体类进行拦截,并记录增删改的日志记录. 还是很方便的,重点就是 Hibernate interceptor 的使用.
测试在是在 Hibernate 4.3 下测试的, 如果是hibernate 3 在openSession的时候是不同的,hibernate4用了session = HibernateUtil.getSessionFactory().withOptions().interceptor(interceptor).openSession(); 如果是Hibernate 3的话,应该是:session = HibernateUtil.getSessionFactory().openSession(interceptor);。
没有更多推荐了,}

我要回帖

更多关于 拦截新郎的问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信