Spring中两种编程式事务管理

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring中两种编程式事务管理相关的知识,希望对你有一定的参考价值。

Spring中两种编程式事务管理

在代码中显示调用beginTransaction,commit,rollback等与事务处理相关的方法,这就是编程式事务管理,当只有少数事务操作时,编程式事务管理才比较合理。
编程式事务管理一般有两种:
1-基于底层API的编程式事务管理
2-基于TransactionTemplate的编程式事务管理

基于底层API的编程式事务管理
就是根据PlatformTransactionMananger,TransactionDefinition和TransanctionStatus几个核心接口,通过编程的方式进行事务处理。

1.创建spring应用ch17,在该应用中导入相关jar包,并在mysql中创建数据库spring,并在该数据库中创建表user,编码方式选择utf8,如下所示
在这里插入图片描述
在这里插入图片描述

2.在src目录下创建配置文件applicationContext2,在该配置文件中指定包,使得注解生效,配置数据源,给数据源配置事务管理器。

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定需要扫描的包,使得注解生效-->
   <context:component-scan base-package="com.ch17"/>
    <!--配置数据源-->
    <bean id = "dataSource" class = "org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!--MySQl数据驱动-->
        <property name = "driverClassName" value = "com.mysql.jdbc.Driver"/>
        <!--连接数据库的URL-->
        <property name = "url" value = "jdbc:mysql://localhost:3306/spring?characterEncoding=utf8"/>
        <!--连接数据库的用户名-->
        <property name = "username" value = "root"/>
        <!--连接数据库的密码-->
        <property name = "password" value = "123456" />
    </bean>

    <!--配置JDBC模板-->
    <bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
        <property name = "dataSource" ref = "dataSource"/>
    </bean>

    <!--为数据添加事务管理-->
    <bean id = "txManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name = "dataSource" ref = "dataSource"/>
    </bean>
</beans>

3.在src目录下创建包com.ch17,并在该包中创建数据访问类CodeTransaction,并注解为@Repository(“codeTransaction”)
在该类中使用编程的方式进行数据库事务管理


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
//声明数据访问层注解有效
@Repository("codeTransaction")
public class CodeTransaction {
    @Autowired
    //使用配置文件的JDBC模板
   private JdbcTemplate jdbcTemplate ;
    @Autowired
    //使用数据源事务管理对象
    private DataSourceTransactionManager txManager ;
    public String test(){
        //默认事务定义,例如隔离级别,传播行为等
        TransactionDefinition tf = new DefaultTransactionDefinition() ;
        //开启事务ts
        TransactionStatus ts = txManager.getTransaction(tf) ;
        String message = "执行成功,没有事务回滚!" ;
        try{
            //删除表中数据
            String sql = "delete from user" ;
            //添加数据
            String sql1 = "insert into user value(?,?,?)" ;
            Object [] param1 = {1, "杨敏玲", "女"} ;
            Object [] param2 = {2, "张珂珂", "男"} ;
            Object [] param3 = {3, "王国栋", "男"} ;
            Object [] param4 = {4, "刘海", "男"} ;
            Object [] param5 = {5, "齐超", "男"} ;
            Object [] param6 = {6, "崔丽华", "女"} ;
            Object [] param7 = {7, "张燕娜", "女"} ;
            Object [] param8 = {8, "魏子俊", "男"} ;
            Object [] param9 = {9, "康伟", "男"} ;
            Object [] param10 = {10, "吴丽丽","女"} ;
            Object [] param11 = {11, "赵冠霖", "男"} ;
            Object [] param12 = {12, "智磊","男"} ;
            Object [] param13 = {13, "韩中洋", "男"} ;
            jdbcTemplate.update(sql) ;
            //添加2条数据
            jdbcTemplate.update(sql1,param1) ;
            jdbcTemplate.update(sql1,param2) ;
            jdbcTemplate.update(sql1,param3) ;
            jdbcTemplate.update(sql1,param4) ;
            jdbcTemplate.update(sql1,param5) ;
            jdbcTemplate.update(sql1,param6) ;
            jdbcTemplate.update(sql1,param7) ;
            jdbcTemplate.update(sql1,param8) ;
            jdbcTemplate.update(sql1,param9) ;
            jdbcTemplate.update(sql1,param10) ;
            jdbcTemplate.update(sql1,param11) ;
            jdbcTemplate.update(sql1,param12) ;
            jdbcTemplate.update(sql1,param13) ;
            //提交事务
            txManager.commit(ts) ;
        }catch(Exception e){
            //出现异常,事务回滚
            txManager.rollback(ts) ;
            message = "主键重复,事务回滚!" ;
            System.out.println(e.getMessage()) ;
        }
        return message ;
    }
}

4-在com.ch17包中创建测试类TestCodeTransaction

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestCodeTransaction {
    public static void main(String[] args){
        //初始化Spring容器,加载配置文件
        ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext2.xml") ;
        //获取对象实例
        CodeTransaction ct = (CodeTransaction) appCon.getBean("codeTransaction");
        String result =ct.test() ;
        System.out.println(result) ;
    }
}

