使用Annotation设计持久层

这篇文章的想法来自于过去的两篇文章:《设计自己的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.javaeye.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;

不准备详细解释例子的业务流程,不过是登录和增加用户两个业务方法,看下就明白。阅读本文前最好已经读过开头提过的两篇文章。我相信代码是最好的解释:)

文章转自庄周梦蝶  ,原文发布5.16

时间: 2024-07-31 21:54:12

使用Annotation设计持久层的相关文章

Kodo EJB:符合EJB3规范的持久层框架

规范 Kodo是BEA公司收购SolarMetric公司后获得的持久层框架项目,以前只是支持JDO标准,2006年2月13日,BEA公司宣布发布Kodo项目的最新版本--Kodo 4.0.0 Early Access 4,Kodo 4.0.0 EA4支持EJB3和JDO2两个标准,本文中,我们将首先学习和了解KODO EJB,了解如何使用Kodo EJB完成开发工作. 我们将按照两种不同的情况讲述如何使用Kodo EJB进行开发,一种是通过命令行工具,另外一种是在Eclipse中使用Ant任务.

Hibernate作为数据持久层的分析和研究

数据 摘要 在Java技术中有许多方法可以对数据进行持久化,持久层也是Java应用程序中最重要的部分之一.本文在分析了3种持久层主流解决方案的基础上,介绍了O-R映射开源项目Hibernate,并介绍了在Web应用开发中怎样配置Hibernate的环境,并使用它建立一个应用. 关键字 hibernate,数据持久化,JDBC, EJB,JDO 数据持久层简介 J2EE的三层结构是指表示层(Presentation),业务逻辑层(Business Logic)以及基础架构层(Infrastruct

SpringSide开发实战(四):打通数据持久层的任督二脉

在这里,将创建一个简化的用户管理模块,演示怎样利用SpringSide提供的数据持久层 的功能,包括怎样通过Hibernate的Annotation来配置多对一映射和多对多映射. 大家都知道,现在最流行用户管理模型的是RBAC,也就是基于角色的访问控制模型,在 这种模型中,可以划分多个层次,如用户-角色-资源.用户-角色-权限-资源.用户-角色- 角色组-权限-资源.用户-角色-角色组-权限-操作-资源等等,因此,想要创建一个完善而 复杂的用户管理模块,是相当具有难度的.在Web2.0时代,有一

《Spring 3.0就这么简单》——1.4 持久层

1.4 持久层 持久层负责数据的访问和操作,DAO类被上层的业务类调用.Spring本身支持多种流行的ORM框架.这里使用Spring JDBC作为持久层的实现技术,关于Spring JDBC的详细内容,请参见第4章的内容.为方便阅读,会对本章涉及的相关知识点进行必要的介绍,所以相信读者在不了解Spring JDBC的情况下,也可以轻松阅读以下的内容.1.4.1 建立领域对象 领域对象(Domain Object)也称为实体类,它代表了业务的状态,一般来说,领域对象属于业务层,但它贯穿展现层.业

设计数据层组件并在层间传递数据

设计|数据 设计数据层组件并在层间传递数据 Angela Crocker.Andy Olsen 和 Edward JezierskiMicrosoft Corporation 2002年8月 适用于:    Microsoft .NET 应用程序 摘要:学习向 Microsoft .NET 应用程序公开数据的最佳方式,以及如何实现一个有效的策略以便在分布式应用程序的层间传递数据.(本文包含一些指向英文站点的链接.) 目录简介 将关系数据映射到业务实体 实现数据访问逻辑组件 实现业务实体 事务处理

ASP数据持久层抽象

数据持久层在所有的系统中都存在.对于小型或者中型的ASP应用,这一点往往不受重视.这篇文章试图改善这一现状,以一种简单的方式提供了简化调用ADO相关对象的方法.这种方法的思想可以延伸到其他编程语言,只要这种语言稍微具备一点点面向对象的思想,那么本篇文章将使你收益. 你还在使用ASP吗?我知道ASP虽然被很多高级的企业级应用抛弃,但是像我一样靠ASP起家的开发者,或者开发一些简单WEB应用的开发者,一定在某些时候还在考虑ASP.它简单,容易使用.在访问数据库方面,通过ADO也能够无所不能.然而使用

在SCA Module中使用iBATIS框架实现数据持久层

在完成 SCA Module 建模后用 Java 对象进行实现时,采用 Hibernate 和采用 iBATIS 实现 SCA Module 的数据持久层,目的都是为 SDO 提供数据访问服务并加快 SCA 模块实现.前文已经讲过关于如何使用 Hibernate 实现 SCA Module 的数据持久层,本文将介绍 iBATIS 框架,比较 iBATIS 和 Hibernate 的异同,并以实例的方式介绍如何使用 iBATIS 实现 SCA Module 的数据持久层. iBATIS 是一种数据

PHP基于MySQL数据库实现对象持久层的方法

 本文实例讲述了PHP基于MySQL数据库实现对象持久层的方法.分享给大家供大家参考.具体如下: 心血来潮,做了一下PHP的对象到数据库的简单持久层. 不常用PHP,对PHP也不熟,关于PHP反射的大部分内容都是现学的. 目前功能比较弱,只是完成一些简单的工作,对象之间的关系还没法映射,并且对象的成员只能支持string或者integer两种类型的. 成员变量的值也没有转义一下... 下面就贴一下代码: 首先是数据库的相关定义,该文件定义了数据库的连接属性: ? 1 2 3 4 5 6 7 8

关于持久层能不能出现多个持久层框架,比如ibatis,jdbc

问题描述 关于持久层能不能出现多个持久层框架,比如ibatis,jdbc 开发有时候会用到多数据库建立数据库连接池的情况,就是想问下,会不会也同样有多个操作数据库的框架共同或者切换使用 解决方案 可以出现.我见过mybatis和hibernate一起使用的,mybatis做一些复杂sql,hibernate做一些简单的对象增删改 解决方案二: 我没遇到过多个持久层框架同时使用的 解决方案三: 我觉得如果有,就要有多个配置,到时候该怎么切换呢 解决方案四: 是可以,不过这样做太麻烦了,也浪费空间.