JPA的自动脏检测

问题1:
当你在做修改的动作时,就算你不给这些按钮加上action,只要有值改变,它就会去执行更新动作。。。。我遇到的最头痛的问题是:当用户对某行数据进行修改的时候,在后台有个验证用户输入的方法,若输入的数据非法,则不会执行更新,并弹出提示框。 可是运行后却让出现这样的现象:输入非法的数据时,它会弹出提示消息,但是却执行了更新的动作!! 我把action去掉后,奇怪的是一但有值改变,它也会执行更新的动作。。。 只有<s:button />不会出现此问题
解决方法:
这是JPA的自动脏检测,解决办法,如果你是开启一个长会话,记得在@Begin里面将flushMode=设置为MANUAL模式,可解决这个问题,给你一个例子。

@Begin(join = true, flushMode = FlushModeType.MANUAL)

问题2:
<begin-conversation join="true" flush-mode="manual"/> ,而改成这样之后 就不会出现以上的问题了,可是页面中的值却跟着改变了,我刷新也没用,直到我关闭页面 重新运行页面,它的值才会显示成最初未改动的值。。。而在整个过程当中,DB的数据是一直没变的(这是我想要的),可是我怎么样才能让页面的值不会出现那种“假象”??
解决方法:
下面的给你个例子参考.你可以使用在你的实体中使用增加一个@PostLoad标记方法,来将name的初始值保存到nameInitial临时变量中.

@Transient
private String nameInitial;

@NotNull
@Column(name = "ROLE_NAME", length = 50)
@Length(max = 50)
private String name;


@PostLoad
public void afterLoad() {
this.nameInitial = this.name;
}
使用@PostLoad方法,这个是代表在实体装入时把name的初始值传给nameInitial,
这样你就可以保存你修改后name的初始值.

产生上面问题的缘由和解决的原因:
XML中的<begin-conversation join="true" flush-mode="manual"/>
等同于
@Begin(join = true,flushMode = FlushModeType.MANUAL)

意义是一样的,都是开启一个长会话,将flushMode设置为MANUAL,

将flushMode设置为MANUAL的原因,下面假如你是继承EntityHome或是HibernateEntityHome类,我以EntityHome源代码update方法为例说明.

/**
* Base class for Home objects of JPA entities.
*
* @author Gavin King
*
*/
public class EntityHome<E> extends Home<EntityManager, E> {


@Transactional
public String update()
{
joinTransaction();
getEntityManager().flush();
updatedMessage();
raiseAfterTransactionSuccessEvent();
return "updated";
}

}

注意@Transactional事务标记以及getEntityManager().flush(),如果标记为@Begin(join = true),将flushMode将默认为AUTO,意味着你对在会话期间对实体做的任何修改,持入化上下文将直接进行脏检测,发现实体修改Seam容器将会自动调用getEntityManager().flush()方法清空缓存,提交到数据库,所以才会产生你现在的问题.将flushMode设置为MANUAL将是告诉Seam由你自己来调用getEntityManager().flush()方法,也就是你想要的做完验证之后合法的数据再提交到数据库.当然这些问题还有可能取决于你Entity的equals()和hashCode()方法的重写,这是Hibernate与JPA的知识,这里不作过多的讨论.

而改成这样之后 就不会出现以上的问题了,可是页面中的值却跟着改变了,我刷新也没用,直到我关闭页面 重新运行页面,它的值才会显示成最初未改动的值。。。而在整个过程当中,DB的数据是一直没变的(这是我想要的),可是我怎么样才能让页面的值不会出现那种“假象”??

这个问题,相信你已经理解Spring与Seam最大的区别,一个是无状态的,一个是有状态的,以及Seam的双向注入@In @Out, 当你注释@Beject标志,或是在XML写入一个begin-conversation节点,都代表是开启一个长会话,直到你标记@End或是在XML 写入<env-conversation>标记,才会结束当前这个会话,在会话期间你对@Name("")标记的实体进行的修改,Seam都会返回到Seam管理的上下文中,说白点就是把修改的后的对象重新复制一份到Seam上下文容器中,Seam容器透明的管理.

解决办法,下面的给你个例子参考.你可以使用在你的实体中使用增加一个@PostLoad标记方法,来将name的初始值保存到nameInitial临时变量中.

@Transient
private String nameInitial;

@NotNull
@Column(name = "ROLE_NAME", length = 50)
@Length(max = 50)
private String name;


@PostLoad
public void afterLoad() {
this.nameInitial = this.name;
}
使用@PostLoad方法,这个是代表在实体装入时把name的初始值传给nameInitial,
这样你就可以保存你修改后name的初始值.

以上仅供参考,个人的理解.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值