好吧,我承认,我蛋疼了。真的很疼很疼。。公司的项目不许用ssh,也不许用ssi...   1>好吧。。action写个调度还是比较easy的..用了三天把调度了,采用的是struts2的思想,一个reuquest一个实例,不过没有为action产生代理。。这个我想也没啥好蛋疼的。。  2> 连结池采用的是c3po,自己写连接池管理器。。  3> 也就是今天碰到的问题:事务.....  加事务啊。在service控制事务目前蛋疼中....   问题:  
   1。如何保证同一个事务方法中所有dao 用的是同一个connection??
   2。保证嵌套事务?????  其它问题暂时未知ing.......  目前想法: 
1: 用事务的方法第一行,开启事务ThreadLocal保存开启事务后的connection..然后将ThreadLocal,放到context中(缓存中)..在各个dao里面,直接从context中获取connection....不知道可不可行??是个大大的XXXXX
2> 用一个count来记录事务的层数? 每嵌套一层+1. 提交一次-1  最后为0时,就connection.commit()????
求大牛指点。    

解决方案 »

  1.   

    1。如何保证同一个事务方法中所有dao 用的是同一个connection??
    单例模式穿件单例类
      

  2.   


    汗连接数据库的Connection变成了单例那你真是个人才。。
      

  3.   

    不用SSH做到,LZ V5啊,顺便接分中,嘻嘻
      

  4.   

    2> 用一个count来记录事务的层数? 每嵌套一层+1. 提交一次-1 最后为0时,就connection.commit()????
    你这么做不是累死
      

  5.   

    建议蛋疼的楼主去看下spring 源码里面对事物的管理的思想。
    参考之:http://developer.51cto.com/art/200906/129854.htm
      

  6.   

    还好LZ公司没限制用java ...不太确定LZ的问题, 本人的做法是在 Action 里面,
    session = dbPool.openSession();
    try {
        session.beginTransaction();
        someService.process(session);
        otherSerivce.process(session);
        session.commit();}
    catch(Exception e) {
        session.rollback()
    }
    finally {
        session.close();
    }class SomeSerivce {
       public static void process(Session session) {
            session.createSQLQuery("select * from ****");
        ....
       }
    }用 ThreadLocal 比较复杂
      

  7.   

    你要实现这个功能可没那么简单啊,如果是类似于 REQUIRED 的还好弄一些,要弄 REQUIES_NEW 的就非常复杂了!你要做的这个不要说是你的应用了,就算是 J2EE 应用服务器这种东西的实现也是有优劣的。在 ThreadLocal 绑定 Connection,在 DAO 中从 ThreadLocal 中获得 Connection使用动态代理,将业务逻辑方法代理,在代理中获得 Connection 并置于 ThreadLocal 中,并在代理中处理事务,这样的话这一业务逻辑调用所有的 DAO 方法均纳入到了一个事务之中。楼主提的问题是 J2EE 设计模式之一——事务上下文模式下面这些帖子有同样的问题,可以参考一下:jdbc如何实现事务处理?(例如先进行读取在进行修改能在一个事务里)
    http://topic.csdn.net/u/20090323/17/29237aab-ee3e-4e16-b9c4-53856425022c.html请教一下,在纯的JDBC中,如何项目采用分层了DAO层,服务层和SERVLET控制层,,那么怎么在servlet中启用JDBC的事务?
    http://topic.csdn.net/u/20080705/18/d894b5e5-8b7b-4560-af16-e4b9d8405681.html将connection存放在Threadlocal里和数据库连接池的区别
    http://topic.csdn.net/u/20080731/22/9af1fa06-2c82-4790-bee0-0274a66f3ae9.html大家来讨论下业务层(BO)该做什么事?该怎样做事?
    http://topic.csdn.net/u/20090528/21/160f4629-8985-4a05-89ed-7b4bdcf9bb0f.html多个线程共享一个connection的问题
    http://topic.csdn.net/u/20071128/12/6f085b57-a1b5-4100-a036-f43ef5ab3f8c.html这里还有一个帖子,虽然涉及 JPA 的,但在 J2SE 环境下 JPA 与 JDBC 没啥区别:EJB3之JPA程序结构,完美的异常处理
    http://topic.csdn.net/u/20090829/20/6e73877e-af46-4f98-9fce-f574495b550c.html声明一下,我不认同这位帖主的做法(其采用 Runnable 接口),不过可以借鉴一下,作为一种思路也行。---------------------------------------------------------------------------------------下面的代码是我实现的事务上下文,之前在实际当中应用过,后来由于其他原因就没有用了,代码量很大,有兴趣的话供为参考:我们系统中也要用到,不过我们是使用 JPA 的,但是 JPA 在 J2SE 环境中跟 JDBC 没啥区别,下面这些是我的关键类和代码:JpaEntityManager 管理类,从该类产生 EntityManager 对象,管理当前线程中绑定的对象: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 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
         */
        static 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();
            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
         */
        static 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);
        }
    }TransactionProxy 使用 JDK 的 Proxy 实现 AOP 用于给业务类加上事务处理(这代码比较多,放在楼下)下面这些是业务事务代理工厂类 ServiceFactory,业务接口 Service, 实现类 GaoService,DAO 类 GaoTestDao,以及 JpaBaseDao 的代码:public class ServiceFactory {    private static Service service = null;
        
        static {
            service = TransactionProxy.delegate(Service.class, new GaoService());
        }
        
        public static Service getService() {
            return service;
        }
    }public interface Service {
        public GaoTest process(Lottery lottery);
    }class GaoService implements Service {
        
        private static int k = 3000;
        
        private static Log log = Logger.getLog(GaoService.class);
        
        public GaoTest process(Lottery lottery) {
            GaoTest gt = new GaoTest();
            gt.setName(lottery.getCode());
            gt.setTime(new Date());      
            GaoTestDao dao = new GaoTestDao();
            dao.persist(gt);        
            GaoTest t = dao.find("c229e808-f1ce-4bab-9af0-9637e3c2c487");
            if(t != null) {
                t.setName("Gao" + (k++));
            }        
            dao.merge(t);
            return gt;
        }
    }public class GaoTestDao extends JpaBaseDao<GaoTest> {
        @SuppressWarnings("unchecked")
        public List<GaoTest> findGaoTestByName(String name) {
            String jpql = "SELECT t FROM GaoTest t WHERE t.name = :name";
            EntityManager em = JpaEntityManager.getEntityManager();
            Query q = em.createQuery(jpql).setParameter("name", name);
            return q.getResultList();
        }
    }import java.io.Serializable;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;import javax.persistence.EntityManager;public class JpaBaseDao<T> implements BaseDao<T> {
        
        private Class<T> entityClass;
        
        @SuppressWarnings("unchecked")
        public JpaBaseDao() {
            Type genType = getClass().getGenericSuperclass();
            Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
            entityClass = (Class)params[0];
        }    public T find(Serializable id) {
            EntityManager em = JpaEntityManager.getEntityManager();
            return em.find(entityClass, id);
        }    @SuppressWarnings("unchecked")
        public List<T> getAll() {
            EntityManager em = JpaEntityManager.getEntityManager();
            String jpql = "SELECT t FROM " + entityClass.getName() + " t"; 
            return em.createQuery(jpql).getResultList();
        }    public void merge(T t) {
            EntityManager em = JpaEntityManager.getEntityManager();
            em.merge(t);
        }    public void persist(T t) {
            EntityManager em = JpaEntityManager.getEntityManager();
            em.persist(t);
            em.flush();
        }    public void remove(T t) {
            EntityManager em = JpaEntityManager.getEntityManager();
            em.remove(t);        
        }
    }未完,接下楼
      

  8.   

    import java.lang.reflect.AnnotatedElement;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;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())) {
                log.debug("[{0}] never transaction", obj.getClass().getSimpleName());
                return (T)obj;
            }
            log.debug("[{0}] require transaction", obj.getClass().getSimpleName());
            // 返回代理对象
            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);
            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) {
                    log.debug("[{0}#{1}] invoke params is empty", obj.getClass().getSimpleName(), method.getName());
                    return;
                }
                StringBuilder sb = new StringBuilder();
                for(int i = 0; i < args.length; i++) {
                    if(i > 0) {
                        sb.append(", ");
                    }
                    sb.append(args[i].getClass().getSimpleName()).append(": ").append(args[i]);
                }
                log.debug("[{0}#{1}] invoke params: ", obj.getClass().getSimpleName(), method.getName(), sb.toString());
            }
        }    /**
         * 使用 JDK 动态代理织入事务处理
         * @author frankiegao123
         * 2009-10-30 上午11:56:47
         */
        private static class XAInvocationHandle implements InvocationHandler {        private Object delegate;        public XAInvocationHandle(Object delegate) {
                this.delegate = delegate;
            }        public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                logArguments(delegate, method, args);            if(isRequiredTransaction(method)) {
                    // 需要事务处理
                    log.debug("[{0}#{1}] method require transaction", delegate.getClass().getSimpleName(), method.getName());
                    return invokeWithTransactionRequired(proxy, method, args);
                } else {
                    // 不需要事务处理
                    log.debug("[{0}#{1}] method never transaction", delegate.getClass().getSimpleName(), method.getName());
                    return invokeWithTransactionNever(proxy, method, args);
                }
            }        private Object invokeWithTransactionNever(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) {
                    log.error("[invokeWithTransactionNever] invoke error", e);
                    throw e;
                } finally {
                    if(em != null) {
                        JpaEntityManager.closeEntityManager(em);
                    }
                }
                return obj;
            }        private Object invokeWithTransactionRequired(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();
                    log.info("[{0}#{1}] EntityManager: {2}", delegate.getClass().getSimpleName(), method.getName(), em);
                    log.debug("[{0}#{1}] transaction begin, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
                    obj = method.invoke(delegate, args);
                    log.debug("[{0}#{1}] transaction commit start, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
                    transaction.commit();
                    if(log.isDebugEnabled()) {
                        log.debug("[{0}#{1}] transaction commit end, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
                    }else if(log.isInfoEnabled()){
                        log.info("[{0}#{1}] transaction commit success", delegate.getClass().getSimpleName(), method.getName());
                    }
                } catch (Throwable e) {
                    if(transaction != null && transaction.isActive()) {
                        log.error("[{0}#{1}] transaction rollback start, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
                        transaction.rollback();
                        log.error("[{0}#{1}] transaction rollback ok, isActive: {2}", delegate.getClass().getSimpleName(), method.getName(), transaction.isActive());
                    } else {
                        log.error("[{0}#{1}] transaction is null or transaction is not active", delegate.getClass().getSimpleName(), method.getName());
                    }
                    log.error("[invokeWithTransactionRequired] invoke error", e);
                    throw e;
                } finally {
                    if(em != null) {
                        JpaEntityManager.closeEntityManager(em);
                    }
                }
                return obj;
            }
        }
    }如果是 JDBC 的话,只要把 EntityManager 改成 Connection 就差不多了下面这个是测试类,根据测试代码的 DEBUG 日志输出结果,以及手工加入异常时,JPA 操作均在事务管理之下:public class TransactionTest {    public static void main(String[] args) {
            for(int i = 0; i < 10; i++) {
                new MultiThreadTest().start();
            }
        }    private static class MultiThreadTest extends Thread {
            public void run() {
                for(int i = 0; i < 10; i++) {
                    try {
                        Lottery lottery = new Lottery();
                        lottery.setCode(Thread.currentThread().getName() + "_" + i);
                        Service service = ServiceFactory.getService();
                        GaoTest t = service.process(lottery);
                        System.out.println(t);
                    }catch(Exception e) {
                        e.printStackTrace();
                    }
                }
            }        
        }
    }
      

  9.   

    哈哈····直接给它来个JSP一页面全搞定
      

  10.   

    强烈不建议帖子有散分有讨论技术,这样比较乱嘛。事务的问题,还是按上面楼层的,自己动手管理事务啦。 
    hibernate和ibatis都不能用的话。自己从连接池里拿出connection然后放在ThreadLocal里面自己管理啊。只有这个办法了。 可以写一个工具类嘛,保证一个线程里拿到的Connection是同一个。
      

  11.   

    上面还有人说用connection用单例,hoho。用单例的话,你死都不知道怎么死的。
      

  12.   

    看完我也蛋疼了 万一哪天不让用spring 我也会悲剧了~~
      

  13.   

    写个公用的静态方法获得connection不是更好,用之前先判断是否为空,不为空直接用。
      

  14.   

    呜呜,竟然有公司不准用SSH,倒!
      

  15.   

    DAO层统一调一个获取JDBC connection的接口,比如叫做Connection.java,在这个类中用工厂模式生产connection并以私有变量方式储存,DAO层的类只能通过Connection.java共有方法获取connection,这样可以保证你的事务用的是同一个connection当然更深入下去可以把Connection.java自身设置为单体模式,自己用HashMap存放connection来加连接池的功能......etc
      

  16.   

    不让我用struts2可以接受,不让我用hibernate没有意见。
    不让我用spring,那我只有走人了。
      

  17.   

    要是你走了,接你活的人估计想自杀的,那将比自学ssh还痛苦