spring的声名式事务,是不是那个事务代理拦截了哪个类,哪个类内的所有操作就是一个事务了?
我做了一个试验,好像我理解的不对,或者是我代码写的不对,兄弟们帮忙看一下,谢谢。
spring配置文件:
 
    <bean id="dao" class="last.soul.dao.DAOImpl">
     <property name="sqlMapClient" ref="sqlMapClient"></property>
    </bean>
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
        <property name="dataSource">   
            <ref bean="dataSource" />   
        </property>   
    </bean>   
    <!-- 利用spring的TransactionProxyFactoryBean去对事务进行自动管理 -->        
    <bean id="daoTr"  
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">   
        <property name="transactionManager">   
            <ref local="transactionManager" />   
        </property>   
        <property name="target">   
            <ref local="dao" />   
        </property>   
        <property name="transactionAttributes">   
            <props>   
                <prop key="select*">PROPAGATION_REQUIRED</prop>   
                <prop key="update*">PROPAGATION_REQUIRED</prop>   
            </props>   
        </property>   
    </bean>  
下面是last.soul.dao.DAOImpl的代码:public List selectByName(String username) throws SQLException
{
List list;
String sql="user.selectByName";
HashMap map=new HashMap();
map.put("username", username);
System.out.println("-------selectByName inVoke----------");


list = sqlMapClient.queryForList(sql, map);
try {

User u1=new User();
u1.setEmail("[email protected]");
u1.setPassword("he2");
u1.setUsername("us2e");
sqlMapClient.insert("user.insert", u1);
User u2=new User();
u2.setEmail("[email protected]");
u2.setPassword("he");
u2.setUsername(null);
sqlMapClient.insert("user.insert", u2);
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
我做了两次插入的操作,第二次我故意让他异常,但我去数据库里看,发现第一条记录插入成功了,也就是说它为什么不回滚事务呢?哪位给解释下,谢谢。

解决方案 »

  1.   

    并不是那个事务代理拦截了哪个类,哪个类内的所有操作就是一个事务了,还要看能看<property name="transactionAttributes">   
                <props>   
    的配置,向你的配置倒是包含了selectByName方法,但你在selectByName方法中抛的异常都给抓到了,然后又没向外抛,spring就认为是正确执行了,所以不会回滚啊,如果出现sql异常你要把他跑出去,并且把   <prop key="select*">PROPAGATION_REQUIRED</prop>   改成
       <prop key="select*">PROPAGATION_REQUIRED, -SQLException</prop> (假设你把SQLException抛出去了)
      

  2.   

    第一,不应该抓DAO,DAO部分处理数据库操作逻辑,不需要关心抛错和事物
    spring应该指定service层的事务处理
    第二,为什么你的select方法也指定成需要事务?这是没必要的给你看下我常用的配置,不过是spring2的,用的是正则匹配 <!-- 事务处理定义 -->
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="find*" read-only="true" />
    <tx:method name="get*" read-only="true" />
    <tx:method name="set*" read-only="true" />
    <tx:method name="*" />
    </tx:attributes>
    </tx:advice>
    <aop:config>
    <aop:pointcut id="daoOperation" expression="execution(* web.service.impl.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperation" />
    </aop:config>再给一段MVC部分的示例
    dao部分public DAO {
    public void save(POJO po) {
    getHibernateTemplate().save(po);
    }
    }service部分public SERVICE {
    private DAO dao;
    public void setDao(DAO dao){
    this.dao = dao;
    }
    public DAO getDao() {
    return this.dao;
    }
    public void save(POJO po) {
    dao.save(po);
    }
    }action部分public class ACTION {
    private SERVICE service;
    public void setService(SERVICE service){
    this.service = service;
    }
    public SERVICE getService() {
    return this.service;
    }
    public String execute() {
    // do something
    // service.save(po);
    }
    }
      

  3.   


    我按你的配置做了,类也做了相应的修改,去了TRY/CATCH,下面的JAVA类,我是这样写的。public List selectByName(String username) throws SQLException
    {
    try {
    User u1=new User();
    u1.setEmail("[email protected]");
    u1.setPassword("he4");
    u1.setUsername("us3e");
    sqlMapClient.insert("user.insert", u1);

    User u2=new User();
    u2.setEmail("[email protected]");
    u2.setPassword("he");
    u2.setUsername(null);
    sqlMapClient.insert("user.insert", u2);
    } catch (SQLException e) {
    throw e;
    }
    return null;
    }但依然和原来一样,第一条数据插入成功,其中CATCH里面的那行去掉也一样。或者把整个TRY/catch去掉,结果还是一样。
      

  4.   

    还有一个问题,我把SPRING中事务的配置去掉了,采用IBATIS的手动事务,还是会插入一条数据,郁闷啊。下面是我手动事务的代码。public List selectByName(String username) throws SQLException
    {
    List list;
    String sql="user.selectByName";
    HashMap map=new HashMap();
    map.put("username", username);
    System.out.println("-------selectByName inVoke----------");

    list = sqlMapClient.queryForList(sql, map);

    try {
    sqlMapClient.startTransaction();
    User u1=new User();
    u1.setEmail("[email protected]");
    u1.setPassword("he4");
    u1.setUsername("us4e");
    sqlMapClient.insert("user.insert", u1);
    User u2=new User();
    u2.setEmail("[email protected]");
    u2.setPassword("he");
    u2.setUsername(null);
    sqlMapClient.insert("user.insert", u2);
    }finally{
    sqlMapClient.endTransaction();
    }
    return list;
    }
      

  5.   

    回2楼的朋友,我知道你的意思,我只是图个方便,只是要测试一下事务的配置,所以才对DAO进行事务管理,而且SELECTBYNAME方法里面我做的是插入操作,还有一点你说的意思是不是说一楼说的不对,不是抛异常的问题?
      

  6.   

    我说过了 事务处理不应该在DAO上进行,至少spring的事务模型对于DAO的操作时没有效果
    txManager需要service层才行
      

  7.   

    dao或者 service层,这个只是人为的定义吧,你说的有道理是应该在SERVICE层上进行事务管理,但我就是想测试一下,spring它知道我是dao层,所以他没有效果?它是怎么知道我是dao层的?这个怎么界定
      

  8.   

    <prop key="select*">PROPAGATION_REQUIRED</prop>   
    <prop key="update*">PROPAGATION_REQUIRED</prop>   你没配 insert*吧
      

  9.   

    默认是runtimeexception,而你的是sqlexception
    刚学,不知道说的对不对
      

  10.   

    <prop key="select*">PROPAGATION_REQUIRED</prop>  改为:<prop key="select*">PROPAGATION_REQUIRED,-Exception</prop>  
      

  11.   

    若楼上
    如果你的抛出的异常是CheckException,你配置事物的时候必须加上 -Exception参数,指定出现Checked异常时回滚,也就是PROPAGATION_REQUIRED,-Exception
      

  12.   

     <bean id="dao" class="last.soul.dao.DAOImpl"  parent="transactionAttributes" >
            <property name="sqlMapClient" ref="sqlMapClient"></property>
       </bean>加上这句试试
      

  13.   

    这样当然起不来了啊,你又没有配置一个bean叫做transactionAttributes,这里parent的意思是父bean。