分享
 
 
 

Using Hibernate3 as a JDBC framework (转载自TSS)

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

There's been a certain amount of noise recently surrounding simple JDBC frameworks like iBATIS. I've liked the idea of iBATIS myself, for use in applications which don't need an object-oriented domain model, and don't work with deep graphs of associated entities in a single transaction. A JDBC framework also makes good sense if you are working with some kind of "insane" legacy database; ORM solutions tend to assume that associations are represented as nice clean foreign keys with proper referential integrity constraints (Hibernate3 much less so than Hibernate 2.x).

Some people even suggest that JDBC frameworks are a suitable alternative to ORM, even for those systems to which ORM is best suited: object-oriented applications with clean relational schemas. They argue that you are always better off with hand-written SQL than generated SQL. Well, I don't think this is true, not only because the overwhelming bulk of SQL code needed by most applications is of the tedious kind, and simply does not require human intervention, but also because a JDBC framework operates at a different semantic level to ORM. A solution like iBATIS knows a lot less about the semantics of the SQL it is issuing, and of the resulting datasets. This means that there is much less opportunity for performance optimizations such as effficent caching. (By "efficient", I am referring mainly to efficient cache invalidation strategies, which are crucial to the usefulness of the cache.) Furthermore, whenever we have seen handwritten SQL, we have seen N+1 selects problems. It is extremely tedious to write a new SQL query for each combination of associations I might need to fetch together. HQL helps significantly here, since HQL is much less verbose than SQL. For a JDBC framework to be able to make the kind of optimizations that an ORM can make, it would have to evolve to a similar level of sophistication. Essentially, it would need to become an ORM, minus SQL generation. In fact, we already start to see this evolution taking place in existing JDBC frameworks. This begins to erode one of the stated benefits: the claimed simplicity.

It also raises the following interesting thought: if, by gradually adding stuff, a JDBC framework will eventually end up as ORM, minus SQL generation, why not just take an existing ORM solution like, ooh, um ... Hibernate, maybe ... and subtract the SQL generation?

The Hibernate team has long recognized the need to mix and match generated SQL with the occasional handwritten query. In older versions of Hibernate, our solution was simply to expose the JDBC connection Hibernate is using, so you can execute your own prepared statement. This started to change a while ago, and Max Andersen has recently done a lot of work on this. Now, in Hibernate3, it is possible to write an entire application with no generated SQL, while still taking advantage of all of Hibernate's other features.

Do we really expect or intend people to use Hibernate in this way? Well, not really - I doubt there are many people out there who really enjoy writing tedious INSERT, UPDATE, DELETE statements all day. On the other hand, we do think that quite a few people need to customize the occasional query. But to prove a point, I'll show you how you can do it, if you really want to.

Let's take a simple Person-Employment-Organization domain model. (You can find the code in the org.hibernate.test.sql package, so I'm not going to reproduce it here.) The simplest class is Person; here's the mapping:

<class name="Person" lazy="true">

<id name="id" unsaved-value="0">

<generator class="increment"/>

</id>

<property name="name" not-null="true"/>

<loader query-ref="person"/>

<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>

<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>

<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>

</class>