5-执行结果如下:
在这里插入图片描述
6-数据库user表中数据如下
在这里插入图片描述

  • 基于TransactionTemplate的编程式事务管理
  • 事务处理的代码散落在业务逻辑代码中,破坏了原有代码的条理性
  • 并且每一个业务方法都包含了类似的启动事务,提交以及回滚事务的代码
  • TransactionTemplate的execute方法有一个TransactionCallback接口类似的参数,
  • 该接口中定义了doInTransaction方法,通常以匿名内部类的形式实现TransactionCallback接口
  • 并在doInTransaction方法中书写业务逻辑代码,在这里可以使用默认的事务提交和回滚规则,
  • 在业务代码中不需要显示的调用任何事务处理的API
  • doInTransaction方法有一个TransactionStatus类型的参数,可以在方法的任何位置调用参数的setRollbackOnly方法将事务标识为回滚,
  • 以执行事务回滚
  • 根据默认规则,如果在执行方法的过程中抛出未检查异常,或者显式调用setRollbackOnly方法,则事务回滚
  • 如果事务执行完成或者抛储checked类型的异常,则提交事务.

1-创建spring应用ch17,在该应用中导入相关jar包,并在mySQL中创建数据库spring,并在该数据库中创建表user,编码方式选择utf8.
2-在src目录下创建配置文件applicationContext3,在该配置文件中指定包,使得注解生效,配置数据源,给数据源配置事务管理器,为事务管理器txManager创建transactionTemplate。

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定需要扫描的包,使得注解生效-->
    <context:component-scan base-package="com.ch17"/>
    <!--配置数据源-->
    <bean id = "dataSource" class = "org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!--MySQl数据驱动-->
        <property name = "driverClassName" value = "com.mysql.jdbc.Driver"/>
        <!--连接数据库的URL-->
        <property name = "url" value = "jdbc:mysql://localhost:3306/spring?characterEncoding=utf8"/>
        <!--连接数据库的用户名-->
        <property name = "username" value = "root"/>
        <!--连接数据库的密码-->
        <property name = "password" value = "123456" />
    </bean>

    <!--配置JDBC模板-->
    <bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
        <property name = "dataSource" ref = "dataSource"/>
    </bean>

    <!--为数据添加事务管理-->
    <bean id = "txManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name = "dataSource" ref = "dataSource"/>
    </bean>

    <!--为事务管理器txManager创建transactionTemplate-->
    <bean id = "transactionTemplate" class = "org.springframework.transaction.support.TransactionTemplate">
        <property name = "transactionManager" ref = "txManager"/>
    </bean>
</beans>

3-在在src目录下创建包com.ch17,在该包中创建数据访问类TransactionTemplateDao,并注解为@Repository(“transactionTemplateDao”)
在该类中通过编程的方式进行事务管理


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

@Repository("transactionTemplateDao")
public class TransactionTemplateDao {
    @Autowired
    //使用配置文件的JDBC模板
    private JdbcTemplate jdbcTemplate ;
    @Autowired
    private TransactionTemplate transactionTemplate ;
    String message = "" ;
    public String test(){
        /**
         * 以匿名内部类的方式实现TransactionCallback接口,使用默认的事务提交和回流规则
         * 在业务代码中不需要显示调用任何事务处理的API
         */
        transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                //删除表中的数据
                String sql = "delete from user" ;
                //添加数据
                String sql1 = "insert into user value(?,?,?)" ;
                Object [] param1 = {1,"王国栋1","男"} ;
                Object [] param2 = {2,"刘海2", "男"} ;
                Object [] param3 = {3,"崔丽娜3","女"} ;
                Object [] param4 = {4,"张燕娜4","女"} ;
                Object [] param5 = {5,"张珂珂","男神"};
                try{
                    //先删除数据
                    jdbcTemplate.update(sql) ;
                    //添加数据
                    jdbcTemplate.update(sql1,param1) ;
                    jdbcTemplate.update(sql1,param2) ;
                    jdbcTemplate.update(sql1,param3) ;
                    jdbcTemplate.update(sql1,param4) ;
                    jdbcTemplate.update(sql1,param5) ;
                    message = "执行成功,没有事务回滚!" ;
                }catch(Exception e){
                    message = "主键重复,事务回滚!" ;
                    System.out.println(e.getMessage())  ;
                }
                return message;
            }
        }) ;
        return message ;
    }
}

4-在com.ch17包中创建测试类TransactionTemplateTest
在该类中获取目标对象的实例,并执行相应的目标方法


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TransactionTemplateTest {
    public static void main(String[] args){
        //初始化Spring容器,加载配置文件
        ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext3.xml") ;
        //获取实例对象
        TransactionTemplateDao transactionTemplateDao = (TransactionTemplateDao) appCon.getBean("transactionTemplateDao");
        String result = transactionTemplateDao.test() ;
        System.out.println(result) ;
    }
}

5-执行结果如下
在这里插入图片描述
6-数据库spring中的user表如下
在这里插入图片描述

以上是关于Spring中两种编程式事务管理的主要内容,如果未能解决你的问题,请参考以下文章

Spring中事务的使用抽象机制及模拟Spring事务实现

Spring_事务

Java EE之SSM框架整合开发 -- Spring的事务管理

Spring的编程式事务和声明式事务

一文解析Spring编程式和声明式事务实例讲解

vue中组件3种编程式路由跳转传参