springboot手动开启事务

推荐 生活 2019-07-07 00:20:56 1895

本文收集整理关于springboot手动开启事务的相关议题,使用内容导航快速到达。

内容导航:

  • Q1:springboot事务异常回滚了,error不回滚,为什么?
  • Q2:spring boot怎么配置编程式事务TransactionTemplate?
  • Q3:SpringBoot整合Mybatis中如何实现事务控制?
  • Q4:SpringBoot如何注解事务声明式事务
  • Q1:springboot事务异常回滚了,error不回滚,为什么?

    新建Spring Boot项目,依赖选择JPA(spring-boot-starter-data-jpa)和Web(spring-bootstarter-web)。
    配置基本属性 在application.properties里配置数据源和jpa的相关属性
    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springboot
    spring.datasource.username=root
    spring.datasource.password=123456、spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true
    spring.jackson.serialization.indent_output=true
    定义映射实体类
    定义Controller类
    @RestControllerpublic class PersonCtroller {
    @Autowired PersonServer personServer;
    @RequestMapping("/rollback")
    public Person rollback(Person person){
    return personServer.savePersonWithRollBack(person);
    }
    @RequestMapping("/norollback")
    public Person noRollback(Person person){
    return personServer.savePersonWithOutRollBack(person);
    }
    }
    定义数据访问层
    public interface PersonRepository extends JpaRepository {}
    定义Server层
    @Servicepublic class PersonServerImp implements PersonServer {
    @Autowired
    PersonRepository personRepository;

    Q2:spring boot怎么配置编程式事务TransactionTemplate?

    一个是TransactionTemplate
    看名字就知道,又是一个类似于RedisTemplate的模板类。使用很简单,是一个回调。
    [java] view plain copy
    transactionTemplate.execute(new TransactionCallback() {
    @Override
    public Object doInTransaction(TransactionStatus transactionStatus) {
    try {
    userRepository.save(user);
    for (int i = 0; i < 10; i++) {
    Post post = new Post();
    if (i == 5) {
    post.setContent("dddddddddddddddddddddddddddddddddddddddddddd");
    } else
    post.setContent("post" + i);
    post.setWeight(i);
    postService.save(post);
    14、

    Q3:SpringBoot整合Mybatis中如何实现事务控制?

    作为一名资深的CURD程序员,事务控制/事务管理是一项不可避免的工作,也是最常见的一项功能,简单说,事务管理就是在执行业务操作时,由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,之前成功操作数据的并不可靠,需要在这种情况下进行回退。

    1、默认的事务管理配置方式:

    在引入相关的依赖之后(比如springboot的web组件依赖、父依赖、mysql驱动依赖以及mybatis依赖等)



    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    1.3.0

    需要在设计service层的时候,将方法用@Transational注解进行注释,默认的话在抛出Exception.class异常的时候,就会触发方法中所有数据库操作回滚。

    而@Transational注解也拥有许多的参数,比如:

    rollbackFor:可以指定需要进行回滚的异常,指定Class对象数组,且该Class必须继承自Throwable;
    value:用于在多数据源的情况下,进行事务管理器的指定(下面描述下多数据源事务这种情况);
    noRollbackFor:有rollbackFor自然有noRollbackFor,顾名思义,用于指定不需要进行回滚的异常;
    readOnly:是读写还是只读事务,默认是false,读写;

    还有许多,不一一描述了....

    实例:

    @Service
    public class TestTransactionalService
    @Autowired
    private TestMapper testMapper;
    @Transactional//当抛出Exception的时候,将进行回滚操作
    public int insertTest(TestEntity testEntity) {
    testEntity.setName("get out! helloService")
    return testMapper.insertOne(testEntity);
    }
    }

    另外,在SpringBoot的启动类中,需要增加@EnableTransactionManagement注解,用于启动事务管理。

    实例:

    @EnableTransactionManagement
    @SpringBootApplication
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }

    至此,SpringBoot整合Mybatis的单数据源的事务管理便配置完成

    2、多数据源的事务配置方式:

    第一种方式基本上满足了普通项目的事务管理功能, 但当项目是比较大型的项目的时候(比如电商项目),可能会存在多个数据源,这时候会出现多个事务管理器,也就需要在声明的时候为不同数据源的数据操作指定不同的事务管理器。

    1)首先,需要引入数据源依赖



    com.alibaba
    druid
    1.0.19

    2)配置properties配置文件(或者yml文件...)

    #主数据源,多数据源的情况下,需要指定主数据源,在后续的config中进行,此时我们将#base数据源作为主数据源来看待~
    spring.datasource.base.jdbc-url=jdbc:mysql://localhost:3306/test1、spring.datasource.base.username=root
    spring.datasource.base.password=root
    spring.datasource.base.driver-class-name=com.mysql.jdbc.Driver
    #从数据源
    spring.datasource.second2.jdbc-url=jdbc:mysql://localhost:3306/test2、spring.datasource.second2.username=root
    spring.datasource.second2.password=root
    spring.datasource.second2.driver-class-name=com.mysql.jdbc.Driver

    3)新增配置类,读取配置文件,进行数据源的配置

    注意,配置类需要对DataSource、DataSourceTransactionManager、SqlSessionFactory 、SqlSessionTemplate四个数据项进行配置;

    其中DataSource类型需要引入javax.sql.DataSource;

    配置主数据源:

    如上文所说,当系统中有多个数据源时,必须有一个数据源为主数据源,在配置类中我们使用@Primary修饰。

    通过@MapperScan注解对指定dao包建立映射,确保在多个数据源下,自动选择合适的数据源,而在service层里不需要做特殊说明,否则需要通过@Transactional的value属性进行指定

    @Configuration
    @MapperScan(basePackages = "com.livinghome.base", sqlSessionTemplateRef = "baseSqlSessionTemplate",sqlSessionFactoryRef = "baseSqlSessionFactory")
    public class BaseDataSourceConfig {
    /**读取base数据源**/
    @Bean(name = "baseDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.base")
    @Primary
    public DataSource setDataSource() {
    return DataSourceBuilder.create().build();
    }
    @Bean(name = "baseTransactionManager")
    @Primary
    public DataSourceTransactionManager setTransactionManager(@Qualifier("baseDataSource") DataSource dataSource) {
    return new DruidDataSource();
    }
    @Bean(name = "baseSqlSessionFactory")
    @Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("baseDataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/base/*.xml"));
    return bean.getObject();
    }
    @Bean(name = "baseSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("baseSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

    配置从数据源:

    @Configuration
    @MapperScan(basePackages = "com.livinghome.second2", sqlSessionTemplateRef = "zentaoSqlSessionTemplate",sqlSessionFactoryRef = "zentaoSqlSessionFactory")
    public class Second2DataSourceConfig {
    @Bean(name = "second2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second2")
    public DataSource setDataSource() {
    return new DruidDataSource();
    }
    @Bean(name = "second2TransactionManager")
    public DataSourceTransactionManager setTransactionManager(@Qualifier("second2DataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
    }
    @Bean(name = "second2SqlSessionFactory")
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("second2DataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/second2/*.xml"));
    return bean.getObject();
    }
    @Bean(name = "second2SqlSessionTemplate")
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("second2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }

    4)到了这里,我们基本的多数据源事务管理便已经完成了(真的)....

    对于service层,不需要进行事务管理器的指定,因为我们上面使用了@MapperScan进行了包指定,当然也可以手动指定,方式便是 @Transactional(transactionManager="baseTransactionManager")

    便可手动指定为base数据源。

    另外,还有分布式事务管理,也就是在一次操作中,操作了不同的数据源的情况,对于service而言,便是在一次service里调用了两个数据源的方法,这种情况常见于微服务架构中,例如电商系统(第二次使用电商系统举例..)。

    从百度上copy了一个简单的下单流程:

    在微服务中,2、3、4步骤是涉及了3个系统以及3个数据库的,当某个操作出现问题时,会出现多数据源的事务管理问题,传统的方式是通过将不同数据源的事务都注册到一个全局事务中(可以通过jpa+atomikos来进行),但有大神告诉我这种方式性能差,具体还未有实践,不是很清楚。

    我说完了... 因为对微服务架构学习还在进行中,所以对于分布式事务问题我还没有太多的理解和实践,等我回来....

    同时,欢迎大神为我指点明路!!

    ——没事待在家里不出门的 居家程序员。(我不想脱发!)

    Q4:SpringBoot如何注解事务声明式事务

    springboot的事务也主要分为两大类,

    一是xml声明式事务,

    二是注解事务,注解事务也可以实现类似声明式事务的方法,

    springboot 之 xml事务

    使用 @ImportResource("classpath:transaction.xml") 引入该xml的配置

    springboot 注解事务

    Transactional注解事务

    注:需要在进行事物管理的方法上添加注解@Transactional,或者偷懒的话直接在类上面添加该注解

    注解声明式事务

    @Configuration
    public class TxConfigBeanName {
    @Autowired
    private DataSourceTransactionManager transactionManager;
    // 创建事务通知
    @Bean(name = "txAdvice")
    public TransactionInterceptor getAdvisor() throws Exception {
    Properties properties = new Properties();
    properties.setProperty("get*", "PROPAGATION_REQUIRED,-Exception,readOnly");
    properties.setProperty("add*", "PROPAGATION_REQUIRED,-Exception,readOnly");
    properties.setProperty("save*", "PROPAGATION_REQUIRED,-Exception,readOnly");
    properties.setProperty("update*", "PROPAGATION_REQUIRED,-Exception,readOnly");
    properties.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception,readOnly");
    TransactionInterceptor tsi = new TransactionInterceptor(transactionManager,properties);
    return tsi;
    }
    @Bean
    public BeanNameAutoProxyCreator txProxy() {
    BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
    creator.setInterceptorNames("txAdvice");
    creator.setBeanNames("*Service", "*ServiceImpl");
    creator.setProxyTargetClass(true);
    return creator;
    }
    }

    相关文章
    启动网络发现 开启不了2019-01-12
    汽车加油怎样开启油箱2019-01-15
    谷歌浏览器弹窗禁止后怎么开启2019-01-21
    小米手机怎样开启定位2019-01-29
    电脑怎么开启远程协助2019-01-30
    开启开发者选项在哪里2019-01-31
    如何开启无线网络连接2019-02-09
    苹果手机健康怎么开启2019-02-11
    电脑如何开启远程控制2019-02-13
    手机怎样开启root权限2019-02-15