环境
  eclipse 4.7
  jdk 1.8
  Spring Boot 1.5.2

一、springboot整合事务
事务分类:编程事务、声明事务(XML、注解),推荐使用注解方式,springboot默认集成事物,只主要在方法上加上@Transactional即可
1、controller

package com.wjy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import com.wjy.test1.service.UserServiceTest1; @RestController
public class UserController { @Autowired
public UserServiceTest1 userServiceTest1; @RequestMapping("/insertTest1ByService")
public String insertTest1ByService(String name,Integer age) {
userServiceTest1.insertuser1(name, age);
return "success";
} }

2、service

/**
*
*/
package com.wjy.test1.service; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.wjy.test1.dao.UserMapperTest1; /**
* @Desc
* @author wangjy15
*/
@Service
public class UserServiceTest1 { @Autowired
private UserMapperTest1 userMapperTest1; /**
* @Description: 如果没有事务控制 那么报错之后 插入到库里的数据不会回滚 加上 注解@Transactional 就可以回滚
*/
@Transactional
public String insertuser1(String name,Integer age) {
userMapperTest1.insert(name, age);
int i =1/0;
return "success";
} }

3、mapper

/**
*
*/
package com.wjy.test1.dao; import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import com.wjy.entity.User; /**
* @Desc
* @author wangjy15
*/
public interface UserMapperTest1 { @Select("SELECT * FROM users WHERE NAME = #{name}")
User findByName(@Param("name") String name); @Insert("insert into users (name,age) values(#{name},#{age})")
int insert(@Param("name") String name,@Param("age") Integer age);
}

4、APP

package com.wjy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class APP { public static void main(String[] args) {
SpringApplication.run(APP.class, args);
} }

5、测试验证

http://localhost:8080/insertTest1ByService?name=wangsan0010&age=1000

二、SpringBoot分布式事务管理

使用springboot+jta+atomikos分布式事务管理,service层有事务控制,dao层没有,一般情况下都需要调用其他数据源的dao层,这就需要进行分布式事务管理。
将多个数据源注册到atomikos进行管理,进行2PC(Two-phaseCommit)二阶段提交。

理解一下分布式事务:

对于上面一中示例做一下修改,再引入一个数据源test2,修改一下service:

/**
*
*/
package com.wjy.test1.service; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.wjy.test1.dao.UserMapperTest1;
import com.wjy.test2.dao.UserMapperTest2;
import com.wjy.test2.service.UserServiceTest2; /**
* @Desc
* @author wangjy15
*/
@Service
public class UserServiceTest1 { @Autowired
private UserMapperTest1 userMapperTest1; @Autowired
private UserMapperTest2 userMapperTest2; @Autowired
private UserServiceTest2 userServiceTest1; /**
* @Desc: 如果没有事务控制 那么报错之后 插入到库里的数据不会回滚 加上 注解@Transactional 就可以回滚
*/
@Transactional
public String insertuser1(String name,Integer age) {
userMapperTest1.insert(name, age);
userServiceTest1.insertuser2(name, age);//有事务控制 可以回滚
int i =1/0;
return "success";
} }
/**
*
*/
package com.wjy.test2.service; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional; import com.wjy.test2.dao.UserMapperTest2; /**
* @Desc
* @author wangjy15
*/
public class UserServiceTest2 {
@Autowired
private UserMapperTest2 userMapperTest2; /**
* @Desc: 如果没有事务控制 那么报错之后 插入到库里的数据不会回滚 加上 注解@Transactional 就可以回滚
*/
@Transactional
public String insertuser2(String name,Integer age) {
userMapperTest2.insert(name, age);
return "success";
} }

这时test1数据库里没有插入数据,test2数据库也没有插入数据库,因为test2在service层也有事务控制。

再修改一下test1 service:

