- 浏览: 273679 次
- 性别:
- 来自: 新乡
-
文章分类
- 全部博客 (227)
- servciemix (10)
- db (18)
- javaTools (4)
- hibernate (31)
- web (3)
- spring (14)
- design pattern (4)
- java security (3)
- portal (1)
- ejb (6)
- session (2)
- java_lang (21)
- jbpm (29)
- struts (7)
- orgRights (2)
- project manager Jira (7)
- 跨库事务 (2)
- mysql (14)
- ubuntu (7)
- osgi (9)
- maven ant make (4)
- 分布式 高并发 高性能 (5)
- virgo-dm_server (0)
- osgi web (3)
- platform (1)
- smooks (1)
- business (1)
- 职场生涯 (14)
- Java编码格式 (2)
- web服务 (1)
- 计算机使用 (1)
- 健康工作生活的保障,工作中务必抛掉的不良心态 (4)
- 电信-网络监控 (1)
- 多线程-multithread (1)
- 海量数据-高性能 (2)
- Mybatis (1)
- web开发平台研发 (0)
- oracle (0)
- 应用服务器调优 (0)
- web前端 (0)
- servlet-jsp (0)
- tomcat (2)
- newtouch (1)
- portal_liferay (2)
- version control (1)
- apm-impact (2)
- tools (1)
- 研发管理 (1)
- 电商业务 (1)
- 生鲜电商市场调查 (0)
- PBX (0)
- 房东 (0)
最新评论
-
lifuchao:
...
权限问题 -
Branding:
谢谢,受教了,另外,CONN AS SYSDBA,必须是在操作 ...
Oracle密码忘记了怎么办? -
zhuchao_ko:
...
Portal实现原理 -
败类斯文:
不知道改哪里。。。木有见到红色。。表示悟性低了、、
jira error: Neither the JAVA_HOME nor the JRE_HOME environment variable is defin -
c__06:
正文:假如事务我是这样定义的: <tx:method n ...
Spring中Transactional配置
权衡 Apache Geronimo EJB 事务选项,第 1 部分: 容器管理事务
了解 Geronimo 和 OpenEJB 能为您做什么
Jonathan Sagorin (jonathan@javaoncall.com), 自由软件开发人员
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
简介: 本系列分为三部分,将探索 Apache Geronimo 中的 Enterprise Java™Beans (EJB) 容器管理事务和 bean 管理事务。在第 1 部分中,将找出两种事务之间的差异,其中包括了解容器管理事务如何帮助您避免事务逻辑和管理的复杂性,从而使您可以专注于企业 bean 的业务逻辑。您还将学会如何在 Geronimo 应用服务器中实现容器管理事务,以及如何使用 Geronimo、OpenEJB 和 XDoclet 将自己从繁重的 EJB 编码工作中解放出来。
查看本系列更多内容
标记本文!
发布日期: 2006 年 10 月 23 日
级别: 初级
访问情况 434 次浏览
建议: 0 (添加评论)
1 star2 stars3 stars4 stars5 stars 平均分 (共 3 个评分 )
简介
OpenEJB 是为 Apache Geronimo 选定的 EJB 容器实例。虽然 EJB 3.0 目前已经面市,但直到发布 Geronimo 2.0 版,在 Geronimo 接受 Java 1.5 认证时,Geronimo 才支持 EJB。
本系列分为三部分,将使您了解 Geronimo 和 OpenEJB 可以为您提供什么帮助,以及在 EJB 2.1 中现在可以实现的 EJB 事务概念(让您顺利进入 EJB 3.0)。
EJB 框架提供的好处是:可以使用事务,但没有事务 API 编程的痛苦。在实现 EJB 事务时,您有两种选择:
* 告诉 EJB 容器处理所有的硬性事务工作(容器管理的事务)。
* 让企业 bean 处理一部分事务工作(bean 管理的事务)。
在本系列的第 1 部分中,将从事务的概述开始,然后讨论 EJB 2.1 中描述的 EJB 容器管理的事务。最后用一些代码片断结束介绍,这些代码将显示如何在 Geronimo 应用服务器上实现容器管理的事务。
在第 2 部分中,将获得 EJB 2.1 中 bean 管理的事务的概述,并查看一些示例代码实现。
在第 3 部分中,将综合这两种事务,并了解与容器管理的事务和 bean 管理的事务有关的难题和附加特性。
事务—— 概述
什么是事务?为什么它们如此重要?可以考虑一下银行事务这个非常简单的案例:将 100 美元从您的一个活期存款帐户转移到您的储蓄存款帐户。通过进一步的调查,可将这一操作分解为两个更小的操作:
* 银行从您的活期存款帐户减去 100 美元。
* 银行在您的储蓄存款帐户增加 100 美元。
如果银行将活期存款额减少 100 美元,但您的储蓄存款额并没有增加 100 美元,那么您可能会感到有点沮丧。就个人而言,我愿意将两个操作视为一个操作。因此,如果您的储蓄存款帐户从没有增加 100 美元,那么 100 美元也决不应从您的活期存款帐户中减去!
类似地,在应用过程中,很多业务案例都是进行整体确认的 (all-or-nothing approach)。一些大的操作由一个或多个更小的步骤组成。为了完成操作,操作中的所有 步骤都必须完成或不完成,这种行为称为原子 行为。
原子性是事务必须保证的四个特征(或属性)之一。其他三个属性是:
* 一致性
* 隔离性
* 耐久性
这四种属性一起被称为 ACID 属性。
ACID 属性
事务对这些已知 ACID 属性的描述为:
* 事务是原子的。所有操作都被认为是一个工作单元。像前面讨论的那样,是整体确认的。
* 事务是一致的。在执行事务之后,必须将系统维持在一致(或合法)状态下。合法状态的定义取决于系统。根据早先的示例,在执行任何撤消操作之后,银行指示您,将保留您的活期存款帐户为顺差。
* 事务是隔离的。每个事务在同一资源进行操作时与其他事务都是相互隔离的。这可通过数据的锁同步来实现。
* 事务是持久的。资源更新必须避免系统故障,如硬件或网络故障。在分布式系统中,当出现网络故障或数据库崩溃时,恢复过程是必需的。
事务模型
有两种流行的事务模型:flat 事务和 nested 事务。EJB 支持 flat 事务模型。
flat 事务是作为单个工作单元处理的一系列操作。工作单元只有两种结果:要么成功,要么失败。如果事务中的所有步骤都成功完成,则事务获得提交,并且该操作执行的所有持久存储数据更改都将永久化。如果事务中某一步骤失败,则事务将回滚 (roll back),并反转事务中步骤受影响的所有数据。
nested 事务允许事务嵌套在其他事务中。嵌套在其他事务中的事务允许在不影响其父事务的情况下进行回滚。失败的 nested 事务可以继续重试。如果再次失败,则可回滚父事务。
回页首
EJB 事务
EJB 是用于组件开发的一个框架。您开发的 EJB 将运行在 EJB 容器中。此外,EJB 容器为事务带来了一些好处。OpenEJB 是 Geronimo 用来提供事务管理的 EJB 容器。
EJB 架构支持分布式事务。一些需要分布式事务的场景模式范例包括:
* 更新多个数据库的单个事务中的应用。
* 从 Java Message Service (JMS) 目标发送或接收消息并更新一个或多个数据库的单个事务中的应用。
* 通过多个 EJB 服务器来更新多个数据库的单个事务中的应用。
* 在更新多个 EJB 服务器上的多个数据库之前,Java 客户端明确区分事务边界。
事务边界
在实现 EJB 事务时,您将划分事务边界:谁启动事务、谁提交或中止事务,以及什么时候使用事务。这取决于 EJB 容器和服务器提供商提供的事务管理和底层事务通信协议。
有两种划分方案:
* declarative 方案,使用该方案可以将事务实现委托给 EJB 容器。(该方案是本文其余部分的焦点。)
* programmatic 方案,在该方案中,企业 bean 使用自己的代码自己提供提交或中止信息。(本系列的第 2 部分中将介绍此方案。)
在使用 declarative 事务划分时,EJB 容器根据 EJB 部署描述符中由应用程序开发人员声明的指令,在企业 bean 的方法上应用事务边界。这称为容器管理的事务。
在实现 programmatic 划分事务时,应用程序开发人员负责将事务逻辑和界线编入企业 bean 代码中。这称为 bean 管理的事务。
我应该使用哪种事务?
容器管理的事务更加简单并且在代码中不需要实现事务逻辑,无论您的企业 bean 方法是否必须运行在事务中。此外,调用 bean 的 Java 客户端不能滥用您的企业 bean,因为事务始终是有始有终的。
如果想完全控制事务边界,请使用 bean 管理的事务。该方法允许在代码中直接控制提交或控制回滚逻辑发生的地方。
会话 bean 和消息驱动 bean (MDB) 可以使用 bean 管理的事务或容器管理的事务,但是实体 bean 必须始终使用容器管理的事务。实体 bean 使用 bean 管理的持久性是不合法的。
回页首
容器管理的事务
事务划分边界是通过指令或事务属性提供的。这些属性描述了企业 bean 是如何参与到事务中的。您可以对每个 bean 指定不同的事务属性而不必考虑 bean 的数目。您可以为 bean 的个别或所有方法指定属性。方法的属性是优先于 bean 的。
回页首
会话 bean 和实体 bean 的事务属性
会话 bean 和实体 bean 可能的属性值包括:
* Required —— bean 必须始终运行在事务中。如果客户端已经启动一个事务,则 bean 将加入到事务中。如果客户端还没有启动事务,那么 EJB 容器将启动一个新事务。当需要 bean 始终运行在事务中时,请使用该属性。
* RequiresNew —— bean 始终启动一个新的事务。如果客户端已经启动一个事务,则挂起现有事务,直到新事务已提交或中止。在新事务完成之后,现有事务将继续。当需要 bean 作为一个单独的工作单元运行并展示所有的 ACID 属性时,请使用该属性。
* Supports —— 如果客户端启动一个事务,则 bean 将加入到事务中。但是,如果事务不存在,EJB 容器不会启动一个新事务。要在企业 bean 上执行非任务关键型操作时,请使用该属性。
* Mandatory —— 在调用 bean 时客户端必须启动一个事务。这不会创建一个新的事务。在调用 bean 时,如果没有事务已经启动,则将抛出一个异常。当 bean 是某一较大系统的一部分时,请使用该属性。通常可能由第三方负责启动事务。对用户而言,这是一个安全选项,因为它可以确保 bean 将成为事务的一部分。
* NotSupported —— 在事务中不能调用 bean。如果客户端已经启动一个事务,则挂起现有事务,直到 bean 的方法完成。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新事务。在不需要 bean 展示任何 ACID 属性(比如类似报表的非系统关键型操作)时,请使用该属性。
* Never —— 如果客户端启动一个事务,则 bean 将抛出一个异常。在您可能永远都不想让您的 bean 参与到事务中的情况下,请使用该属性。
回页首
消息驱动 bean 的事务属性
只有两种消息驱动 bean 消息监听器方法使用的事务属性:
* NotSupported —— bean 不能参与到事务中。如果客户端启动一个事务,那么现有事务将挂起,直到 bean 的方法完成为止。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新的事务。
* Required —— bean 必须始终运行在事务中。如果客户端已经启动事务,则 bean 将加入到事务中。如果客户端没有启动事务,则 EJB 容器将启动一个新事务。
在为企业 bean 方法确定正确事务属性之后,就可以配置 EJB 部署描述符了。
回页首
配置 EJB 部署描述符
对于每个企业 bean,都要在部署描述符中配置事务的下列两个部分:
* 在 EJB 部署描述符中使用 <transaction-type> 元素指定 bean 使用的是容器管理的事务还是 bean 管理的事务。可能的值是 container 或 bean。由于实体 bean 必须使用容器管理的事务,这只对会话 bean 和消息驱动 bean 是必需的。
* 对于容器管理的事务,您可以为企业 bean 的方法随意指定事务属性。在 EJB 部署描述符中的 <container-transaction> 部分指定它。清单 1 中显示了每种方法的通用格式。
清单 1. 每种方法的通用格式
<method>
<ejb-name>EJBNAME</ejb-name>
<method-name>METHODNAME</method-name>
<trans-attribute>TRANSATTRIBUTE</trans-attribute>
</method>
TRANSATTRIBUTE 可能的值有:
* NotSupported
* Required
* Supports
* RequiresNew
* Mandatory
* Never
也可以对企业 bean 的所有方法指定事务属性。对 <method-name> 属性使用 *。
清单 2 显示了为容器管理的企业 bean 指定事务属性的示例。除了为 updateClaimNumber 方法分配 Mandatory 属性以外,ClaimRecord企业 bean 为所有方法都分配了 Required 属性。Coverage bean 对所有方法指派 RequiresNew 属性。
清单 2. ejb 部署描述符文件中的事务属性
<ejb-jar>
...
<assembly-descriptor>
...
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>updateClaimNumber</methodname>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Coverage</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
...
</assembly-descriptor>
...
</ejb-jar>
回页首
Geronimo 配置
既然您明白了在 EJB 部署描述符中指定事务属性的通用格式,那么可以考虑一下如何在 Geronimo 中使用 OpenEJB 实现这一点。在 Geronimo 中开发 EJB 时,可以通过使用 XDoclet 生成所需的大部分单调的 EJB 编程工件 (artifact) 来节省时间。作为这些工件的一部分,XDoclet 生成了 EJB 部署描述符。
作为正常开发过程的一部分,可以在企业 bean 中指定 JavaDoc-style 标识标签。通过在企业 bean 中声明标识标签,XDoclet 可生成 ejbjar.xml。这包括属性定义的任何事务。您不用自己直接编译部署描述符 (ejb-jar.xml)。
在 XDoclet 中使用 @ejb.transaction 标识指定事务属性。在需要使用它时,可以在企业 bean 的方法之上声明它。
XDoclet 配置示例和 ejbjar.xml 生成
下面的代码片断显示了一个简洁的会话 bean 和实体 bean 示例,然后由 XDoclet 生成最终的 ejbjar.xml 文件。首先,清单 3 显示了一个名为 SampleSession 的无状态会话 bean。只需要注意与事务相关的部分即可(用粗体显示)。
清单 3. 会话 bean
package org.my.package.ejb;
/**
* Sample session bean.
* Declare all my XDoclet tags here
* ...
* ...
* @ejb.bean name="SampleSession"
* type="Stateless"
* local-jndi-name="java:comp/env/ejb/SampleSessionLocal"
* jndi-name="org.my.package.ejb/SampleSessionLocal/Home"
* view-type="both"
*
* @ejb.permission unchecked="true"
*
* @ejb.interface generate="local,remote"
* remote-class="org.my.package.ejb.SampleSession"
* local-class=" org.my.package.ejb. SampleSession Local"
* @ejb.home generate="local, remote"
* remote-class="org.my.package.ejb.SampleSession Home"
* local-class="org.my.package.SampleSession LocalHome"
* @ejb.util generate="physical"
* ...
* ...
*/
public abstract class SampleSessionBean implements javax.ejb.SessionBean {
/**
* Perform a business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void doSomething(java.lang.String someParam)) {
...
}
/*
* Perform another business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="RequiresNew"
*/
public void doSomethingElse(java.lang.String someParam)) {
...
}
/**
* @ejb.create-method
* @ejb.transaction type="Required"
*/
public void ejbCreate ()
throws javax.ejb.CreateException
{
}
public void ejbPostCreate ()
throws javax.ejb.CreateException
{
}
protected javax.ejb.SessionContext _ctx = null;
public void setSessionContext( javax.ejb.SessionContext ctx )
{
_ctx = ctx;
}
protected javax.ejb.SessionContext getSessionContext()
{
return _ctx;
}
}
同样的标识 @ejb.transaction 被用来指定该实体 bean 的事务属性。清单 4 显示如何指定实体 bean 的事务属性。同样,只需要注意粗体的标识即可。
清单 4. 实体 bean
package org.my.package.ejb;
/**
*
* @ejb.bean
* type="CMP"
* cmp-version="2.x"
* name="ClaimEntry"
* local-jndi-name="org.my.package.ejb/ClaimLocalHome"
* view-type="local"
* primkey-field="name"
*
*
* @xx-ejb.data-object
* container="true"
* setdata="true"
* generate="true"
*
* @ejb.value-object
*
* @ejb.transaction type="Required"
* @ejb.permission unchecked="true"
* @struts.form include-all="true"
*
* @web.ejb-local-ref
* name="ejb/ClaimLocal"
* type="Entity"
* home="org.my.package.ejb.ClaimLocalHome"
* local="org.my.package.ejb.ClaimLocal"
* link="PhoneBookEntry"
*
* @ejb.persistence table-name="Claim"
*
*/
public abstract class ClaimBean
implements javax.ejb.EntityBean
{
* ... EJB entity bean implementation here
}
在编译过程中执行 XDoclet 时,生成了 ejb-jar.xml。清单5 显示了文件的事务相关部分。注意粗体显示的 <transaction-type> 和 <trans-attribute> 元素。
清单 5. 生成的 ejb-jar.xml 片断
...
<ejb-jar >
<description><![CDATA[No Description.]]></description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<!-- Session Beans -->
<session >
<description><![CDATA[Sample session
bean.]]></description>
<ejb-name>SampleSession</ejb-name>
<home>org.my.package.ejb.SampleSessionHome</home>
<remote>org.my.package.ejb.SampleSession</remote>
<local-home>org.my.package.ejb.SampleSessionLocalHome
</local-home>
<local>org.my.package.ejb.SampleSessionLocal</local>
<ejb-class>org.my.package.ejb.SampleSessionSessionSession
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
...
<!-- Entity Beans -->
<entity >
<description><![CDATA[]]></description>
<ejb-name>Claim</ejb-name>
<local-home>
org.my.package.ejb.ClaimLocalHome</local-home>
<local>org.my.package.ejb.ClaimLocal</local>
<ejb-class>org.my.package.ejb.ClaimCMP</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>Claim</abstract-schema-name>
...
</entity>
...
<container-transaction >
<method >
<ejb-name>Claim</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
...
</ejb-jar>
事务同步
容器管理的事务允许 EJB 容器指定事务边界,这可以简化您的工作。然而,当事务中止时,可能需要执行一些 bean 状态的恢复工作。对于无状态会话 bean,可能抛出一个简单的异常。有状态会话 bean 表示了对话状态(或商业流程),这可能会跨越几个 bean 方法调用。
如果要求有状态会话 bean 获得事务边界状态事件通知,则需要编写企业 bean 代码来实现可选的 javax.ejb.SessionSynchronization 接口。您必须实现定义在接口上的下列方法:
* afterBegin() —— 在新事务启动之后但在调用业务方法之前通知会话 bean。在事务提交之前,bean 实例可以做任何它所需要的数据库读取操作。在缓冲事务所需要的数据时,这很有用。
* beforeCompletion() —— 在业务方法完成之后但是在事务提交之前通知会话 bean。如果有任何缓冲数据,可以将其更新到数据库中。bean 还可以在会话上下文中通过调用 setRollBackOnly() 执行事务的手动回滚。
* afterCompletion(boolean committed) —— 在事务提交之后通知会话 bean。提交的布尔值指出是提交事务还是中止事务。如果该值为 true,则事务成功获得提交。如果该值为 false,则事务中止。因此,bean 的对话状态/实例变量可以被恢复或重新设置。
避免使用的方法
既然 EJB 容器是负责控制事务边界,那么您不应该调用任何可能干涉容器边界划分的方法。如果您正在实现容器管理的事务,请确保企业 bean 方法不会调用下列方法:
* java.sql.Connection 的 commit、setAutoCommit 和 rollback 方法
* javax.ejb.EJBContext 的 getUserTransaction 方法
* javax.transaction.UserTransaction 的任何方法
回滚
在某些情况下您可能需要明确中止事务。有两种回滚容器管理的事务的方式:
* 让容器自动回滚事务。如果有任何企业 bean 抛出的运行时异常,就会发生这种回滚。
* 调用 EJBContext 接口的 setRollBackOnly() 方法。在发生回滚时,允许您进行控制。或许由于一些有效性验证失败或存在数据完整性问题,您可能需要回滚整个事务并抛出一个应用程序异常。应用程序异常不会自动导致容器回滚一个异常。
回页首
结束语
在本系列的第 1 部分,简单介绍了事务和 EJB 事务的两个选择。您可以看到容器管理的事务如何使您专注于您的企业 bean 的业务逻辑,而将事务逻辑和管理的复杂性留给 EJB 容器。
使用容器管理的事务,您只需要关心企业 bean 如何参与到事务中,并通过 EJB 部署描述符的简单配置来实现这一点。Geronimo 应用服务器、OpenEJB 和 XDoclet 将帮助您简化如何指定容器管理的设置,并将您从繁重的 EJB 工件编码工作中解放出来。
继续关注本系列的第 2 部分,您将了解 bean 管理的事务,在第 3 部分中,我们会将二者综合使用。
参考资料
学习
* 阅读 “利用 Geronimo 深入 EJB Web 应用程序”(developerWorks,2005 年 7 月),了解如何在 Geronimo 中使用 EJB。
* 通过 “在 Apache Geronimo 上部署 J2EE 应用程序”(developerWorks,2006 年 1 月)了解如何部署 JavaServer Pages (JSP)、servlet 和 Apache Geronimo 上的不同 EJB。
* 查看 Dale Green 的文章 “Enterprise Beans”,获得关于 Geronimo 中部署描述符的更多信息。
* 阅读更多有关 Sun 公司的 EJB 规范 的信息。
* 学习有关 XDoclet 的更多信息。
* 阅读 Nicholas Chase 与 David Blevins(OpenEJB 的共同创始人)的访谈 “Geronimo 叛逆者:OpenEJB 和 Apache Geronimo 的 EJB 实现”(developerWorks,2006 年 5 月),了解 OpenEJB 是如何被选为 Geronimo 的 EJB 实现的。
* 加入 Apache Geronimo 网站的 邮件列表。
* 阅读 “构建更佳的 J2EE 服务器,开源之路”(developerWorks,2005 年 5 月),获得有关 Geronimo 背后的开发过程的重要信息,包括其 JSR-88 支持。
* 查看 developerWorks Apache Geronimo 项目专区,获得有助于您现在使用 Geronimo 开始开发的文章、教程和其他参考资料。
* 在 developerWorks 的 现在开始学习 Apache Geronimo 部分查找对于初学者和有经验的用户有用的参考资料。
* 查看提供的 IBM Support for Apache Geronimo,它会使您在开发 Geionimo 应用程序时得到世界级的 IBM 支持。
* 访问 developerWorks 开放源码专区,从那里可以获得大量的 how-to 信息、工具和项目更新,这些有助于您使用开放源码技术进行开发,并将这些技术 IBM 产品结合使用。
* 在 “developerWorks 开放源码专区” 上浏览所有可获得的 Apache 文章 和 免费 Apache 教程。
* 浏览 Safari bookstore 上的有关书籍和其他技术主题。
获得产品和技术
* 下载 Apache Geronimo, Version 1.0。
* 使用 IBM 试用软件 改进您的下一个开放源码开发项目,可以通过下载或从 DVD 中获得这些软件。
* 下载 IBM WebSphere® Application Server Community Edition V1.0 的免费副本 —— 它是一个轻量级的 J2EE 应用服务器,使用 Apache Geronimo 开放源码技术构建而成,用于帮助您加速开发和部署工作。
讨论
* 参与论坛讨论。
* 与 Apache Geronimo blog 上的 Geronimo 开发保持同步。
* 通过参与 developerWorks blogs 加入 developerWorks 社区。
关于作者
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
了解 Geronimo 和 OpenEJB 能为您做什么
Jonathan Sagorin (jonathan@javaoncall.com), 自由软件开发人员
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
简介: 本系列分为三部分,将探索 Apache Geronimo 中的 Enterprise Java™Beans (EJB) 容器管理事务和 bean 管理事务。在第 1 部分中,将找出两种事务之间的差异,其中包括了解容器管理事务如何帮助您避免事务逻辑和管理的复杂性,从而使您可以专注于企业 bean 的业务逻辑。您还将学会如何在 Geronimo 应用服务器中实现容器管理事务,以及如何使用 Geronimo、OpenEJB 和 XDoclet 将自己从繁重的 EJB 编码工作中解放出来。
查看本系列更多内容
标记本文!
发布日期: 2006 年 10 月 23 日
级别: 初级
访问情况 434 次浏览
建议: 0 (添加评论)
1 star2 stars3 stars4 stars5 stars 平均分 (共 3 个评分 )
简介
OpenEJB 是为 Apache Geronimo 选定的 EJB 容器实例。虽然 EJB 3.0 目前已经面市,但直到发布 Geronimo 2.0 版,在 Geronimo 接受 Java 1.5 认证时,Geronimo 才支持 EJB。
本系列分为三部分,将使您了解 Geronimo 和 OpenEJB 可以为您提供什么帮助,以及在 EJB 2.1 中现在可以实现的 EJB 事务概念(让您顺利进入 EJB 3.0)。
EJB 框架提供的好处是:可以使用事务,但没有事务 API 编程的痛苦。在实现 EJB 事务时,您有两种选择:
* 告诉 EJB 容器处理所有的硬性事务工作(容器管理的事务)。
* 让企业 bean 处理一部分事务工作(bean 管理的事务)。
在本系列的第 1 部分中,将从事务的概述开始,然后讨论 EJB 2.1 中描述的 EJB 容器管理的事务。最后用一些代码片断结束介绍,这些代码将显示如何在 Geronimo 应用服务器上实现容器管理的事务。
在第 2 部分中,将获得 EJB 2.1 中 bean 管理的事务的概述,并查看一些示例代码实现。
在第 3 部分中,将综合这两种事务,并了解与容器管理的事务和 bean 管理的事务有关的难题和附加特性。
事务—— 概述
什么是事务?为什么它们如此重要?可以考虑一下银行事务这个非常简单的案例:将 100 美元从您的一个活期存款帐户转移到您的储蓄存款帐户。通过进一步的调查,可将这一操作分解为两个更小的操作:
* 银行从您的活期存款帐户减去 100 美元。
* 银行在您的储蓄存款帐户增加 100 美元。
如果银行将活期存款额减少 100 美元,但您的储蓄存款额并没有增加 100 美元,那么您可能会感到有点沮丧。就个人而言,我愿意将两个操作视为一个操作。因此,如果您的储蓄存款帐户从没有增加 100 美元,那么 100 美元也决不应从您的活期存款帐户中减去!
类似地,在应用过程中,很多业务案例都是进行整体确认的 (all-or-nothing approach)。一些大的操作由一个或多个更小的步骤组成。为了完成操作,操作中的所有 步骤都必须完成或不完成,这种行为称为原子 行为。
原子性是事务必须保证的四个特征(或属性)之一。其他三个属性是:
* 一致性
* 隔离性
* 耐久性
这四种属性一起被称为 ACID 属性。
ACID 属性
事务对这些已知 ACID 属性的描述为:
* 事务是原子的。所有操作都被认为是一个工作单元。像前面讨论的那样,是整体确认的。
* 事务是一致的。在执行事务之后,必须将系统维持在一致(或合法)状态下。合法状态的定义取决于系统。根据早先的示例,在执行任何撤消操作之后,银行指示您,将保留您的活期存款帐户为顺差。
* 事务是隔离的。每个事务在同一资源进行操作时与其他事务都是相互隔离的。这可通过数据的锁同步来实现。
* 事务是持久的。资源更新必须避免系统故障,如硬件或网络故障。在分布式系统中,当出现网络故障或数据库崩溃时,恢复过程是必需的。
事务模型
有两种流行的事务模型:flat 事务和 nested 事务。EJB 支持 flat 事务模型。
flat 事务是作为单个工作单元处理的一系列操作。工作单元只有两种结果:要么成功,要么失败。如果事务中的所有步骤都成功完成,则事务获得提交,并且该操作执行的所有持久存储数据更改都将永久化。如果事务中某一步骤失败,则事务将回滚 (roll back),并反转事务中步骤受影响的所有数据。
nested 事务允许事务嵌套在其他事务中。嵌套在其他事务中的事务允许在不影响其父事务的情况下进行回滚。失败的 nested 事务可以继续重试。如果再次失败,则可回滚父事务。
回页首
EJB 事务
EJB 是用于组件开发的一个框架。您开发的 EJB 将运行在 EJB 容器中。此外,EJB 容器为事务带来了一些好处。OpenEJB 是 Geronimo 用来提供事务管理的 EJB 容器。
EJB 架构支持分布式事务。一些需要分布式事务的场景模式范例包括:
* 更新多个数据库的单个事务中的应用。
* 从 Java Message Service (JMS) 目标发送或接收消息并更新一个或多个数据库的单个事务中的应用。
* 通过多个 EJB 服务器来更新多个数据库的单个事务中的应用。
* 在更新多个 EJB 服务器上的多个数据库之前,Java 客户端明确区分事务边界。
事务边界
在实现 EJB 事务时,您将划分事务边界:谁启动事务、谁提交或中止事务,以及什么时候使用事务。这取决于 EJB 容器和服务器提供商提供的事务管理和底层事务通信协议。
有两种划分方案:
* declarative 方案,使用该方案可以将事务实现委托给 EJB 容器。(该方案是本文其余部分的焦点。)
* programmatic 方案,在该方案中,企业 bean 使用自己的代码自己提供提交或中止信息。(本系列的第 2 部分中将介绍此方案。)
在使用 declarative 事务划分时,EJB 容器根据 EJB 部署描述符中由应用程序开发人员声明的指令,在企业 bean 的方法上应用事务边界。这称为容器管理的事务。
在实现 programmatic 划分事务时,应用程序开发人员负责将事务逻辑和界线编入企业 bean 代码中。这称为 bean 管理的事务。
我应该使用哪种事务?
容器管理的事务更加简单并且在代码中不需要实现事务逻辑,无论您的企业 bean 方法是否必须运行在事务中。此外,调用 bean 的 Java 客户端不能滥用您的企业 bean,因为事务始终是有始有终的。
如果想完全控制事务边界,请使用 bean 管理的事务。该方法允许在代码中直接控制提交或控制回滚逻辑发生的地方。
会话 bean 和消息驱动 bean (MDB) 可以使用 bean 管理的事务或容器管理的事务,但是实体 bean 必须始终使用容器管理的事务。实体 bean 使用 bean 管理的持久性是不合法的。
回页首
容器管理的事务
事务划分边界是通过指令或事务属性提供的。这些属性描述了企业 bean 是如何参与到事务中的。您可以对每个 bean 指定不同的事务属性而不必考虑 bean 的数目。您可以为 bean 的个别或所有方法指定属性。方法的属性是优先于 bean 的。
回页首
会话 bean 和实体 bean 的事务属性
会话 bean 和实体 bean 可能的属性值包括:
* Required —— bean 必须始终运行在事务中。如果客户端已经启动一个事务,则 bean 将加入到事务中。如果客户端还没有启动事务,那么 EJB 容器将启动一个新事务。当需要 bean 始终运行在事务中时,请使用该属性。
* RequiresNew —— bean 始终启动一个新的事务。如果客户端已经启动一个事务,则挂起现有事务,直到新事务已提交或中止。在新事务完成之后,现有事务将继续。当需要 bean 作为一个单独的工作单元运行并展示所有的 ACID 属性时,请使用该属性。
* Supports —— 如果客户端启动一个事务,则 bean 将加入到事务中。但是,如果事务不存在,EJB 容器不会启动一个新事务。要在企业 bean 上执行非任务关键型操作时,请使用该属性。
* Mandatory —— 在调用 bean 时客户端必须启动一个事务。这不会创建一个新的事务。在调用 bean 时,如果没有事务已经启动,则将抛出一个异常。当 bean 是某一较大系统的一部分时,请使用该属性。通常可能由第三方负责启动事务。对用户而言,这是一个安全选项,因为它可以确保 bean 将成为事务的一部分。
* NotSupported —— 在事务中不能调用 bean。如果客户端已经启动一个事务,则挂起现有事务,直到 bean 的方法完成。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新事务。在不需要 bean 展示任何 ACID 属性(比如类似报表的非系统关键型操作)时,请使用该属性。
* Never —— 如果客户端启动一个事务,则 bean 将抛出一个异常。在您可能永远都不想让您的 bean 参与到事务中的情况下,请使用该属性。
回页首
消息驱动 bean 的事务属性
只有两种消息驱动 bean 消息监听器方法使用的事务属性:
* NotSupported —— bean 不能参与到事务中。如果客户端启动一个事务,那么现有事务将挂起,直到 bean 的方法完成为止。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新的事务。
* Required —— bean 必须始终运行在事务中。如果客户端已经启动事务,则 bean 将加入到事务中。如果客户端没有启动事务,则 EJB 容器将启动一个新事务。
在为企业 bean 方法确定正确事务属性之后,就可以配置 EJB 部署描述符了。
回页首
配置 EJB 部署描述符
对于每个企业 bean,都要在部署描述符中配置事务的下列两个部分:
* 在 EJB 部署描述符中使用 <transaction-type> 元素指定 bean 使用的是容器管理的事务还是 bean 管理的事务。可能的值是 container 或 bean。由于实体 bean 必须使用容器管理的事务,这只对会话 bean 和消息驱动 bean 是必需的。
* 对于容器管理的事务,您可以为企业 bean 的方法随意指定事务属性。在 EJB 部署描述符中的 <container-transaction> 部分指定它。清单 1 中显示了每种方法的通用格式。
清单 1. 每种方法的通用格式
<method>
<ejb-name>EJBNAME</ejb-name>
<method-name>METHODNAME</method-name>
<trans-attribute>TRANSATTRIBUTE</trans-attribute>
</method>
TRANSATTRIBUTE 可能的值有:
* NotSupported
* Required
* Supports
* RequiresNew
* Mandatory
* Never
也可以对企业 bean 的所有方法指定事务属性。对 <method-name> 属性使用 *。
清单 2 显示了为容器管理的企业 bean 指定事务属性的示例。除了为 updateClaimNumber 方法分配 Mandatory 属性以外,ClaimRecord企业 bean 为所有方法都分配了 Required 属性。Coverage bean 对所有方法指派 RequiresNew 属性。
清单 2. ejb 部署描述符文件中的事务属性
<ejb-jar>
...
<assembly-descriptor>
...
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>updateClaimNumber</methodname>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Coverage</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
...
</assembly-descriptor>
...
</ejb-jar>
回页首
Geronimo 配置
既然您明白了在 EJB 部署描述符中指定事务属性的通用格式,那么可以考虑一下如何在 Geronimo 中使用 OpenEJB 实现这一点。在 Geronimo 中开发 EJB 时,可以通过使用 XDoclet 生成所需的大部分单调的 EJB 编程工件 (artifact) 来节省时间。作为这些工件的一部分,XDoclet 生成了 EJB 部署描述符。
作为正常开发过程的一部分,可以在企业 bean 中指定 JavaDoc-style 标识标签。通过在企业 bean 中声明标识标签,XDoclet 可生成 ejbjar.xml。这包括属性定义的任何事务。您不用自己直接编译部署描述符 (ejb-jar.xml)。
在 XDoclet 中使用 @ejb.transaction 标识指定事务属性。在需要使用它时,可以在企业 bean 的方法之上声明它。
XDoclet 配置示例和 ejbjar.xml 生成
下面的代码片断显示了一个简洁的会话 bean 和实体 bean 示例,然后由 XDoclet 生成最终的 ejbjar.xml 文件。首先,清单 3 显示了一个名为 SampleSession 的无状态会话 bean。只需要注意与事务相关的部分即可(用粗体显示)。
清单 3. 会话 bean
package org.my.package.ejb;
/**
* Sample session bean.
* Declare all my XDoclet tags here
* ...
* ...
* @ejb.bean name="SampleSession"
* type="Stateless"
* local-jndi-name="java:comp/env/ejb/SampleSessionLocal"
* jndi-name="org.my.package.ejb/SampleSessionLocal/Home"
* view-type="both"
*
* @ejb.permission unchecked="true"
*
* @ejb.interface generate="local,remote"
* remote-class="org.my.package.ejb.SampleSession"
* local-class=" org.my.package.ejb. SampleSession Local"
* @ejb.home generate="local, remote"
* remote-class="org.my.package.ejb.SampleSession Home"
* local-class="org.my.package.SampleSession LocalHome"
* @ejb.util generate="physical"
* ...
* ...
*/
public abstract class SampleSessionBean implements javax.ejb.SessionBean {
/**
* Perform a business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void doSomething(java.lang.String someParam)) {
...
}
/*
* Perform another business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="RequiresNew"
*/
public void doSomethingElse(java.lang.String someParam)) {
...
}
/**
* @ejb.create-method
* @ejb.transaction type="Required"
*/
public void ejbCreate ()
throws javax.ejb.CreateException
{
}
public void ejbPostCreate ()
throws javax.ejb.CreateException
{
}
protected javax.ejb.SessionContext _ctx = null;
public void setSessionContext( javax.ejb.SessionContext ctx )
{
_ctx = ctx;
}
protected javax.ejb.SessionContext getSessionContext()
{
return _ctx;
}
}
同样的标识 @ejb.transaction 被用来指定该实体 bean 的事务属性。清单 4 显示如何指定实体 bean 的事务属性。同样,只需要注意粗体的标识即可。
清单 4. 实体 bean
package org.my.package.ejb;
/**
*
* @ejb.bean
* type="CMP"
* cmp-version="2.x"
* name="ClaimEntry"
* local-jndi-name="org.my.package.ejb/ClaimLocalHome"
* view-type="local"
* primkey-field="name"
*
*
* @xx-ejb.data-object
* container="true"
* setdata="true"
* generate="true"
*
* @ejb.value-object
*
* @ejb.transaction type="Required"
* @ejb.permission unchecked="true"
* @struts.form include-all="true"
*
* @web.ejb-local-ref
* name="ejb/ClaimLocal"
* type="Entity"
* home="org.my.package.ejb.ClaimLocalHome"
* local="org.my.package.ejb.ClaimLocal"
* link="PhoneBookEntry"
*
* @ejb.persistence table-name="Claim"
*
*/
public abstract class ClaimBean
implements javax.ejb.EntityBean
{
* ... EJB entity bean implementation here
}
在编译过程中执行 XDoclet 时,生成了 ejb-jar.xml。清单5 显示了文件的事务相关部分。注意粗体显示的 <transaction-type> 和 <trans-attribute> 元素。
清单 5. 生成的 ejb-jar.xml 片断
...
<ejb-jar >
<description><![CDATA[No Description.]]></description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<!-- Session Beans -->
<session >
<description><![CDATA[Sample session
bean.]]></description>
<ejb-name>SampleSession</ejb-name>
<home>org.my.package.ejb.SampleSessionHome</home>
<remote>org.my.package.ejb.SampleSession</remote>
<local-home>org.my.package.ejb.SampleSessionLocalHome
</local-home>
<local>org.my.package.ejb.SampleSessionLocal</local>
<ejb-class>org.my.package.ejb.SampleSessionSessionSession
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
...
<!-- Entity Beans -->
<entity >
<description><![CDATA[]]></description>
<ejb-name>Claim</ejb-name>
<local-home>
org.my.package.ejb.ClaimLocalHome</local-home>
<local>org.my.package.ejb.ClaimLocal</local>
<ejb-class>org.my.package.ejb.ClaimCMP</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>Claim</abstract-schema-name>
...
</entity>
...
<container-transaction >
<method >
<ejb-name>Claim</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
...
</ejb-jar>
事务同步
容器管理的事务允许 EJB 容器指定事务边界,这可以简化您的工作。然而,当事务中止时,可能需要执行一些 bean 状态的恢复工作。对于无状态会话 bean,可能抛出一个简单的异常。有状态会话 bean 表示了对话状态(或商业流程),这可能会跨越几个 bean 方法调用。
如果要求有状态会话 bean 获得事务边界状态事件通知,则需要编写企业 bean 代码来实现可选的 javax.ejb.SessionSynchronization 接口。您必须实现定义在接口上的下列方法:
* afterBegin() —— 在新事务启动之后但在调用业务方法之前通知会话 bean。在事务提交之前,bean 实例可以做任何它所需要的数据库读取操作。在缓冲事务所需要的数据时,这很有用。
* beforeCompletion() —— 在业务方法完成之后但是在事务提交之前通知会话 bean。如果有任何缓冲数据,可以将其更新到数据库中。bean 还可以在会话上下文中通过调用 setRollBackOnly() 执行事务的手动回滚。
* afterCompletion(boolean committed) —— 在事务提交之后通知会话 bean。提交的布尔值指出是提交事务还是中止事务。如果该值为 true,则事务成功获得提交。如果该值为 false,则事务中止。因此,bean 的对话状态/实例变量可以被恢复或重新设置。
避免使用的方法
既然 EJB 容器是负责控制事务边界,那么您不应该调用任何可能干涉容器边界划分的方法。如果您正在实现容器管理的事务,请确保企业 bean 方法不会调用下列方法:
* java.sql.Connection 的 commit、setAutoCommit 和 rollback 方法
* javax.ejb.EJBContext 的 getUserTransaction 方法
* javax.transaction.UserTransaction 的任何方法
回滚
在某些情况下您可能需要明确中止事务。有两种回滚容器管理的事务的方式:
* 让容器自动回滚事务。如果有任何企业 bean 抛出的运行时异常,就会发生这种回滚。
* 调用 EJBContext 接口的 setRollBackOnly() 方法。在发生回滚时,允许您进行控制。或许由于一些有效性验证失败或存在数据完整性问题,您可能需要回滚整个事务并抛出一个应用程序异常。应用程序异常不会自动导致容器回滚一个异常。
回页首
结束语
在本系列的第 1 部分,简单介绍了事务和 EJB 事务的两个选择。您可以看到容器管理的事务如何使您专注于您的企业 bean 的业务逻辑,而将事务逻辑和管理的复杂性留给 EJB 容器。
使用容器管理的事务,您只需要关心企业 bean 如何参与到事务中,并通过 EJB 部署描述符的简单配置来实现这一点。Geronimo 应用服务器、OpenEJB 和 XDoclet 将帮助您简化如何指定容器管理的设置,并将您从繁重的 EJB 工件编码工作中解放出来。
继续关注本系列的第 2 部分,您将了解 bean 管理的事务,在第 3 部分中,我们会将二者综合使用。
参考资料
学习
* 阅读 “利用 Geronimo 深入 EJB Web 应用程序”(developerWorks,2005 年 7 月),了解如何在 Geronimo 中使用 EJB。
* 通过 “在 Apache Geronimo 上部署 J2EE 应用程序”(developerWorks,2006 年 1 月)了解如何部署 JavaServer Pages (JSP)、servlet 和 Apache Geronimo 上的不同 EJB。
* 查看 Dale Green 的文章 “Enterprise Beans”,获得关于 Geronimo 中部署描述符的更多信息。
* 阅读更多有关 Sun 公司的 EJB 规范 的信息。
* 学习有关 XDoclet 的更多信息。
* 阅读 Nicholas Chase 与 David Blevins(OpenEJB 的共同创始人)的访谈 “Geronimo 叛逆者:OpenEJB 和 Apache Geronimo 的 EJB 实现”(developerWorks,2006 年 5 月),了解 OpenEJB 是如何被选为 Geronimo 的 EJB 实现的。
* 加入 Apache Geronimo 网站的 邮件列表。
* 阅读 “构建更佳的 J2EE 服务器,开源之路”(developerWorks,2005 年 5 月),获得有关 Geronimo 背后的开发过程的重要信息,包括其 JSR-88 支持。
* 查看 developerWorks Apache Geronimo 项目专区,获得有助于您现在使用 Geronimo 开始开发的文章、教程和其他参考资料。
* 在 developerWorks 的 现在开始学习 Apache Geronimo 部分查找对于初学者和有经验的用户有用的参考资料。
* 查看提供的 IBM Support for Apache Geronimo,它会使您在开发 Geionimo 应用程序时得到世界级的 IBM 支持。
* 访问 developerWorks 开放源码专区,从那里可以获得大量的 how-to 信息、工具和项目更新,这些有助于您使用开放源码技术进行开发,并将这些技术 IBM 产品结合使用。
* 在 “developerWorks 开放源码专区” 上浏览所有可获得的 Apache 文章 和 免费 Apache 教程。
* 浏览 Safari bookstore 上的有关书籍和其他技术主题。
获得产品和技术
* 下载 Apache Geronimo, Version 1.0。
* 使用 IBM 试用软件 改进您的下一个开放源码开发项目,可以通过下载或从 DVD 中获得这些软件。
* 下载 IBM WebSphere® Application Server Community Edition V1.0 的免费副本 —— 它是一个轻量级的 J2EE 应用服务器,使用 Apache Geronimo 开放源码技术构建而成,用于帮助您加速开发和部署工作。
讨论
* 参与论坛讨论。
* 与 Apache Geronimo blog 上的 Geronimo 开发保持同步。
* 通过参与 developerWorks blogs 加入 developerWorks 社区。
关于作者
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
相关推荐
在日常的开发和使用中,我们经常需要借助各种小工具来提高工作效率,例如快速启动常用的应用程序、管理文件等。一个简单但功能强大的集成工具箱可以帮助用户快速访问、启动并管理程序。今天,我们将以Python为基础,结合Tkinter和Win32API,开发一个类似Windows快捷方式的工具箱应用,能够让你轻松集成各种常用程序并一键启动
django自建博客app
《基于YOLOv8的智慧校园实验室高压灭菌锅安全联锁系统》(包含源码、可视化界面、完整数据集、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计
用于hifi测序数据的基因组组装程序
Microsoft Access 2010 数据库引擎可再发行程序包AccessDatabaseEngine-X64解压后的文件AceRedist
从大模型、智能体到复杂AI应用系统的构建——以产业大脑为例
自然语言处理之TF-IDF算法与TextRank算法的缠绵_textrank,tf-idf和两者的组合-CSDN博客.html
内容概要:2023版《科学智能 (AI4S)全球发展观察与展望》阐述了AI for Science(AI4S)在全球范围内的最新进展及其对科学和工业的深远影响。文章首先回顾了AI4S在过去一年中的快速发展,特别是在药物研发、材料科学、地质学、污染治理等多个领域的应用实例。AI4S通过结合深度学习、机器学习和其他AI技术,加速了从基础研究到实际应用的转化过程。例如,在药物研发中,AI4S帮助科学家克服了“反摩尔定律”的挑战,提高了新药研发的成功率;在材料科学中,AI4S实现了复杂材料的高效模拟,如人造钻石、石墨烯、碳纳米管等;在地质学中,AI4S通过模拟地球内部结构和物理过程,为地震学研究提供了新视角。此外,文章还探讨了大语言模型(LLMs)与科学方法的结合,指出LLMs不仅能辅助科学研究,还能生成新的科学假设并进行逻辑推理。 适合人群:具备一定科研背景或对AI技术感兴趣的科研人员、工程师、政策制定者及高校师生。
这个数据集包含了日常步数统计、睡眠时长、活跃分钟数以及消耗的卡路里,是个人健康与健身追踪的一部分。 该数据集非常适合用于以下实践: 数据清洗:现实世界中的数据往往包含缺失值、异常值或不一致之处。例如,某些天的步数可能缺失,或者存在不切实际的数值(如10,000小时的睡眠或负数的卡路里消耗)。通过处理这些问题,可以学习如何清理和准备数据进行分析。 探索性分析(发现日常习惯中的模式):可以通过分析找出日常生活中的模式和趋势,比如一周中哪一天人们通常走得最多,或是睡眠时间与活跃程度之间的关系等。 构建可视化图表(步数趋势、睡眠与活动对比图):将数据转换成易于理解的图形形式,有助于更直观地看出数据的趋势和关联。例如,绘制步数随时间变化的趋势图,或是比较睡眠时间和活动量之间的关系图。 数据叙事(将个人风格的追踪转化为可操作的见解):通过讲述故事的方式,把从数据中得到的洞察变成具体的行动建议。例如,根据某人特定时间段内的活动水平和睡眠质量,提供改善健康状况的具体建议。
框架结构天城商业办公楼5200平米(建筑图 结构图 计算书 开题报告 任务书 文献翻.zip
柴油机连杆加工工艺及夹具设计.zip
读书网首页的HTML信息
文字渐变颜色代码生成器:让文字绽放多彩魅力,演示:在信息交流日益丰富的今天,个性化的文字展示成为吸引目光的关键。这款文字渐变颜色代码生成器,便是为满足这一需求而生的绿色软件,无需安装,便捷实用。 它的操作极为简便。用户只需在软件界面中输入想要转换的文字内容,接着从丰富的色彩选项里挑选心仪的起始颜色与结束颜色,随后轻轻按下 “转换按钮”,神奇的事情就此发生 —— 适用于论坛、网页、QQ 空间等多种平台,以及自定义格式的渐变颜色代码便会即刻生成。不仅如此,生成的代码还能自动复制到剪切板,极大地节省了用户手动复制的时间。当你在论坛回帖、更新网页内容或是装扮 QQ 空间时,只需轻松粘贴代码,原本单调的文字瞬间就能拥有绚丽的渐变色彩,瞬间脱颖而出,为你的表达增添独特魅力,让文字不再平凡,轻松成为视觉焦点。 一款可以轻松把一段文字生成渐变颜色代码的绿色软件,当你在软件中输入完要转换的文字后,只需要挑选自己喜欢的起始颜色、结束颜色后,按一下―转换按钮即可生成相应的论坛/网页/QQ空间以及自定义格式代码,并且代码可以自动复制到剪切板中,回帖时直接粘贴代码即可不错得文字代码生成器,让你得文字更加漂亮.
1.【锂电池剩余寿命预测】Transformer锂电池剩余寿命预测(Matlab完整源码和数据) 2.数据集:NASA数据集,已经处理好,B0005电池训练、B0006测试; 3.环境准备:Matlab2023b,可读性强; 4.模型描述:Transformer在各种各样的问题上表现非常出色,现在被广泛使用。 5.领域描述:近年来,随着锂离子电池的能量密度、功率密度逐渐提升,其安全性能与剩余使用寿命预测变得愈发重要。本代码实现了Transformer在该领域的应用。 6.作者介绍:机器学习之心,博客专家认证,机器学习领域创作者,2023博客之星TOP50,主做机器学习和深度学习时序、回归、分类、聚类和降维等程序设计和案例分析,文章底部有博主联系方式。从事Matlab、Python算法仿真工作8年,更多仿真源码、数据集定制私信。
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
Android项目原生java语言课程设计,包含LW+ppt
配套文章:https://blog.csdn.net/gust2013/article/details/146909670?spm=1001.2014.3001.5502
《基于YOLOv8的智慧社区儿童游乐设施安全监测系统》(包含源码、可视化界面、完整数据集、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计