分享
 
 
 

J2EE - 如何在JBoss中解决自动增长键值问题

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

J2EE - 如何在JBoss中解决自动增长键值问题

【前言】

自动增长键值是关系数据库的一个显著功能特征,如MS Sql Server、MySql可以直接将一个字段设置成自动增长(auto-increment)类型,Oracle也提供了类似的sequence number功能。然而在EJB2.0规范之前,CMP部分并没有对自动增长键有相关的说明,这一缺陷一直深受J2EE开发人员的诟病,而应用服务器开发商为此也提出了各自的解决方案,但是在没有上升到规范的高度之前,这些解决方案都是非正式的,也就是说缺乏通用性,如闻名遐尔的Weblogic,在1.0规范的时候也仅仅是对一些主流数据库进行了支持。JBoss的3.0版本没有支持auto-increment特征,到3.2版本才正式支持。本篇是介绍在3.0版本下JBoss如何使用AutoNumber这个EJB插件来实现数据库表键值自动增长功能,在文章的后半部分介绍在3.2版本中如何使用“unknown keys”特征来真正实现自动键值增长。后台数据库使用的是MySql4.0.12版本。

EJB是一个仍在快速发展的技术,发展就意味着变化,而“快速”同样适用于“变化”二字,尤其在EJB的CMP部分,其变化尤为突出。CMP是EJB最精华的体现,由于使用了对象的方式来描述数据库,而目前大多数据库仍以关系类型为主,表达与被表达之间存在着不可忽略的差异,因而EJB规范在制定中需要考虑相关因素,不得不做出均衡的取舍。由于前面所提到的发展性,规范的最终成熟也不是一蹴而就,一个规范的推出可能迫于时机因素(技术或者是商业) 而推迟,开发人员在实际开发当中应该能够明确意识到这点,在遇到规范所引发的局限的地方,充分发挥主观能动性,在考虑问题解决问题方面能够突破到一个新境界。

JBoss3.0提供的AutoNumber处理方式

JBoss3.0给用户提供了一个AutoNumber插件来“伪”实现CMP的键值自动增长,之所以冠以一个“伪”字,是因为这个功能并不是通过数据库自身的功能来实现,而是利用了一个工厂类型的CMP Entity Bean来为各类实体Bean(对应数据库中的表)生成相应的键值,用户不必考虑如何来维护键值的唯一性和连续性,这一切都由AutoNumber来代理,用户要做的就是在使用这个“插件”之前先部署这个Bean Jar,并弄清楚其调用原理以知悉如何来使用这个CMP Bean。

在着手部署这个插件之前,先来看一段JBoss源代码文件AutoNumberFactory的代码注释:

/**

* Gets the next key for the given collection.

* Note 1: you must deploy EJB AutoNumber

* Note 2: the keys are persistent in your database, independent of

* the actual table

* Note 3: you can only add instances to the collection which have a

* key generated by this method, otherwise the keys are not guaranteed

* to be unique

* Note 4: key values are >= 0

*/

大意如下:该类是为了给一个键集合获取下一个键值,为了使用这个工厂方法,你首先必须部署AutoNumber这个EJB,键集信息被存储在数据库中,与实际表无关,为了确保键值的唯一性,你只能通过这个工厂方法来生成键值,键值的范围是大于或等于0的整数。

部署AutoNumber CMP Entity Bean

AutoNumber插件的位置是在%JBOSS_HOME%/server/default/lib/ autonumber-plugin.jar,令人觉得惊奇的是JBoss没有为这个插件如何部署给出例子或者是指导性的说明文件(或者是本人尚未发现)。在研究了一下相关的源代码后,以下是一个部署的实例,以及在数据库中如何创建一个表来对应这个实体Bean。

首先在MySql中创建一张表,来对应AutoNumber bean。这张表很简单,只包含两个字段列name和value,name列用以存储键值名称,value用以存储当前可用的键值。DDL语句如下:

CREATE TABLE `myauto` (

`name` varchar(20) NOT NULL default '',

`value` int(11) NOT NULL default '0',

PRIMARY KEY (`name`),

UNIQUE KEY `name` (`name`)

) TYPE=InnoDB

这里将name设置为主键,并且为unique,约束了键名不可重复。

Ejb-jar.xml描述文件:

<ejb-jar>

<enterprise-beans>

<entity>

<display-name>MyAutoNumber</display-name>

<ejb-name>AutoNumber</ejb-name>

<home>org.jboss.varia.autonumber.AutoNumberHome</home>

<remote>org.jboss.varia.autonumber.AutoNumber</remote>

<ejb-class>org.jboss.varia.autonumber.AutoNumberEJB2</ejb-class>

<persistence-type>Container</persistence-type>

<prim-key-class>java.lang.String</prim-key-class>

<reentrant>False</reentrant>

<cmp-version>2.x</cmp-version>

<abstract-schema-name>autonumberschema</abstract-schema-name>

<cmp-field>

<field-name>name</field-name>

