??xml version="1.0" encoding="utf-8" standalone="yes"?>
随着Hibernate在Java开发中的广泛应用,我们在用Hibernateq行对象持久化操作中也遇C各种各样的问题。这些问题往往都是我们对Hibernate~Z了解所_q里我讲个我从前遇到的问题及一些想法,希望能给大家一点借鉴?br />
q是在一ơ事务提交时遇到的异常?br /> an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
net.sf.hibernate.AssertionFailure: possible nonthreadsafe access to session
注:非possible non-threadsafe access to the session Q那是另外的错误Q类g不一P
q个异常应该很多的朋友都遇到q,原因可能各不相同。但所有的异常都应该是在flush或者事务提交的q程中发生的。这一般由我们在事务开始至事务提交的过E中q行了不正确的操作导_也会在多U程同时操作一个Session时发生,q里我们仅仅讨论单线E的情况Q多U程除了U程同步外基本与此相同?br />
至于具体是什么样的错误操作那Q我l大家看一个例子(假设Hibernate配置正确Qؓ保持代码z,不引入包及处理Q何异常)
SessionFactory sf = new Configuration().configure().buildSessionFactory() ;
Session s = sf.openSession();
Cat cat = new Cat();
Transaction tran = s.beginTransaction(); (1)
s.save(cat); (2)Q此处同样可以ؓupdate deleteQ?br />s.evict(cat); (3)
tran.commit(); (4)
s.close();(5)
q就是引h异常的典型错误。我当时遇Cq个异常Q检查代码时Ҏ没感觉到q段代码Z问题Q想当然的认为在Session上开始一个事务,通过Session对象存入数据库Q再这个对象从Session上拆,提交事务Q这是一个很正常的流E。如果这里正常的话,那问题一定在别处?br />
问题恰恰在q里Q我的想法也许没有错Q但是一个错误的论据所引出的观Ҏq都不可能是正确的。因为我一直以为直接在Ҏ据库q行操作Q忘C在我与数据库之间隔了一个HibernateQHibernate在ؓ我们提供持久化服务的同时Q也改变了我们对数据库的操作方式Q这U方式与我们直接的数据库操作有着很多的不同,正因为我们对q种方式没有一个大致的了解造成了我们的应用q未得到预先设想的结果?br />
那Hibernate的持久化机制到底有什么不同那Q简单的_Hibernate在数据库层之上实C一个缓存区Q当应用save或者update一个对象时QHibernateq未这个对象实际的写入数据库中Q而仅仅是在缓存中Ҏ应用的行为做了登讎ͼ在真正需要将~存中的数据flush入数据库时才执行先前登记的所有行为?br />
在实际执行的q程中,每个Session是通过几个映射和集合来l护所有与该Session建立了关联的对象以及应用对这些对象所q行的操作的Q与我们q次讨论有关的有entityEntriesQ与Session相关联的对象的映)、insertionsQ所有的插入操作集合Q、deletionsQ删除操作集合)、updatesQ更新操作集合)。下面我开始解释在最开始的例子中,Hibernate到底是怎样q作的?br />(1)生成一个事务的对象Qƈ标记当前的Session处于事务状态(注:此时q未启动数据库事务Q?br />(2)应用使用s.save保存cat对象Q这个时候Sessioncatq个对象攑օentityEntriesQ用来标记cat已经和当前的会话建立了关联,׃应用对cat做了保存的操作,Sessionq要在insertions中登记应用的q个插入行ؓQ行为包括:对象引用、对象id、Session、持久化处理c)?br />(3)s.evict(cat)cat对象从s会话中拆,q时s会从entityEntries中将catq个对象Ud?br />(4)事务提交Q需要将所有缓存flush入数据库QSession启动一个事务,q按照insert,update,…?delete的顺序提交所有之前登记的操作Q注意:所有insert执行完毕后才会执行updateQ这里的Ҏ处理也可能会你的程序搞得一团糟Q如需要控制操作的执行序Q要善于使用flushQ,现在cat不在entityEntries中,但在执行insert的行为时只需要访问insertionsp够了Q所以此时不会有M的异常。异常出现在插入后通知Session该对象已l插入完毕这个步骤上Q这个步骤中需要将entityEntries中cat的existsInDatabase标志|ؓtrueQ由于catq不存在于entityEntries中,此时Hibernatep为insertions和entityEntries可能因ؓU程安全的问题生了不同步(也不知道Hibernate的开发者是否考虑C子中的处理方式,如果没有的话Q这也许是一个bug吧)Q于是一个net.sf.hibernate.AssertionFailurep抛出Q程序终止?br />
我想现在大家应该明白例子中的E序到底哪里有问题了吧,我们的错误的认ؓs.save会立即的执行Q而将cat对象q早的与Session拆离Q造成了Session的insertions和entityEntries中内容的不同步。所以我们在做此cL作时一定要清楚Hibernate什么时候会数据flush入数据库Q在未flush之前不要已q行操作的对象从Session上拆R?br />
对于q个错误的解x法是Q我们可以在(2)?3)之间插入一个s.flush()强制Session缓存中的数据flush入数据库Q此时Hibernate会提前启动事务,?2)中的save登记的insert语句登记在数据库事务中,q将所有操作集合清I)Q这样在(4)事务提交时insertions集合已l是I的了,即我们拆离了cat也不会有M的异怺?br />前面单的介绍了一下Hibernate的flush机制和对我们E序可能带来的媄响以及相应的解决ҎQHibernate的缓存机制还会在其他的方面给我们的程序带来一些意想不到的影响。看下面的例子:
Qname为cat表的主键Q?br />Cat cat = new Cat();
cat.setName(“tom?;
s.save(cat);
cat.setName(“mary?;
s.update(cat);(6)
Cat littleCat = new Cat();
littleCat.setName(“tom?;
s.save(littleCat);
s.flush();
q个例子看v来有什么问题?估计不了解Hibernate~存机制的h多半会说没有问题Q但它也一样不能按照我们的思\正常q行Q在flushq程中会产生主键冲突Q可能你想问Q“在save(littleCat)之前不是已经更改cat.nameq已l更C么?Z么还会发生主键冲H那Q”这里的原因是我在解释W一个例子时所提到的缓存flush序的问题,Hibernate按照insert,update,…?delete的顺序提交所有登记的操作Q所以你的s.update(cat)虽然在程序中出现在s.save(littleCat)之前Q但是在flush的过E中Q所有的save都将在update之前执行Q这造成了主键冲H的发生?br />
q个例子中的更改Ҏ一h?6)之后加入s.flush()强制Session在保存littleCat之前更新cat的name。这样在W二ơflush时就只会执行s.save(littleCat)q次登记的动作,q样׃会出C键冲H的状况?br />
再看一个例子(很奇怪的例子Q但是能够说明问题)
Cat cat = new Cat();
cat.setName(“tom?;
s.save(cat); (7)
s.delete(cat);(8)
cat.id=null;(9)
s.save(cat);(10)
s.flush();
q个例子在运行时会生异常net.sf.hibernate.HibernateException: identifier of an instance of Cat altered from 8b818e920a86f038010a86f03a9d0001 to null
q里例子也是有关于缓存的问题Q但是原因稍有不同:
Q?Q和Q?Q的处理相同?br />Q?QSession会在deletions中登记这个删除动作,同时更新entityEntries中该对象的登记状态ؓDELETED?br />Q?QCatcȝ标识W字Dؓid,其|ؓnull便于重新分配idq保存进数据库?br />Q?0Q此时Session会首先在entityEntries查找cat对象是否曄与Session做过兌Q因为cat只改变了属性|引用q未改变Q所以会取得状态ؓDELETED的那个登记对象。由于第二次保存的对象已l在当前Session中删除,save会强制Session缓存flush才会l箋Qflush的过E中首先要执行最开始的save动作Q在q个save中检查了catq个对象的id是否与原来执行动作时的id相同。不q的是,此时cat的id被赋为nullQ异常被抛出Q程序终止(此处要注意,我们在以后的开发过E尽量不要在flush之前改变已经q行了操作的对象的idQ?br />
q个例子中的错误也是׃~存的g时更新造成的(当然Q与不正规的使用Hibernate也有关系Q,处理Ҏ有两U:
1、在Q?Q之后flushQ这样就可以保证Q?0Q处savecat作ؓ一个全新的对象q行保存?br />2、删除(9Q,q样W二ơsave所引v的强制flush可以正常的执行,在数据库中插入cat对象后将其删除,然后l箋W二ơsave重新插入cat对象Q此时cat的id仍与从前一致?br />
q两U方法可以根据不同的需要来使用Q呵呵,总觉得好像是很不正规的方式来解决问题Q但是问题本w也不够正规Q只希望能够在应用开发中l大家一些帮助,不对的地方也希望各位l与指正?br />
ȝ来说Q由于Hibernate的flush处理机制Q我们在一些复杂的对象更新和保存的q程中就要考虑数据库操作顺序的改变以及延时flush是否对程序的l果有媄响。如果确实存在着影响Q那可以在需要保持这U操作顺序的位置加入flush强制Hibernate缓存中记录的操作flush入数据库Q这Lh也许不太观Q但很有效?/td>
]]>
public
static
void
main(String[] args)
throws
Exception
{
System.out.println(isWrapClass(Long.
class
));
System.out.println(isWrapClass(String.
class
));
}
public
static
boolean
isWrapClass(Class clz)
{
try
{
return
((Class) clz.getField(
"
TYPE
"
).get(
null
)).isPrimitive();
}
catch
(Exception e)
{
return
false
;
}
}
]]>
function RunOnBeforeUnload() {
if (g_blnCheckUnload) {window.event.returnValue = 'You will lose any unsaved content';
}
}
</script>
<body onbeforeunload="RunOnBeforeUnload()">
</body>
]]>Definitions (from the RFC)
Various types of NAT (still according to the RFC)
]]>
2、至需要一位小写字母;
3、至需要一位大写字母;
4、至需要一位数字?br />String password = "password";
System.out.println(password != null && password.length() >= 6
&& password.length() <= 32
&& Pattern.compile("[a-z]+").matcher(password).find()
&& Pattern.compile("[A-Z]+").matcher(password).find()
&& Pattern.compile("[\\d]+").matcher(password).find());
]]>