/**
*
*/
package com.wjy.test1.service; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.wjy.test1.dao.UserMapperTest1;
import com.wjy.test2.dao.UserMapperTest2;
import com.wjy.test2.service.UserServiceTest2; /**
* @Desc
* @author wangjy15
*/
@Service
public class UserServiceTest1 { @Autowired
private UserMapperTest1 userMapperTest1; @Autowired
private UserMapperTest2 userMapperTest2;
/**
* @Desc: 如果没有事务控制 那么报错之后 插入到库里的数据不会回滚 加上 注解@Transactional 就可以回滚
*/
@Transactional
public String insertuser1(String name,Integer age) {
userMapperTest1.insert(name, age);
userMapperTest2.insert(name, age);//没有事务控制 不可以回滚 int i =1/0;
return "success";
} }

这时test1数据库里没有插入数据,test2数据库有数据插入到数据库  没有回滚,因为test2在mapper层也没有事务控制。

下面引入atomikos  和springboot整合:

1、数据源配置信息

引入依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
# Mysql 1
mysql.datasource.test1.url = jdbc:mysql://192.168.118.102:3306/springboot?useSSL=false&autoReconnect=true&useUnicode=true&characterEncoding=utf-8
mysql.datasource.test1.username = root
mysql.datasource.test1.password = 123456 mysql.datasource.test1.minPoolSize = 3
mysql.datasource.test1.maxPoolSize = 25
mysql.datasource.test1.maxLifetime = 20000
mysql.datasource.test1.borrowConnectionTimeout = 30
mysql.datasource.test1.loginTimeout = 30
mysql.datasource.test1.maintenanceInterval = 60
mysql.datasource.test1.maxIdleTime = 60
mysql.datasource.test1.testQuery = select 1 # Mysql 2
mysql.datasource.test2.url =jdbc:mysql://192.168.118.102:3306/springboot2?useSSL=false&autoReconnect=true&useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =123456 mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60
mysql.datasource.test2.testQuery = select 1

2、数据源配置类