</cmp-field>

<cmp-field>

<field-name>value</field-name>

</cmp-field>

<primkey-field>name</primkey-field>

</entity>

</enterprise-beans>

<assembly-descriptor>

<container-transaction>

<method>

<ejb-name>AutoNumber</ejb-name>

<method-name>*</method-name>

</method>

<trans-attribute>Required</trans-attribute>

</container-transaction>

</assembly-descriptor>

</ejb-jar>

Jbosscmp-jdbc.xml描述文件:

<jbosscmp-jdbc>

<enterprise-beans>

<entity>

<ejb-name>AutoNumber</ejb-name>

<datasource>java:/MySqlDS</datasource>

<datasource-mapping>mySQL</datasource-mapping>

<create-table>false</create-table>

<remove-table>false</remove-table>

<read-only>false</read-only>

<table-name>myauto</table-name>

<cmp-field>

<field-name>name</field-name>

<column-name>NAME</column-name>

</cmp-field>

<cmp-field>

<field-name>value</field-name>

<column-name>VALUE</column-name>

</cmp-field>

</entity>

</enterprise-beans>

</jbosscmp-jdbc>

<datasource>标签值改成你相应的数据源名称,<table-name>及<field-name>标签值也改成你相应建立的数据库表及字段列名称。

Jboss.xml描述文件:

<jboss>

<enterprise-beans>

<entity>

<ejb-name>AutoNumber</ejb-name>

<jndi-name>JBossUtilAutoNumber</jndi-name>

</entity>

</enterprise-beans>

</jboss>

在正式部署前,将部署文件置入一个meta-inf目录中,然后连同autonumber-plugin.jar文件一同jar进一个新的jar文件当中,最后是将该新jar文件copy至%JBOSS_HOME%/server/default/deploy目录并启动JBoss以观部署后效。<jndi-name>标签指明的jndi名必须是JBossUtilAutoNumber,因为AutoNumberFactory就是通过这个名字来调用AutoNumberBean的本地引用的。

AutoNumber的调用

AutoNumber这个cmp bean是通过AutoNumberFactory这个工厂类的静态类方法来调用的,调用方法很简单,假如你有一张表叫table1,里头有一整数类型的列充当了主键,那么可以将这个键值集合命名成“table1_pk”,通过AutoNumberFactory. getNextInteger(“table1_pk”)就可以获得表table1的当前一个Integer类型的键值。如果是第一次调用,那么获得的值为0,通过这个工厂类来调用AutoNumber不用做任何初始化工作,在调用的CMP类文件中要写这样一个import语句:import org.jboss.varia.autonumber.AutoNumberFactory;

此外AutoNumber还提供了键值初始化和reset的方法,详细参考AutoNumberFactory的源代码文件。AutoNumberFactory主要用在cmp bean的ejbCreate方法中,如:

Integer myPk=AutoNumberFactory. getNextInteger(“table1_pk”);

setId(myPk);

AutoNumber的原理

AutoNumber插件的核心是一个CMP bean,并且使用了工厂方式来生成自动增长键,不过这个工厂模式是建立在数据库上,可以同时为多个表生成键值。每次调用getNextInteger的时候,AutoNumberFactory通过JNDI名获得AutoNumber bean的本地接口,调用bean提供的方法,该方法要做的就是返回当前数据库中的键值,而后将键值加一。

小结

AutoNumber相当于开辟了另一条路来方便用户获取一个整数类型的键值,并确保通过该路径获取的键值能够保持唯一性。但是这种绕开数据库的方式有着很大的问题,因为它不是数据库自身来维护的,比如你在另一个数据访问程序(如mysql提供的客户端)来为一个表增加一条记录,如果你忘记了模拟AutoNumber的形式获得键值,也就是忘了在myauto表中将相应键值加一,那么你的ejb下一次获得的键值将会产生冲突。另外一个缺点就是键值只支持Integer类型。对于第一个缺点,是AutoNumber无法解决的,但是第二个缺点却是可以解决的,那就是创建我们自己的Factory方法,支持各种需要的主键数据类型,AutoNumber给了我们一个很好的设计范例。

在JBoss3.2中实现自动增长键值功能

先决条件

对于MySql的用户来说,你需要一个更好的引擎来支持更好的功能,为了让3.2版本能够在mysql中完成这个功能实现的一个例子,你首先要做的就是下载一个先进的JDBC引擎,

MySQL Connector/J 3,该引擎支持了JDBC3.0,至于原因可参看【部署描述文件】部分。这里稍微引开一个话题,如果你是一个好的java程序员,那么你必须时刻对版本保持高度的敏感性,看看Jbuilder版本更新之快之大,JBoss4.0也在日程当中 ,更高的版本意味着更好的功能,但是,不要遗漏了版本之间的差异,不仅仅是主体的差异,还有联系体的差异(这里是JBoss是主体,mysql jdbc driver是联系体),不然你会头碰南墙欲哭无泪,“为伊消得人憔悴”,云云。闲话少说,将Connector/J 3的驱动jar文件拷贝至%JBOSS_HOME%/ server/default/lib/之下,记得将原有驱动删除。

