这篇文章的想法来自于过去的两篇文章:《设计自己的MVC框架》《设计模式之事务处理》
链接:
http://www.javaresearch.org/article/59935.htm
http://www.javaresearch.org/article/59043.htm
代码下载同样在www.126.com的邮箱里,用户名 sharesources 密码 javafans
本文只是学习性质的文章,我一开始的想法就是修改《设计模式之事务处理》,提供Annotation来提供事务支持,支持到方法级别。通过引入一个 @Transaction标注,如果被此标注的方法将自动享受事务处理。目的是学习下Annotation和加深下对声明式事务处理的理解。
Annotation是JDK5引入的新特性,现在越来越多的框架采用此特性来代替烦琐的xml配置文件,比如hibernate,ejb3, spring等。对Annotation不了解,请阅读IBM网站上的文章,还有推荐javaeye的Annotation专栏:http: //www.iteye.com/subject/Annotation
代码的示例是一个简单的用户管理例子。
首先,环境是mysql+jdk5+myeclipse5+tomcat5,在mysql中建立一张表adminusers:
create table adminusers(id int(10) auto_increment not null primary key,
name varchar(10) not null,
password varchar(10) not null,
user_type varchar(10));
然后在tomcat下建立一个数据源,把代码中的strutslet.xml拷贝到tomcat安装目录下的 /conf/Catalina/localhost目录里,请自行修改文件中的数据库用户名和密码,以及数据库名称。另外,把mysql的 jdbc驱动拷贝到tomcat安装目录下的common/lib目录。这样数据源就建好了。在web.xml中引用:
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/test</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
我的例子只是在《设计模式之事务处理》的基础上改造的,在那篇文章里,我讲解了自己对声明式事务处理的理解,并利用动态代理实现了一个 TransactionWrapper(事务包装器),通过业务代理工厂提供两种版本的业务对象:经过事务包装的和未经过事务包装的。我们在默认情况下包装业务对象中的所有方法,但实际情况是,业务对象中的很多方法不用跟数据库打交道,它们根本不需要包装在一个事务上下文中,这就引出了,我们为什么不提供一种方式来配置哪些方法需要事务控制而哪些并不需要?甚至提供事务隔离级别的声明?很自然的想法就是提供一个配置文件,类似spring式的事务声明。既然JDK5已经引入Annotation,相比于配置文件的烦琐和容易出错,我们定义一个@Transaction的annotation来提供此功能。
看下Transaction.java的代码:
package com.strutslet.db;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.sql.Connection;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Transaction {
//事务隔离级别,默认为read_committed
public int level() default Connection.TRANSACTION_READ_COMMITTED ;
}
@Transaction 标注只有一个属性level,level表示事务的隔离级别,默认为Read_Committed(也是一般JDBC驱动的默认级别,JDBC驱动默认级别一般于数据库的隔离级别一致)。 @Target(ElementType.METHOD)表示此标注作用于方法级别, @Retention(RetentionPolicy.RUNTIME)表示在运行时,此标注的信息将被加载进JVM并可以通过Annotation的 API读取。我们在运行时读取Annotation的信息,根据隔离级别和被标注的方法名决定是否将业务对象的方法加进事务控制。我们只要稍微修改下 TransactionWrapper:
//TransactionWrapper.java
package com.strutslet.db;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import com.strutslet.exception.SystemException;
public class TransactionWrapper {
public static Object decorate(Object delegate) {
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(), new XAWrapperHandler(
delegate));
}
static final class XAWrapperHandler implements InvocationHandler {
private final Object delegate;
XAWrapperHandler(Object delegate) {
// Cache the wrapped delegate, so we can pass method invocations
// to it.
this.delegate = delegate;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
Connection con = ConnectionManager.getConnection();
//得到Transaction标注
Transaction transaction = method.getAnnotation(Transaction.class);
//如果不为空,说明代理对象调用的方法需要事务控制。
if (transaction != null) {
// System.out.println("transaction.." + con.toString());
// 得到事务隔离级别信息
int level = transaction.level();
try {
if (con.getAutoCommit())
con.setAutoCommit(false);
//设置事务隔离级别
con.setTransactionIsolation(level);
//调用原始对象的业务方法
result = method.invoke(delegate, args);
con.commit();
con.setAutoCommit(true);
} catch (SQLException se) {
// Rollback exception will be thrown by the invoke method
con.rollback();
con.setAutoCommit(true);
throw new SystemException(se);
} catch (Exception e) {
con.rollback();
con.setAutoCommit(true);
throw new SystemException(e);
}
} else {
result = method.invoke(delegate, args);
}
return result;
}
}
}
现在,看下我们的UserManager业务接口,请注意,我们是使用动态代理,只能代理接口,所以要把@Transaction标注是接口中的业务方法(与EJB3中的Remote,Local接口类似的道理):
package com.strutslet.demo.service;
import java.sql.SQLException;
import com.strutslet.db.Transaction;
import com.strutslet.demo.domain.AdminUser;
public interface UserManager {
//查询,不需要事务控制
public boolean checkUser(String name, String password) throws SQLException;
//新增一个用户,需要事务控制,默认级别
@Transaction
public boolean addUser(AdminUser user) throws SQLException;
}
要把addUser改成其他事务隔离级别(比如oracle的serializable级别),稍微修改下:@Transaction(level=Connection.TRANSACTION_SERIALIZABLE)
public boolean addUser(AdminUser user) throws SQLException;
不准备详细解释例子的业务流程,不过是登录和增加用户两个业务方法,看下就明白。阅读本文前最好已经读过开头提过的两篇文章。我相信代码是最好的解释:)
分享到:
相关推荐
在本文中,我们将了解如何使用Java 5 注释来简化Hibernate代码,并使持久层的编码过程变得更为轻松。 传统上,Hibernate的配置依赖于外部 XML 文件:数据库映射被定义为一组 XML 映射文件,并且在启动时进行加载。...
用cascading实现传播性持久化(Transitive persistence) 2.2.5.5. 关联关系获取 2.2.6. 映射复合主键与外键 2.2.7. 映射二级表(secondary tables) 2.3. 映射查询 2.3.1. 映射EJBQL/HQL查询 2.3.2. 映射本地化查询 ...
springboot-aop-annotation-redis-demo:源码主要用于学习SpringBoot + AOP + Redis控制Redis自动缓存和...查询,数据库使用MySQL 8.0.16,持久层使用Spring Data JPA,前端调用Swagger-UI 2.9.2提供API可视化调试操作
hibernate是在JDBC之上提供一层薄薄的封装,在提供完全透明的持久化机制的同时又提供尽可能多的灵活性。相比之ibatis则是面向“语句映射”的层面,使用SQL作为查询语言。
传统上,Hibernate的配置依赖于外部 *.hbm.xml文件:数据库映射被定义为一组 XML ...由于 Hibernate 3 还提供了一些扩展,因此您可以十分轻松地遵从这些标准,并使用 EJB 3 编程模型来对 Hibernate 持久层进行编码。
第4章 orm中间件名流hibernate 3接管持久层 191 4.1 orm简介 191 4.1.1 持久化与持久层 191 4.1.2 jdbc劣势 192 4.1.3 实体域模型与关系数据模型 193 4.1.4 orm中间件 196 4.2 hibernate简介 196 4.2.1 ...
springboot-jdbc-aop-transactional-demo
MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀的持久层框架,它消除了几乎所有的JDBC代码、对参数的手工设置以及对结果集繁琐的处理,使用简单的XML或注解(annotation)用于配置和映射,将接口和POJO...
利用Spring的AOP来做声明式事务,利用Spring的Annotation方式基本达到了零配置,持久层全部使用Hibernate Annotation方式,主要采用的是标准的JPA注解,这样减少了大量的Hibernate映射文件,提高了可维护性,Java与...
17.2.6 持久层设计 17.2.7 服务层设计 17.2.8 Web层设计 17.2.9 数据库设计 17.3 开发前的准备 17.4 持久层开发 17.4.1 PO类 17.4.2 DAO基类 17.4.3 通过扩展基类所定义DAO类 17.4.4 DAO Bean的装配 17.4.5 使用...
17.2.6 持久层设计 17.2.7 服务层设计 17.2.8 Web层设计 17.2.9 数据库设计 17.3 开发前的准备 17.4 持久层开发 17.4.1 PO类 17.4.2 DAO基类 17.4.3 通过扩展基类所定义DAO类 17.4.4 DAO Bean的装配 17.4.5 使用...
使用struts做界面。hibernate(这里使用的是xml,不是用Annotation写的)做持久层,spring进行依赖注入,使三个层次结构鲜明,做出了自己想要的效果。欢迎大家下载后,给予评价
您还可以确保持久层得到更多保护,以防止代码漏洞。 目前,就在刷新之前对数据进行了验证,这与使用ORM的想法不同,在ORM中,实体在“构造”之后必须有效。 但是,该模块为我解决了许多现实生活中的问题,我...
FastQuery数据持久层框架 FastQuery基于Java语言。他的使命是:简化Java操作数据层。提供某种Annotation ,消费者只用关心Annotation解的含义,从而进行框架的核心替换,并能够持续良性发展。 FastQuery主要特性如下...
该案例采用目前最流行、最规范的java ee架构,整个应用分为jpa实体层、eao层、业务逻辑层、mvc层和视图层,各层之间分层清晰,层与层之间以松耦合的方法组织在一起。该案例既提供了ide无关的、基于ant管理的项目源码...
此文档仅供初学者学习,包括Spring的依赖注入(控制反转)的详细实例。以三层贯穿实例(持久层、业务层、控制层),由MAIN方法直接调用测试用例。
提供少许Annotation,消费者只用关心注解的含义,这就使得框架的核心便于重构,便于持续良性发展.,仅仅只需要设计编写DAO接口即可,在项目初始化阶段采用ASM生成好实现类. 因此,开发代码不得不简洁而优雅.从而,大幅度...
warp-dynamic-finder:提供了基于Annotation的动态查询功能,让数据库查询变得异常简单,不再需要DAO层 warp-mvc:借鉴了Tapestry5,提供了一个基于事件机制和组件化的Web层,并且组件注入方式高度IoC化 warp-...
cache-dao 持久层模块double-cache-common 公共模块,redis工具类,guava chche抽象类在该模块中分支说明master基础版本cache_annotation_20190114 【强烈推荐直接切换到该分支代码,后续的优化及改进都将在该分支上...
优点 | Advantages无侵入:jDialects工作原理基于对SQL文本进行变换,不会对您现有的持久层工具产生任何影响。依赖少:仅依赖单个jar文件, 大小约280k。从Annotation创建DDL:提供对一些主要的JPA注解的支持从Java...