第1 页 共1页1

从spring 2.5的文档里直接抄下的来配置文件,来配置数据库连接池和hibernate,结果发现运行一段时间后程序就会在查询数据库的地方卡死,而且日志里并没有打印现hibenrate的sql,问题到底发生在什么地方呢?我打开jconsole,连接到程序上一看,发现好多线程被阻塞了,而且都阻塞于pool.getConnection(),看来是DBCP出了问题。后来在网上查了一会,找到hibernate邮件列表上的一段讨论,原来hibernate开发人员认为DBCP设计得不好,BUG多,文档少,所以就不再提供对DBCP的支持了,要用数据库连接池就得用c3p0。看来hibernate每次用完连接都不还给连接池的。我也不想去找如何配置C3P0了,反正生产环境用的肯定是jboss的通过JNDI取到的数据源。干脆让tomcat来管理数据库连接池吧,让spring通过jndi来找到它。在tomcat里配置数据源很简单,官方网站上有详细说明。简单说把下面这段xml复制到tomcat安装目录下的conf/context.xml里就可以了:

<Resource name=”myDataSourceName” auth=”Container” type=”javax.sql.DataSource”
maxActive=”100″ maxIdle=”30″ maxWait=”10000″
username=”root” password=”" driverClassName=”com.mysql.jdbc.Driver”
url=”jdbc:mysql://localhost:3309/mydatabase” removeAbandoned=”true” removeAbandonedTimeout=”10″ logAbandoned=”false” />

上面这段Resource元素很容易理解,关键就是removeAbandoned和removeAbandonedTimeout这两个属性,它们是告诉DBCP把被遗弃的连接删掉,以及被遗弃多久才删除。hibernate就是那个常常遗弃连接的家伙。

Share/Save/Bookmark

如果在映射时,定义了 optimistic-lock=”version”,同时映射了  <version name=”version” type=”integer” unsaved-value=”negative”/>,那么就会起用hibernate的乐观锁机制。hibernate会在执行update merge等更新操作时对比数据库里的该行的version和当前对象的version是否一样,如果一样则更新,不一样则出异常。但并hibernate并不会在所有的更新操作时都做去对比这个version。

乐观锁是用来处理并发事务的。如果有多个事物同时对一行数据进行更新,那么才会检测这个version;反之,如果在一个事务内部,无论对version做怎么样的更改,都不会检测。那么hibernate是如何做到这一步的呢?在每个事务提交的时候,hibernate会判断当前事务里有哪些对象被更新到数据库里,如果这个对象处理持久化状态,则不检查它的version,如果处于游离态,则要在更新前检查version。

换句话说, 如果对象是在当前的事物里通过load方法,get方法,或者通过query等查询出来的,那么这个对象在当前事物里处于持久化状态,hibernate就不会检测version。如果对象不是在当前事务中被从数据库中读出来的,而是程序新建,或者是前一个事务或前一个session里取出来的,那么在当前事务里它就处于游离态,hibernate就会检version。

例如,有一个类Person,需要更新属性name。于你查出这个对象把这个对象在页面显示,并且让用户在页面上更改完成并提交时,form里包含那个对象的id,要更新的字段name和version。这样当用户提交后,在后台,如果你是这样做的:

//……

Transaction transaction = session.beginTransaction();

Person person = (Person) session.load( Person.class, id);

person.setName(name);

person.setVersion(version);

session.update(person);

transaction.commit();

//……

上面那种情况,因为被update的person是从当前事务中查询出来的,正处于持久化状态,所以在更新时,就算页面传来的version值比前数据库里的version值小,hibernate也不会报错,因为它根本就不会检测。如果想让hibernate检测,你可以这样做:

//……

Transaction transaction = session.beginTransaction();

Person person = new Person();

person.setId(id); 

person.setName(name);

person.setVersion(version);

session.update(person);

transaction.commit();

//……

由于是新建出来的person,这时的person处于游离态,所以在后面的更新时,hibernate就会按照你的意愿去检测version 了。

但是上面的方法还是有问题,就是如果那个Person里有很多个属性,而你只要改其中一部分,如果你不把所有的属性都扔到页面上,再在回来时写入新建的person里,那么在更新时,很可能会就会把一些你不想被更新字段给覆盖掉。而且,如果person和其它对象有外键关联,就更麻烦了。在这样的情况下,还是从数据库里取出当前对象,并更新它的那几个字段来得方便,不过这个时候如果你真的需要检测version,估计只好手动判断version 的值是否正确了。

Share/Save/Bookmark

1、到底在哪用cascade=”…”?
cascade属性并不是多对多关系一定要用的,有了它只是让我们在插入或删除对像时更方便一些,只要在cascade的源头上插入或是删除,所有cascade的关系就会被自己动的插入或是删除。便是为了能正确的 cascade,unsaved-value是个很重要的属性。Hibernate通过这个属性来判断一个对象应该save还是update,如果这个对象的id是unsaved-value的话,那说明这个对象不是persistence object要save(insert);如果id是非unsaved-value的话,那说明这个对象是persistence object(数据库中已存在),只要update就行了。saveOrUpdate方法用的也是这个机制。
2、到底在哪用inverse=”ture”?
inverse属性默认是false的,就是说关系的两端都来维护关系。这个意思就是说,如有一个Student, Teacher和TeacherStudent表,Student和Teacher是多对多对多关系,这个关系由TeacherStudent这个表来表现。那么什么时候插入或删除TeacherStudent表中的记录来维护关系呢?在用hibernate时,我们不会显示的对 TeacherStudent表做操作。对TeacherStudent的操作是hibernate帮我们做的。hibernate就是看hbm文件中指定的是”谁”维护关系,那个在插入或删除”谁”时,就会处发对关系表的操作。前提是”谁”这个对象已经知道这个关系了,就是说关系另一头的对象已经set 或是add到”谁”这个对象里来了。前面说过inverse默认是false,就是关系的两端都维护关系,对其中任一个操作都会处发对表系表的操作。当在关系的一头,如Student中的bag或set中用了inverse=”true”时,那就代表关系是由另一关维护的(Teacher)。就是说当这插入Student时,不会操作TeacherStudent表,即使Student已经知道了关系。只有当Teacher插入或删除时才会处发对关系表的操作。所以,当关系的两头都用inverse=”true”是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是 inverse=”false”或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。
在一对多关系中inverse就更有意义了。在多对多中,在哪端inverse=”true”效果差不多(在效率上)。但是在一对多中,如果要一方维护关系,就会使在插入或是删除”一”方时去update”多”方的每一个与这个”一”的对象有关系的对象。而如果让”多”方面维护关系时就不会有update 操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。当然这时也要遍历”多”方的每一个对象显示的操作修关系的变化体现到DB中。不管怎样说,还是让”多”方维护关系更直观一些。

Share/Save/Bookmark


第1 页 共1页1
© 2007 涂0实验室 | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress