BMT就是Bean自己管理事务,这种方式就是以硬编码的方式在Bean中自己通过JTA接口自己维护事务代码,开始事务、提交事务、回滚事务都需要自己以硬编码的方式来维护,这种方式就是一个优点,灵活,不过EJB规范不建议使用此策略来管理事务,而是采用CMT。
代码如下:
package ejb.sessionBean.impl;
/** * bean代码自管理事务 * * @author liuyan * */ @Stateless @TransactionManagement(TransactionManagementType.BEAN) public class BMTServerEAOImpl implements BMTServer {
private DataSource dataSource;
@Resource private UserTransaction userTransaction;
public BMTServerEAOImpl() throws NamingException { Context context = new InitialContext(); dataSource = (DataSource) context.lookup("java:/jbossdemo"); }
@Override public void insert() throws Exception {
Connection connection = null;
Statement statement = null;
try {
// 开始事务 userTransaction.begin();
connection = dataSource.getConnection();
statement = connection.createStatement();
String insert1 = "insert into person values(17,'一线生')";
String insert2 = "insert into person values(16,'冷剑白狐')";
statement.executeUpdate(insert1);
statement.executeUpdate(insert2); // 事务手工提交 userTransaction.commit(); statement.close(); connection.close(); } catch (Exception e) { System.out.println("事务回滚~~"); userTransaction.rollback(); e.printStackTrace(); } } } |
测试代码不再赘述,执行后JBoss控制台如下,数据库也没添加任何数据。
15:18:47,568 INFO [STDOUT] 事务回滚~~ 15:18:47,638 ERROR [STDERR] com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '16' for key 'PRIMARY' |
把代码稍微修改一下,将重复的主键修改一下
String insert2 = "insert into person values(18,'冷剑白狐')"; |
执行后数据库成功插入新的纪录,如下
1. EJB拦截器
EJB也支持简单的自定义AOP类和横切方法,还是直接看例子吧。
AOP类——MyInterceptor
package aop; import java.lang.reflect.Method; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext;
/** * 自定义的拦截器 * * @author liuyan * */ public class MyInterceptor { @AroundInvoke public Object log(InvocationContext ctx) throws Exception { System.out.println("日志开启"); Object object = ctx.getTarget(); System.out.println("拦截的SessionBean实例:" + object); Method method = ctx.getMethod(); System.out.println("拦截的SessionBean方法:" + method.getName()); Object objectReturn = ctx.proceed(); System.out.println("日志记录结束"); return objectReturn; } } |
所谓横切方法,实际上就是代理执行,那么在此AOP类中就需要调用被拦截的方法。Object objectReturn = ctx.proceed();就是执行被拦截目标类的方法。如果没有此行代码,那么目标方法将不会执行。
下面看一下被横切,拦截的目标类——HelloAopServerEAOImpl
package aop.server.impl; import javax.ejb.Stateless; import javax.interceptor.ExcludeClassInterceptors; import javax.interceptor.Interceptors; import aop.MyInterceptor; import aop.server.HelloAopServer;
@Stateless @Interceptors(MyInterceptor.class) public class HelloAopServerEAOImpl implements HelloAopServer {
@Override @ExcludeClassInterceptors public void noAop() { System.out.println("noAop()");
}
@Override public String sayHello() { return "hello AOP"; }
@Override public void sayWelcome() { System.out.println("sayWelcome()"); } } |
在目标类中使用@Interceptors(MyInterceptor.class)注解代表使用此类被作为AOP的目标所拦截。而此类的方法上加上@ExcludeClassInterceptors注解则代表该方法不会被拦截。
客户端测试代码如下:
public void test01() throws Exception { Context context = init(); HelloAopServer helloAopServer = (HelloAopServer) context .lookup("HelloAopServerEAOImpl/remote"); helloAopServer.sayHello(); helloAopServer.sayWelcome(); helloAopServer.noAop(); } |
执行后,服务器控制台信息如下
15:40:16,812 INFO [STDOUT] 日志开启 15:40:16,812 INFO [STDOUT] 拦截的SessionBean实例:aop.server.impl.HelloAopServerEAOImpl@1dc88c7 15:40:16,812 INFO [STDOUT] 拦截的SessionBean方法:sayHello 15:40:16,812 INFO [STDOUT] 日志记录结束 15:40:16,822 INFO [STDOUT] 日志开启 15:40:16,822 INFO [STDOUT] 拦截的SessionBean实例:aop.server.impl.HelloAopServerEAOImpl@1dc88c7 15:40:16,822 INFO [STDOUT] 拦截的SessionBean方法:sayWelcome 15:40:16,822 INFO [STDOUT] sayWelcome() 15:40:16,822 INFO [STDOUT] 日志记录结束 15:40:16,831 INFO [STDOUT] noAop() |
可以证明:预期该拦截的sayHello()和sayWelcome()都被拦截了,而noAop()并没有被拦截到。