package com.wjy.datasource;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix="mysql.datasource.test1")
public class DBConfig1 { private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMinPoolSize() {
return minPoolSize;
}
public void setMinPoolSize(int minPoolSize) {
this.minPoolSize = minPoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getMaxLifetime() {
return maxLifetime;
}
public void setMaxLifetime(int maxLifetime) {
this.maxLifetime = maxLifetime;
}
public int getBorrowConnectionTimeout() {
return borrowConnectionTimeout;
}
public void setBorrowConnectionTimeout(int borrowConnectionTimeout) {
this.borrowConnectionTimeout = borrowConnectionTimeout;
}
public int getLoginTimeout() {
return loginTimeout;
}
public void setLoginTimeout(int loginTimeout) {
this.loginTimeout = loginTimeout;
}
public int getMaintenanceInterval() {
return maintenanceInterval;
}
public void setMaintenanceInterval(int maintenanceInterval) {
this.maintenanceInterval = maintenanceInterval;
}
public int getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(int maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
public String getTestQuery() {
return testQuery;
}
public void setTestQuery(String testQuery) {
this.testQuery = testQuery;
} }
package com.wjy.datasource;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix="mysql.datasource.test2")
public class DBConfig2 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery; public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMinPoolSize() {
return minPoolSize;
}
public void setMinPoolSize(int minPoolSize) {
this.minPoolSize = minPoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getMaxLifetime() {
return maxLifetime;
}
public void setMaxLifetime(int maxLifetime) {
this.maxLifetime = maxLifetime;
}
public int getBorrowConnectionTimeout() {
return borrowConnectionTimeout;
}
public void setBorrowConnectionTimeout(int borrowConnectionTimeout) {
this.borrowConnectionTimeout = borrowConnectionTimeout;
}
public int getLoginTimeout() {
return loginTimeout;
}
public void setLoginTimeout(int loginTimeout) {
this.loginTimeout = loginTimeout;
}
public int getMaintenanceInterval() {
return maintenanceInterval;
}
public void setMaintenanceInterval(int maintenanceInterval) {
this.maintenanceInterval = maintenanceInterval;
}
public int getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(int maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
public String getTestQuery() {
return testQuery;
}
public void setTestQuery(String testQuery) {
this.testQuery = testQuery;
} }
package com.wjy.datasource;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; ////注册到springboot容器中
@Configuration
////@MapperScan可以指定要扫描的Mapper类的包的路径 sqlSessionFactoryRef 表示定义了 key ,表示一个唯一 SqlSessionFactory 实例
@MapperScan(basePackages="com.wjy.test1",sqlSessionFactoryRef="sqlSessionFactory1")
public class TestMyBatisConfig1 { @Bean(name="dataSource1")
@Primary
public DataSource dataSource1(DBConfig1 dbConfig1) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(dbConfig1.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(dbConfig1.getPassword());
mysqlXaDataSource.setUser(dbConfig1.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("dataSource1"); xaDataSource.setMinPoolSize(dbConfig1.getMinPoolSize());
xaDataSource.setMaxPoolSize(dbConfig1.getMaxPoolSize());
xaDataSource.setMaxLifetime(dbConfig1.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(dbConfig1.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(dbConfig1.getLoginTimeout());
xaDataSource.setMaintenanceInterval(dbConfig1.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(dbConfig1.getMaxIdleTime());
xaDataSource.setTestQuery(dbConfig1.getTestQuery());
return xaDataSource;
} //注意 这里没有事务管理类 因为事务全部交给AtomikosDataSourceBean来管理 @Primary
@Bean(name = "sqlSessionFactory1")
public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
} @Primary
@Bean(name = "sqlSessionTemplate1")
public SqlSessionTemplate sqlSessionTemplate1(
@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
} }
package com.wjy.datasource;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; @Configuration
@MapperScan(basePackages="com.wjy.test2",sqlSessionFactoryRef="sqlSessionFactory2")
public class TestMyBatisConfig2 { @Bean(name="dataSource2")
public DataSource dataSource2(DBConfig2 dbConfig2) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(dbConfig2.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(dbConfig2.getPassword());
mysqlXaDataSource.setUser(dbConfig2.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("dataSource2"); xaDataSource.setMinPoolSize(dbConfig2.getMinPoolSize());
xaDataSource.setMaxPoolSize(dbConfig2.getMaxPoolSize());
xaDataSource.setMaxLifetime(dbConfig2.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(dbConfig2.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(dbConfig2.getLoginTimeout());
xaDataSource.setMaintenanceInterval(dbConfig2.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(dbConfig2.getMaxIdleTime());
xaDataSource.setTestQuery(dbConfig2.getTestQuery());
return xaDataSource;
} //注意 这里没有事务管理类 因为事务全部交给AtomikosDataSourceBean来管理 @Bean(name = "sqlSessionFactory2")
public SqlSessionFactory sqlSessionFactory2(@Qualifier("dataSource2") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
} @Bean(name = "sqlSessionTemplate2")
public SqlSessionTemplate sqlSessionTemplate2(
@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

3、controller

package com.wjy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import com.wjy.test1.service.UserServiceTest1; @RestController
public class UserController { @Autowired
public UserServiceTest1 userServiceTest1; @RequestMapping("/insertTest1ByService")
public String insertTest1ByService(String name,Integer age) {
userServiceTest1.insertuser1(name, age);
return "success";
} }

4、service

/**
*
*/
package com.wjy.test1.service; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.wjy.test1.dao.UserMapperTest1;
import com.wjy.test2.dao.UserMapperTest2; /**
* @Desc
* @author wangjy15
*/
@Service
public class UserServiceTest1 { @Autowired
private UserMapperTest1 userMapperTest1; @Autowired
private UserMapperTest2 userMapperTest2; /**
* @Desc: 如果没有事务控制 那么报错之后 插入到库里的数据不会回滚 加上 注解@Transactional 就可以回滚
*/
@Transactional
public String insertuser1(String name,Integer age) {
userMapperTest1.insert(name, age);
userMapperTest2.insert(name, age);//没有事务控制 不可以回滚 int i =1/0;
return "success";
} }

5、APP

package com.wjy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import com.wjy.datasource.DBConfig1;
import com.wjy.datasource.DBConfig2; @SpringBootApplication
@EnableConfigurationProperties(value = { DBConfig1.class, DBConfig2.class }) //启动的时候读取两个类对应的配置信息
public class APP { public static void main(String[] args) {
SpringApplication.run(APP.class, args);
} }

6、测试验证

http://localhost:8080/insertTest1ByService?name=wangsan&age=10

执行后  两个数据库里都没有数据

【Spring Boot学习之四】Spring Boot事务管理的更多相关文章

  1. Spring Boot学习——数据库操作及事务管理

    本文讲解使用Spring-Data-Jpa操作数据库. JPA定义了一系列对象持久化的标准. 一.在项目中使用Spring-Data-Jpa 1. 配置文件application.properties ...

  2. spring boot学习(6) SpringBoot 之事务管理

    两个操作要么同时成功,要么同时失败: 事务的一致性: 以前学ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作: 用来 ...

  3. spring框架学习笔记7:事务管理及案例

    Spring提供了一套管理项目中的事务的机制 以前写过一篇简单的介绍事务的随笔:http://www.cnblogs.com/xuyiqing/p/8430214.html 还有一篇Hibernate ...

  4. Spring+Mybatis+MySql+Maven 简单的事务管理案例

    利用Maven来管理项目中的JAR包,同时使用Spring在业务处理层进行事务管理.数据库使用MySq,数据处理层使用Spring和Mybatis结合. 本案例代码主要结构如图: 1.数据库脚本 -- ...

  5. Spring整合JMS(四)——事务管理

    原文链接:http://haohaoxuexi.iteye.com/blog/1983532 Spring提供了一个JmsTransactionManager用于对JMS ConnectionFact ...

  6. Spring整合JMS(四)——事务管理(转)

    *注:别人那复制来的 Spring提供了一个JmsTransactionManager用于对JMS ConnectionFactory做事务管理.这将允许JMS应用利用Spring的事务管理特性.Jm ...

  7. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...

  8. Spring Cloud 学习 之 Spring Cloud Eureka(搭建)

    Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 搭建服务注册中心: 注册服务提供者: 高可用注册中心: 搭建服务注册中心: ...

  9. spring boot中的声明式事务管理及编程式事务管理

    这几天在做一个功能,具体的情况是这样的: 项目中原有的几个功能模块中有数据上报的功能,现在需要在这几个功能模块的上报之后生成一条消息记录,然后入库,在写个接口供前台来拉取消息记录. 看到这个需求,首先 ...

随机推荐

  1. 20180523模拟赛T2——前缀!

    简化版题面 jyt毒瘤,写了超长的题面,要看完整题面的翻到最后-- 定义\(f_0(x) = A_x\),\(f_n(x) = \sum^x_{i = 1} f_{n-1}(i)\).给出长度为\(N ...

  2. Spring AOP 知识点入门

    一.基本知识点 1.AOP概念 AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对 ...

  3. http 和 https(通俗原理了解)

    超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂 ...

  4. Sliding Window Median

    Description Given an array of n integer, and a moving window(size k), move the window at each iterat ...

  5. codeblocks异常退出

    ExceptionAn exception has been raised! The application encountered an error atC:\CB1312\src\sdk\conf ...

  6. Android编程权威指南笔记2:解决R文件爆红问题和SDK概念

    在android studio中会遇到R文件的丢失,所以遇见这问题怎么解决呢? 重新检查资源文件中xml文件 最近一次编译时如果未生成R.java文件,项目中资源引用的地方都会出错.通常,这是某个xm ...

  7. 阿里云ECS服务器相关配置以及操作---上(初学者)

    最近买了一台阿里云的ECS服务器 linux系统 centos镜像,把我相关的一些操作记录下来,供大家参考,不足之处欢迎指正. 首先买的过程就不用介绍了,根据自己的实际需要选择自己想要的配置,点击付钱 ...

  8. quartz 1.6.2之前的版本,定时任务自动停掉问题

    https://searchcode.com/codesearch/view/28831622/ Quartz 1.6.2 Release Notes This release contains a ...

  9. 对回溯算法的理解(以数独游戏为例,使用c++实现)

    算法思想: 数独游戏的规则: 每一行都用到1.2.3.4.5.6.7.8.9位置不限: 每一列都用到1.2.3.4.5.6.7.8.9位置不限: 每3×3的格子(共九个这样的格子)都用到1.2.3.4 ...

  10. git推送本地分支到远程仓库并在远程仓库创建新分支

    $ git push <远程主机名> <本地分支名>:<远程分支名> git push master test:test #master 为设置的远程仓库别名,第一 ...