一个CMP Bean场景

为了方便描述how to,使用一个简单的cmp bean作为实例来加以描述。假设有一张表auto_inc_test,只有两个字段id和name,其中id是自动增长类型,sql脚本如下:

create table auto_inc_test (

id TINYINT(4) NOT NULL auto_increment,

name varchar(10),

primary key (id)

) type=InnoDB

至于如何设计和实现这个cmp bean,这里就不详加描述,对于Jbuilder而言仅仅是几个drag and drop的回合,我们将重心放在部署文件的配置上面。我们的bean 名称叫做TestAutoIncBean,有一个ejbCreate方法,只接受一个字符类型数据为参数,即name字段,id和name字段在bean中都有get/set方法。

部署描述文件

JBoss3.2较之3.0版本又有了极其不同的差异,一个就是对EJB2.0规范的支持,其体现在部署文件描述又变了。在三个描述文件ejb-jar.xml、jboss.xml和jbosscmp-jdbc.xml中,前两个与一般部署无异,最后一个部署文件的描述如下:

Jbosscmp-jdbc.xml描述文件

<!-- $Id: standardjbosscmp-jdbc.xml,v 1.39.2.12 2003/03/02 13:43:33 cooperfbi Exp $ -->

<jbosscmp-jdbc>

<defaults>

<datasource>java:/MySqlDS</datasource>

<datasource-mapping>mySQL</datasource-mapping>

<create-table>false</create-table>

<remove-table>false</remove-table>

<read-only>false</read-only>

<time-out>300</time-out>

<pk-constraint>true</pk-constraint>

<fk-constraint>false</fk-constraint>

<row-locking>false</row-locking>

<preferred-relation-mapping>foreign-key</preferred-relation-mapping>

<read-ahead>

<strategy>on-load</strategy>

<page-size>1000</page-size>

<eager-load-group>*</eager-load-group>

</read-ahead>

<list-cache-max>1000</list-cache-max>

<unknown-pk>

<key-generator-factory>UUIDKeyGeneratorFactory</key-generator-factory>

<unknown-pk-class>java.lang.Integer</unknown-pk-class>

<jdbc-type>INTEGER</jdbc-type>

<sql-type>INTEGER</sql-type>

</unknown-pk>

<entity-command name="mysql-get-generated-keys"/>

</defaults>

<enterprise-beans>

<entity>

<ejb-name>TestAutoInc</ejb-name>

<table-name>auto_inc_test</table-name>

<cmp-field>

<field-name>id</field-name>

<column-name>id</column-name>

</cmp-field>

<cmp-field>

<field-name>name</field-name>

<column-name>name</column-name>

</cmp-field>

</entity>

</enterprise-beans>

<dependent-value-classes>

</dependent-value-classes>

</jbosscmp-jdbc>

这里把与数据库映射的描述部分放在<enterprise-beans>标签外部,意指这些数据库设置对所有entity bean适用,也可以放在<enterprise-beans>内部对单独的entity bean进行指定。<unknown-pk>是JBoss3.2新增的描述标签,用户可以在其中指定<key-generator-factory>,该标签指明获得键值工厂生成器的JNDI名称,这里是UUIDKeyGeneratorFactory,由JBoss服务器自身内部提供的,用户不必关注其中细节,另外用户要指定主键类的类型,这里是Integer type。另外值得一提的是<entity-command>标签,它指明了在创建entity bean的时候要调用哪个辅助插件,这里的值是"mysql-get-generated-keys",当创建entity bean的时候调用org.jboss.ejb.plugins.cmp.jdbc.mysql.JDBCMySQLCreateCommand插件,该插件则调用了Connector /J3提供的接口来处理与主键相关的事务。注意该描述文件的头一句<!-- $Id: standardjbosscmp-jdbc.xml,v 1.39.2.12 2003/03/02 13:43:33 cooperfbi Exp $ -->,虽然只是注释,但是对JBoss的xml解析器而言这个信息非常重要,因为JBoss仍要处理低版本的部署文件,这个id是为了告诉JBoss用什么规则来解析。

总结

通过以上两个对auto-increment问题在JBoss不同版本中的解决方案,可以看出J2EE的一些特点,对开发人员而言这些特点相当重要。J2EE的设计思想非常先进,但同时也带来了一定的的复杂度,需要考虑和处理的问题会有相应增加。

JBoss是一个开发源码而且完全免费的应用服务器,其与MySql的搭配可以用“天造一对,地设一双”来形容,对于需要实践锻炼的开发者而言是一个天大的福音,不仅可以免费在上面进行开发,还可以参考其设计思路(如第一节对AutoNumberFactory的设计分析)。JBoss在使用上面透露着二字,那就是“简洁”,但又不失其强大的J2EE引擎功能。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有