关于Spring声明式事务细节问题请教

53 阅读1分钟

最近在看狂神Spring视频,后面看到事务部分,我在原来的基础上进行了业务层级的修改,由视频里的userMapperImpl修改成公司中常用的service层:

  • service: UserService
    • impl: UserServceImpl

发现事务没有生效。详情请往下看:

项目层级

image.png

Mapper

public interface UserMapper {

    @Select("select * from user where id = #{id}")
    User getById(Integer id);

    @Insert("insert into user(id, userCode, userName) values(#{id}, #{userCode}, #{userName})")
    Integer addUser(User user);

    @Delete("deletes from user where id = #{id}")
    Integer deleteById(Integer id);

    @Select("select * from user")
    List<User> selectList();
}
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {

    @Override
    public User getById(Integer id) {
        return getSqlSession().getMapper(UserMapper.class).getById(id);
    }

    @Override
    public Integer addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    @Override
    public Integer deleteById(Integer id) {
        return getSqlSession().getMapper(UserMapper.class).deleteById(id);
    }

    @Override
    public List<User> selectList() {

        User user = new User();
        user.setId(1001);
        user.setUserCode("xiaowang");
        user.setUserName("小王");

        UserMapper userMapper = getSqlSession().getMapper(UserMapper.class);
        userMapper.addUser(user);
        userMapper.deleteById(1001);

        return userMapper.selectList();
    }
}

Service

public interface UserService {

    User getById(Integer id);

    Integer addUser(User user);

    Integer deleteById(Integer id);

    List<User> selectList();
}
public class UserServiceImpl implements UserService {

    private SqlSessionTemplate sqlSession;
    private UserMapper userMapper;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
        this.userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Override
    public User getById(Integer id) {
//        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        return userMapper.getById(id);
    }

    @Override
    public Integer addUser(User user) {
        return userMapper.addUser(user);
    }

    @Override
    public Integer deleteById(Integer id) {
        return userMapper.deleteById(id);
    }

    @Override
    public List<User> selectList() {

        User user = new User();
        user.setId(1001);
        user.setUserCode("xiaowang");
        user.setUserName("小王");

        userMapper.addUser(user);
        userMapper.deleteById(1001);

        return userMapper.selectList();
    }
}

XML配置

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/aop  
    https://www.springframework.org/schema/aop/spring-aop.xsd">  
  
    <!-- dataSource -->  
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />  
        <property name="username" value="root" />  
        <property name="password" value="123456" />  
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/spring-mybatis" />  
    </bean>  
  
    <!-- SqlSessionFactory -->  
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  
        <property name="configuration">  
            <bean class="org.apache.ibatis.session.Configuration">  
                <property name="mapUnderscoreToCamelCase" value="true" />  
                <property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl" />  
                <property name="defaultStatementTimeout" value="28800" />  
            </bean>  
        </property>  
        <property name="mapperLocations" value="classpath*:com/lw/**/mapper/xml/*.xml" />  
    </bean>  
    
    <!-- SqlSessionTemplate: 就是我们使用的SqlSession -->  
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />  
    </bean>  
  
    <bean id="userService" class="com.lw.service.impl.UserServiceImpl" >  
        <property name="sqlSession" ref="sqlSession" />  
    </bean>  
  
    <bean id="userMapper" class="com.lw.mapper.UserMapperImpl">  
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />  
    </bean>  
  
    <!-- 配置声明式事务:Spring事务 -->  
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <constructor-arg ref="dataSource" />  
    </bean>  
    
    <!-- 结合AOP实现事务的织入 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" />  
        </tx:attributes>  
    </tx:advice>  

    <!-- 配置事务切入 -->  
    <aop:config>  
        <aop:pointcut id="txPointCut" expression="execution(* com.lw.mapper.*.*(..)) || execution(* com.lw.service.*.*(..))"/>  
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />  
    </aop:config>
</beans>

测试

@Test  
public void test1() {  
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
    UserMapper userMapper = context.getBean("userMapper", UserMapper.class);  
    List<User> users = userMapper.selectList();  
    for (User user : users) {  
        System.out.println(user);  
    }  
}  
  
@Test  
public void test2() {  
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
    UserService userService = context.getBean("userService", UserService.class);  
    List<User> users = userService.selectList();  
    for (User user : users) {  
        System.out.println(user);  
    }  
}

事务失效情况

UserMapper中的delete方法故意写错, 当XML配置中的切入点只扫描mapper下的方法时:execution(* com.lw.mapper.*.*(..)), test1事务生效回滚没有插入数据,test2在报错的情况下依旧是插入了新数据。

当修改切入点:execution(* com.lw.service.*.*(..)),test2事务生效回滚,没有插入新数据。

UserServiceImpl本质是调用了UserMapper,当切入点只配置:execution(* com.lw.mapper.*.*(..))时,为什么调用service的方法事务不会生效呢?