The first thing to notice is the handwritten INSERT, UPDATE and DELETE statements. The ? order of the parameters matches to the order in which properties are listed above (we'll have to eventually support named parameters, I suppose). I guess there is nothing especially interesting there.

More interesting is the <loader> tag: it defines a reference to a named query which is to be used anytime we load a person using get(), load(), or lazy association fetching. In particular, the named query might be a native SQL query, which it is, in this case:

<sql-query name="person">

<return alias="p" class="Person" lock-mode="upgrade"/>

SELECT NAME AS {p.name}, ID AS {p.id} FROM PERSON WHERE ID=? FOR UPDATE

</sql-query>

(A native SQL query may return multiple "columns" of entities; this is the simplest case, where just one entity is returned.)

Employment is a bit more complex, in particular, not all properties are included in the INSERT and UPDATE statements:

<class name="Employment" lazy="true">

<id name="id" unsaved-value="0">

<generator class="increment"/>

</id>

<many-to-one name="employee" not-null="true" update="false"/>

<many-to-one name="employer" not-null="true" update="false"/>

<property name="startDate" not-null="true" update="false"

insert="false"/>

<property name="endDate" insert="false"/>

<property name="regionCode" update="false"/>

<loader query-ref="employment"/>

<sql-insert>

INSERT INTO EMPLOYMENT

(EMPLOYEE, EMPLOYER, STARTDATE, REGIONCODE, ID)

VALUES (?, ?, CURRENT_DATE, UPPER(?), ?)

</sql-insert>

<sql-update>UPDATE EMPLOYMENT SET ENDDATE=? WHERE ID=?</sql-update>

<sql-delete>DELETE FROM EMPLOYMENT WHERE ID=?</sql-delete>

</class>

<sql-query name="employment">

<return alias="emp" class="Employment"/>

SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},

STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},

REGIONCODE as {emp.regionCode}, ID AS {emp.id}

FROM EMPLOYMENT

WHERE ID = ?

</sql-query>

The mapping for Organization has a collection of Employments:

<class name="Organization" lazy="true">

<id name="id" unsaved-value="0">

<generator class="increment"/>

</id>

<property name="name" not-null="true"/>

<set name="employments"

lazy="true"

inverse="true">

<key column="employer"/> <!-- only needed for DDL generation -->

<one-to-many class="Employment"/>

<loader query-ref="organizationEmployments"/>

</set>

<loader query-ref="organization"/>

<sql-insert>

INSERT INTO ORGANIZATION (NAME, ID) VALUES ( UPPER(?), ? )

</sql-insert>

<sql-update>UPDATE ORGANIZATION SET NAME=UPPER(?) WHERE ID=?</sql-update>

<sql-delete>DELETE FROM ORGANIZATION WHERE ID=?</sql-delete>

</class>

Not only is there a <loader> query for Organization, but also for its collection of Employments:

<sql-query name="organization">

<return alias="org" class="Organization"/>

SELECT NAME AS {org.name}, ID AS {org.id} FROM ORGANIZATION

WHERE ID=?

</sql-query>

<sql-query name="organizationEmployments">

<return alias="empcol" collection="Organization.employments"/>

<return alias="emp" class="Employment"/>

SELECT {empcol.*},

EMPLOYER AS {emp.employer}, EMPLOYEE AS {emp.employee},

STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},

REGIONCODE as {emp.regionCode}, ID AS {emp.id}

FROM EMPLOYMENT empcol

WHERE EMPLOYER = :id AND DELETED_DATETIME IS NULL

</sql-query>

When I was writing this code, I really started to feel the advantages of having Hibernate write the SQL for me. In just this simple example, I would have eliminated more than 35 lines of code that I would have to later maintain.

Finally, for ad hoc querying, we can use a native SQL query (a named query, or one embedded in the Java code). For example:

<sql-query name="allOrganizationsWithEmployees">

<return alias="org" class="Organization"/>

SELECT DISTINCT NAME AS {org.name}, ID AS {org.id}

FROM ORGANIZATION org

INNER JOIN EMPLOYMENT e ON e.EMPLOYER = org.ID

</sql-query>

Personally, I prefer to program in Java than in XML, so all this stuff is much too XML-heavy for my liking. I think I'll stick with SQL generation, wherever I can, which is almost everywhere. It's not that I don't like SQL. In fact, I am a great fan of SQL, and just love watching the queries scroll past when I turn Hibernate's logging on. It's just that Hibernate is much better at writing SQL than I am.

About the author

Gavin King (gavin@hibernate.org)

Blog: http://blog.hibernate.org/

Gavin King is the founder of the Hibernate project. He is co-author of the book Hibernate in Action, to be published by Manning Publications. He is currently involved in the JDO expert group and is employed by JBoss Inc, where he is redesigning the JBoss CMP engine.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有