事务属性主要用于控制事务的作用域。
假设ma是一个事务a,mb是一个事务b,当ma调用mb时,是在哪个事务作用域中执行的?这个取决于mb的事务属性了。
事务属性支持如下6个值
1,Required
如果ma正处于某个事务上下文中,ma调用了mb方法,则mb直接处于ma所在的事务的作用域中执行。如果ma没有处于任何事务中,容器会自动为mb启动一个新的事务。这个属性值适合绝大多数EJB事务,建议将其设置为默认的,至少在开发阶段。EJB事务属性是声明式的,后期也可以很容易修改。
2,RequiresNew
如果ma在事务中,此时容器采用如下操作
1)挂起ma的当前事务
2)为mb启动一个新的事务
3)执行mb的方法
4)mb执行完毕后,恢复ma的事务
如果ma不在事务中,则启动一个新的事务。也就是说此属性值总会为mb启动一个新的事务。
3,Mandatory
如果ma在事务中,则mb在ma的事务的作用域中运行。如果ma没有在事务中,则容器会抛出TransactionRequiredException。
4,NotSupported
如果ma在事务中,此时容器采用如下操作
1)挂起ma的当前事务
2)执行mb方法
3)执行完毕后,恢复ma的事务。
如果ma不在事务中,则容器也直接执行mb,不会为他启动任何事务。
5,Supports
如果ma在事务中,则mb在ma的事务中运行。如果ma不在事务中,则容器正常执行mb,不会为其启动事务。
6,Never
如果ma在事务中,容器会抛出RemoteException。如果ma不在事务中,则容器正常执行mb,不会为其启动事务。
为EJB设置事务属性,可以通过使用javax.ejb.TransactionAttribute Annotation来标注EJB或方法,并将其值设置为javax.ejb.TransactionAttributeTyep枚举值之一。取值就是上面的介绍内容。如TransactionAttributeType.REQUIRED。
如果修饰类,则代表EJB中所有的方法都使用该属性值。
EJB有两种事务管理方式,这两种方式通常都建立在JTA基础之上,一种是通过容器管理事务(CMT)以声明式方式来管理事务;另一种则在EJB内部使用事务管理代码自己管理事务,这种方式也被称为Bean管理事务(BMT)。
EJB默认使用容器管理事务的策略。容器总是在业务方法的开始、结束处标记事务边界,也就是说,容器将在调用方法之前开始JTA事务,然后根据方法的调用情况来决定提交或回滚事务。当使用CMT事务管理策略时,开发者无需为事务控制编写任何代码,只需要通过Annotation或XML配置文件告诉容器如何处理事务即可。当使用CMT时,业务方法不应该调用任何可能与容器所设置事务边界冲突的方法,如下情形都是被禁止的。
1)禁止调用Connection接口的commit、setAutoCommit和rollback方法
2)禁止调用EJBContext的getUserTransaction方法
3)禁止调用UserTransaction的任何方法
CMT的最大优点是简单、方便,但是它不够灵活。与CMT相比,BMT则可由开发者来决定业务方法中的事务边界,对于BMT来说,程序代码中不要调用EJBContext接口中的getRollbackOnly和setRollbackOnly方法,允许调用UserTransaction的方法来手动控制事务。
weblogic设置事务的超时
<xa-set-transaction-timeout>true</xa-set-transaction-timeout>
<xa-transaction-timeout>5</xa-transaction-timeout>
jboss设置事务的超时
<xa-resource-timeout>10<xa-resource-timeout>
JNDI的全称是 Java Naming Directory Interface,即Java命名目录接口,它允许Java程序通过一个名称来访问真正的Java对象。
RMI指的是Remote Method Invoke(远程方法调用),RMI为Java分布式应用编程提供了基础,RMI底层依然是依赖于Socket网络通信来实现的。
RMI也离不开JNDI,当RMI服务器希望把自己提供的远程方法暴露出来时,就要为自己绑定一个JNDI名称,而RMI客户机则通过JNDI查找来获取远程RMI服务器,然后调用RMI服务器上的远程方法。
JNDI结构包含两组API:JNDI API和JNDI SPI(Service Provider Interface)。开发者使用JNDI API以一致的方式来访问各种命名、目录服务,而JNDI SPI则保证各种命名、目录服务透明地加入JNDI结构中,Naming Manager则负责管理他们二者之间的转换。
JNDI编程
1)创建Context对象
2)调用Context的方法来执行绑定、查找等操作
3)关闭Context
由于Context只是一个接口,因此通常会使用它的实现类InitialContext来创建实例。
InitialContext提供了如下两个构造器:
1)InitialContext():读取系统属性作为Context属性来创建InitialContext
2)InitialContext(Hashtable<?,?> environment):以environment参数指定的属性作为Context属性来创建InitialContext
其中传入的Hashtable作为参数,该Hashtable至少包括如下两个key
java.naming.factory.initial:可用Context内的INITIAL_CONTEXT_FACTORY常量代替。该key的值应该为初始化Context的工厂类。
java.naming.provider.url:可用Context内的PROVIDER_URL常量代替。该key的值应该为Context服务提供者的URL。
例如
Hashtable env=new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,“com.sun.jndi.fscontext.RefFSContextFactory”);
env.put(Context.PROVIDER_URL,“file:/g:/test/”);
Context ctx=new InitialContext(env);
一旦获取了InitialContext对象之后,就可以执行JNDI的相关操作了。
1)查找对象
通过lookup(jndi)方法来实现,该方法接收被绑定的JNDI名,返回与之绑定的对象。由于该方法返回一个Object类型,因此需要强制类型转换
ServiceBean service=(ServcieBean)ctx.lookup(“service”);
2)绑定
JNDI通过bind(String name,Object obj)方法来执行绑定,第一个参数是被绑定的JNDI名,第二个参数是被绑定的对象。执行完该方法后,相当于为obj起了一个name名称。
ServiceBean service=new ServiceBean();
ctx.bind(“service”,service);
3)重新绑定
rebind(String name,Object obj)与绑定的功能基本相似,但是比bind方法更健壮,如果调用rebind方法将某个名字重新绑定到指定对象上时,如果该名字已被绑定过,那么这个已绑定过的名字会重新绑定到新的对象上;如果使用bind方法,则会引发NameAlreadyBoundException异常。如果该名称没有被绑定过,那么rebind方法的功能和bind方法的功能相同。
WebLogic访问被绑定的对象
String factory=”weblogic.jndi.WLInitialContextFactory”;
String url=”t3://localhost:7001”;
执行之前需要将Middleware\wlserver_10.3\server\lib路径下的webservices.jar、wlclient.jar加入classpath中
JBoss访问被绑定的对象
String factory=”org.jnp.interfaces.NamingContextFactory”;
String url=”jnp://localhost:1099”;
执行之前需要将client路径下的jbossall-client.jar、jnp-client.jar、jboss-logging-spi.jar加入classpath中。