spring 声明式事务

发布于:2025-09-14 ⋅ 阅读:(19) ⋅ 点赞:(0)

未添加事务测试

mapper配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.cht.dao.StudentDao">

    <resultMap id="StudentMap" type="com.cht.model.Student">
        <id property="studentId" column="s_id"/>
        <result property="studentNm" column="s_nm"/>
        <result property="age" column="s_age"/>
        <result property="score" column="s_score"/>
    </resultMap>
    
    <select id="queryStudentList" resultMap="StudentMap">
        select s_id,s_nm,s_age,s_score from student
    </select>

    <insert id="addUser" parameterType="com.cht.model.Student" useGeneratedKeys="true" keyProperty="studentId">
        insert into student (s_nm,s_age,s_score) values (#{studentNm},#{age},#{score})
    </insert>

    <delete id="deletUser" parameterType="int">
        delete from student where s_id = #{studeId}
    </delete>

</mapper>

接口:

public interface StudentDao {

    List<Student> queryStudentList();

    void addUser(Student student);

    void deletUser(@Param("studentId") int studentId);
}

实现类:

public class StudentDaoImpl implements StudentDao {

    private static final Logger logger = LoggerFactory.getLogger(StudentDaoImpl.class);

    /**
     * spring容器引用对象注入
     */
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<Student> queryStudentList() {
        StudentDao mapper = sqlSessionTemplate.getMapper(StudentDao.class);
        Student student = new Student("小强123", 19, 88);
        addUser(student);
        logger.info("插入成功:{}", student);
        deletUser(student.getStudentId());
        return mapper.queryStudentList();
    }

    @Override
    public void addUser(Student student) {
        StudentDao mapper = sqlSessionTemplate.getMapper(StudentDao.class);
        mapper.addUser(student);
    }

    @Override
    public void deletUser(int studentId) {
        StudentDao mapper = sqlSessionTemplate.getMapper(StudentDao.class);
        mapper.deletUser(studentId);
    }


}

测试类:

public class Test {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 动态代理获取接口的代理类
        StudentDao studentDao = applicationContext.getBean("studentDaoImpl", StudentDao.class);
        List<Student> students = studentDao.queryStudentList();
        for (Student student : students) {
            System.out.println(student);
        }
    }
}

测试验证:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@319bc845] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1bdf8190] will not be managed by Spring
==>  Preparing: insert into student (s_nm,s_age,s_score) values (?,?,?)
==> Parameters: 小强123(String), 19(Integer), 88(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@319bc845]
2025-09-13 17:56:01 [main] INFO  com.cht.Impl.StudentDaoImpl - 插入成功:Student(studentId=10045, studentNm=小强123, age=19, score=88)
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@560513ce] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@37fbe4a8] will not be managed by Spring
==>  Preparing: delete from student where s_id = ?
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@560513ce]
Exception in thread "main" org.mybatis.spring.MyBatisSystemException: 
### Error updating database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'studeId' not found. Available parameters are [studentId, param1]

未配置事务时,执行查询方法中当删除报错时,新增还是会执行成功。我们期望的是如果删除失败则新增失败,要保证数据的原子性

spring声明式事务

基于aop实现,切记导入aop织入依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.22.1</version>
    <scope>runtime</scope>
</dependency>
<!-- AspectJ运行时核心库 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.22.1</version>
</dependency>

在spring容器中配置事务

    <!-- 注入事务管理 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="driverManagerDataSource"/>
    </bean>

    <!-- 事务通知 -->
    <tx:advice id="transactionAdvice">
        <tx:attributes>
            <!-- * 所有方法 ;propagation 传播行为一般都是用REQUIRED -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!-- 事务生效的切入点 -->
    <aop:config>
        <aop:pointcut id="cut" expression="execution(* com.cht.Impl.StudentDaoImpl.*(..))"/>
        <aop:advisor advice-ref="transactionAdvice" pointcut-ref="cut"/>
    </aop:config>

再次测试验证:

从数据库查询,并未查询到插入的这条记录,事务生效。

当开启事务时,创建sqlSession时,会先注册一个事务,开启事务后续的释放事务,以及如何实现回滚的后续再补充吧。

开启事务和未开启事务 最突出的不同点:

开启事务后,日志里会有“Registering transaction synchronization for SqlSession” 。