环境
  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. jmeter对接口测试入参进行MD5加密的5种方式

    在使用jmeter做测试的过程中,经常需要对请求的入参进行加密,下面列举几种常用的方法,以登录请求密码需要MD5加密为例. 虽然可以先把参数化的明文密码都先md5加密,而不是在登录前先执行加密,但是实 ...

  2. php的快速排序

    <?php     function quicksort($str){         if(count($str)<=1) return $str;//如果个数不大于一,直接返回     ...

  3. 记一次PATH环境变量设置不生效的问题

    问题:卸载原有版本jdk后,如下图在/etc/profile中配置新的环境变量且source /etc/profile 生效配置后,JAVA_HOME值都正确,但PATH变量值还是不对 echo $P ...

  4. Properties 取值和设置函数 Hashtable的静态内部类Entry的结构和克隆方法

  5. Easy-Mock模拟get接口和post接口实例

    1.先创建项目,再新建接口 创建项目入口:首页右下角 + 按钮 创建接口入口如下图: 关于mock的语法这里不做说明,可查看mock.js官方查看更详情的资料. 小tip:在Easy-Mock里面支持 ...

  6. A1128 | 逻辑想象能力、简洁高效美观的代码、memset的使用情景

    写了三遍才AC,这真是对智商极大的侮辱 C++代码: #include <stdio.h> #include <memory.h> #include <math.h> ...

  7. JavaScript sort函数

    默认排序法则: 按照String类型ASCII码大小排序 如果要倒序排序,我们可以把大的数放前面: var arr = [10, 20, 1, 2]; arr.sort(function (x, y) ...

  8. centos7 出现“FirewallD is not running”

    原因:没有开启防火墙 #提示没有开启防火墙服务,–permanent #永久生效,没有此参数重启后失效 [root@uJZ ~]# firewall-cmd --permanent --zone=/t ...

  9. 【POJ2676】Sudoku

    本题传送门 本题知识点:深度优先搜索 + 回溯 问题就是要让我们解决一个数独问题.如果你懂得怎么玩数独的话,那就很自然想到用暴力搜索去做题.(比如我就不会,所以先WA了一发quq) 数独符合三个条件 ...

  10. 微信小程序之上传图片(含前后端代码例子)

    此代码示例,能够让你成功将图片上传至后端,后端做相应的处理,然后返回成功码. 前端小程序代码 index.wxml: <view class='content'> <view cla ...