现在要搭建一个框架 单纯jsp+servlet+javaBean的形式,不采用任何框架数据库操作采用dbUtils,简单的对JDBC进行封装现在有一个疑问:我现在采用service层充当业务逻辑层,dao封装DB相关操作我是在DAO中的每个方法里添加事务还是在service中添加事务呢?最后会在service层中操作不同的表,进行INSERT和UPDATE如何在SERVICE层写事务,如何来写啊怎样更好一些?
没多少分了,大家帮帮忙

解决方案 »

  1.   

    当然在Service层加事务了,多步操作不同的数据库,回滚怎么在DAO层保持数据一致性呢
      

  2.   

    我是把事务放在service层
    对dao 出来的资料进行处理
      

  3.   

    dbUtils没有用过,就跟写DAO一样的,在Service层创建Connection,然后try{拿到Transaction,然后begin事务,然后调用DAO,commit事务}catch(Exception e){transaction.rollback;e.printStack()}
      

  4.   

    这是事务管理的一个难点,也是 J2EE 设计模式之一的事务上下文模式。应在业务层进行事务控制,如果我们不应该在业务层的方法中把 Connection 传来传去,这样就太傻了。事务上下文的宗旨就是进行无入侵式事务,使用 ThreadLocal 存放 Connection,将业务对象使用 AOP 或者是简单的动态代理将事务代码切入。下面这些代码是使用 JPA,没有使用其他框架时自己实现的。import java.lang.reflect.AnnotatedElement;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.HashSet;
    import java.util.Set;import javax.persistence.EntityManager;
    import javax.persistence.EntityTransaction;import net.blogjava.frankiegao123.log.Log;
    import net.blogjava.frankiegao123.log.Logger;/**
     * 事务代理
     * @author frankiegao123
     * 2009-10-30 上午10:25:57
     */
    public class TransactionProxy {
        
        private static Log log = Logger.getLog(TransactionProxy.class);    @SuppressWarnings("unchecked")
        public static <T> T delegate(Class<T> clazz, Object obj) {
            if(!isRequiredTransaction(obj.getClass())) {
                return (T)obj;
            }
            // 返回代理对象
            return (T)Proxy.newProxyInstance(
                        obj.getClass().getClassLoader(),
                        obj.getClass().getInterfaces(),
                        new XAInvocationHandle(obj)
                    );
        }
        
        /**
         * 检查某一对象是否需要使用事务,业务方法默认带有事务
         * @param obj
         * @return
         * @author frankiegao123
         * 2009-10-30 上午10:26:58
         */
        private static boolean isRequiredTransaction(AnnotatedElement obj) {
            TransactionAttribute type = obj.getAnnotation(TransactionAttribute.class);
            // 为 null 时,说明方法上未标注 TransactionAttribute,这时默认启用事务
            if((type == null) || TransactionAttributeType.REQUIRED.equals(type.value())) {
                return true;
            }
            return false;
        }
        
        private static void logArguments(Object obj, Method method, Object[] args) {
            if(log.isDebugEnabled()) {
                if(args == null || args.length == 0) {
                    return;
                }
                StringBuilder sb = new StringBuilder();            
                for(int i = 0; i < args.length; i++) {
                    if(i > 0) {
                        sb.append(", ");
                    }
                    sb.append(args[i]);
                }
            }
        }
        
        /**
         * 使用 JDK 动态代理织入事务处理
         * @author frankiegao123
         * 2009-10-30 上午11:56:47
         */
        private static class XAInvocationHandle implements InvocationHandler {
            
            private Object delegate;
            
            private static Set<String> excludeMethodNames = excludeMethodNames();
            
            public XAInvocationHandle(Object delegate) {
                this.delegate = delegate;
            }        public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                logArguments(delegate, method, args);            
                if(excludeMethodNames.contains(method.getName())) {
                    return invokeObjectMethod(proxy, method, args);
                }            
                if(isRequiredTransaction(method)) {
                    // 需要事务处理                
                    return invokeRequiredTransaction(proxy, method, args);
                } else {
                    // 不需要事务处理                
                    return invokeNeverTransaction(proxy, method, args);
                }
            }
            
            private Object invokeNeverTransaction(Object proxy, Method method, Object[] args) throws Throwable {
                Object obj = null;
                EntityManager em = null;
                try {
                    em = JpaEntityManager.bindThreadEntityManager();
                    obj = method.invoke(delegate, args);
                } catch(Throwable e) {
                    throw e;
                } finally {
                    JpaEntityManager.closeEntityManager(em);
                }
                return obj;
            }
            
            private Object invokeObjectMethod(Object proxy, Method method, Object[] args) throws Throwable {
                Object obj = null;
                try {
                    obj = method.invoke(delegate, args);
                } catch(Throwable e) {       
                    throw e;
                }
                return obj;
            }
            
            private Object invokeRequiredTransaction(Object proxy, Method method, Object[] args) throws Throwable {
                EntityManager em = null;
                EntityTransaction transaction = null;
                Object obj = null;
                try {
                    em = JpaEntityManager.bindThreadEntityManager();
                    transaction = em.getTransaction();
                    transaction.begin();
                    obj = method.invoke(delegate, args);                
                    transaction.commit();
                } catch (Throwable e) {                
                    if(transaction != null && transaction.isActive()) {
                        transaction.rollback();
                    }
                    throw e;
                } finally {
                    JpaEntityManager.closeEntityManager(em);
                }
                return obj;
            }
            
            private static Set<String> excludeMethodNames() {
                Method[] methods = Object.class.getMethods();
                Set<String> methodNames = new HashSet<String>();
                for(int i = 0; i < methods.length; i++) {
                    methodNames.add(methods[i].getName());
                }
                return methodNames;
            }
        }
    }import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;import net.blogjava.frankiegao123.log.Log;
    import net.blogjava.frankiegao123.log.Logger;/**
     * JPA EntityManager 管理工具<br />
     *
     * 从 EntityManagerFactory 获得 EntityManager 对象并绑定到当前线程中,以便进行事务管理
     *
     * @author frankiegao123
     * 2009-10-30 下午12:16:41
     */
    public class JpaEntityManager {    private static Log log = Logger.getLog(JpaEntityManager.class);    private static EntityManagerFactory factory;    /**
         * 本地线程容器
         */
        private static ThreadLocal<EntityManager> entityManagerThreadBind = new ThreadLocal<EntityManager>();    static {
            try {
                // 初始化 EntityManagerFactory
                factory = Persistence.createEntityManagerFactory(Config.getInstance().getJpaUnitName());
            } catch(Exception e) {
                log.error("EntityManagerFactory init failed", e);
            }
        }    private JpaEntityManager() {
        }    /**
         * 从当前线程中获得已经绑定在线程上的 EntityManager 对象
         * @return
         * @author frankiegao123
         * 2009-10-30 下午12:35:15
         */
        public static synchronized EntityManager getEntityManager(){
            EntityManager entityManager = findThreadEntityManager();
            if(entityManager == null) {
                // 没有绑定时,抛出异常
                throw new ThreadEntityManagerException("EntityManager cannot be found from current thread");
            }
            log.info("find EntityManager: {0} from current thread", entityManager);
            return entityManager;
        }    /**
         * 关闭当前线程中的 EntityManager 对象,同时清空当前线程中 EntityManager,便于下次重新绑定执行事务
         *
         * @param entityManager
         * @author frankiegao123
         * 2009-10-30 下午12:37:11
         */
        public static synchronized void closeEntityManager(EntityManager entityManager) {
            EntityManager em = findThreadEntityManager();
            log.debug("current thread EntityManager: {0}, parameter EntityManager: {1}", em, entityManager);
            if(em == null) {
                log.warn("EntityManager object in current thread is null, Using method invoke parameter EntityManager: {0}", entityManager);
                em = entityManager;
            }
            em.close();
            em = null;
            log.debug("EntityManager object close success");
            entityManagerThreadBind.set(null);
            log.info("current EntityManager object has been closed and the object in ThreadLocal has been set null");
        }    /**
         * 获得新的 EntityManager 对象,并绑定到当前线程中
         *
         * @return
         * @author frankiegao123
         * 2009-10-30 下午12:38:15
         */
        public static synchronized EntityManager bindThreadEntityManager() {
            EntityManager preEntityManager = findThreadEntityManager();
            if(preEntityManager != null) {
                // 当前线程中还存在之前没有被处理的 EntityManager 对象
                log.warn("pre EntityManager not be closed, EntityManager: {0}", preEntityManager);
                closeEntityManager(preEntityManager);
            }
            EntityManager entityManager = factory.createEntityManager();
            setEntityManager(entityManager);
            log.debug("EntityManager object was binded to current thread, EntityManager: {0}", entityManager);
            return entityManager;
        }    /**
         * 从本地线程中获得 EntityManager 对象
         * @return
         * @author frankiegao123
         * 2009-10-30 下午12:18:44
         */
        private static EntityManager findThreadEntityManager() {
            return entityManagerThreadBind.get();
        }    private static void setEntityManager(EntityManager entityManager) {
            entityManagerThreadBind.set(entityManager);
        }
    }还有两个用于标注于业务方法上的事务属性,简单地实现了两个。
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;@Target(value = { ElementType.METHOD, ElementType.TYPE })
    @Retention(value = RetentionPolicy.RUNTIME)
    public @interface TransactionAttribute {
        TransactionAttributeType value() default TransactionAttributeType.REQUIRED;
    }/**
     * 事务属性
     * @author frankiegao123
     * 2009-10-30 上午10:16:06
     */
    public enum TransactionAttributeType {    /**
         * 启用事务
         */
        REQUIRED,
        
        /**
         * 不启用事务
         */
        NEVER
    }
      

  5.   

    这上面的 EntityManager 就相当于 JDBC 中的 Connection
      

  6.   

    如果有可能的话,可以去看看这本书,这本书对事务上下文模式有详细地介绍。http://oreilly.com.cn/book.php?bn=7-5083-3099-4不过这本书是 2005 年出版的,买肯定是买不到了。