代码之家  ›  专栏  ›  技术社区  ›  James

除非在DAO内部,否则事务不工作

  •  0
  • James  · 技术社区  · 14 年前

    我对事务有一个问题,那就是用@transactional来注释调用DAO的服务会引发一个异常,说明会话没有打开。我唯一能让它工作的方法是用@transactional注释DAO。究竟会发生什么?

    这是我想做但不起作用的事情:

    class CustomerService {
        private CustomerDao dao;
    
        @Transactional
        public void foo() {
            int customerId = dao.getCustomer("fred");
        }
    }
    
    class CustomerDao {
        private HibernateTemplate hibernateTemplate;
    
        public int getCustomer(String name) {
            String sql = "SELECT {m.*} from Customers {m} where name=:name";
            Query qry = getSession().createSQLQuery(sql).addEntity("m", Customer.class);
            qry.setParameter("name", name);
            qry.setCacheable(false);
            List<Customer> list = qry.list();
            return list.iterator().next().getId();
        }
    
        private Session getSession() {
            return hibernateTemplate.getSessionFactory().getCurrentSession();
        }
    }
    

    这是我正在做的,但我不想:

    class CustomerService {
        private CustomerDao dao;
    
        public Customer(CustomerDao dao) {
            this.dao = dao;
        }
    
        public void foo() {
            int customerId = dao.getCustomer("fred");
        }
    }
    
    class CustomerDao {
        private HibernateTemplate hibernateTemplate;
    
        @Transactional
        public int getCustomer(String name) {
            String sql = "SELECT {m.*} from Customers {m} where name=:name";
            Query qry = getSession().createSQLQuery(sql).addEntity("m", Customer.class);
            qry.setParameter("name", name);
            qry.setCacheable(false);
            List<Customer> list = qry.list();
            return list.iterator().next().getId();
        }
    
        private Session getSession() {
            return hibernateTemplate.getSessionFactory().getCurrentSession();
        }
    }
    

    该问题似乎是由包装类的构造函数中实例化的CustomerService引起的,包装在SpringXML上下文文件中声明:

    class AllServices {
        private final CustomerService customerService;
        private final OrderService orderService;
    
        @Autowired
        public AllServices(CustomerDao customerDao, OrderDao orderDao) {
            this.customerService = new CustomerService(customerDao);
            this.orderService = new OrderService(orderDao);
        }
    
        public CustomerService getCustomerService() {
            return this.customerService;
        }
    
        public OrderService getOrderService() {
            return this.orderService;
        }
    }
    

    Spring文件如下所示:

    <context:annotation-config />
    <import resource="classpath:db-spring-conf.xml"/>
    <bean id="allServices" class="myPackage.AllServices" />
    

    以及DB Spring配置:

    <bean id="editorDatasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="${versioning.db}" />
        <property name="username" value="${versioning.user}" />
        <property name="password" value="${versioning.pass}" />
    </bean>
    
    <tx:annotation-driven transaction-manager="editorTransactionManager"/>
    
    <bean id="editorSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="editorDatasource"/>
        <property name="exposeTransactionAwareSessionFactory">
            <value>true</value>
        </property>
        <property name="annotatedClasses">
            <list>
                <value>myPackage.Order</value>
            </list>
        </property> 
        <property name="mappingResources">
            <list>
                <value>mappings/customer.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">validate</prop>
                <!-- Enable Query Cache -->
                <prop key="hibernate.cache.use_query_cache">false</prop>
                <!-- Enable 2nd Level Cache -->
                <prop key="hibernate.cache.use_second_level_cache">false</prop>
                <prop key="hibernate.connection.autocommit">false</prop>
                <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate3.SpringSessionContext</prop>
            </props>
        </property>
    </bean>
    
    <bean id="editorHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="editorSessionFactory"/>
    </bean>
    
    <bean id="editorTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="editorSessionFactory" />
    </bean>
    
    <!-- DAOs -->
    <bean id="customerDao" class="myPackage.CustomerHibernateDao" />
    <bean id="orderDao" class="myPackage.OrderHibernateDao" />
    

    现在,我已经将CustomerService的实例化移到了Spring配置文件中,一切都很好。使用@transactional的所有类都必须在上下文文件中吗?此外,为了使其正常工作,我必须为CustomerService创建一个接口,以防止在加载上下文文件时出现异常。- Could not generate CGLIB subclass of class

    1 回复  |  直到 12 年前
        1
  •  2
  •   axtavt    12 年前

    所以,你确定了问题的原因-弹簧 @Transactional 支持是一个方面,Spring中的方面仅应用于由Spring Contriner管理的组件(尽管它 can be changed 但是对于复杂的情况来说,它是一个高级特性)。

    如果您不喜欢用XML声明服务,您可以查看delcare spring托管组件的其他选项:

    关于cglib代理的问题,请参阅 7.6 Proxying mechanisms -可能在类路径中没有cglib实现。