【Spring Boot学习之四】Spring Boot事务管理
环境
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事务管理的更多相关文章
- Spring Boot学习——数据库操作及事务管理
本文讲解使用Spring-Data-Jpa操作数据库. JPA定义了一系列对象持久化的标准. 一.在项目中使用Spring-Data-Jpa 1. 配置文件application.properties ...
- spring boot学习(6) SpringBoot 之事务管理
两个操作要么同时成功,要么同时失败: 事务的一致性: 以前学ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作: 用来 ...
- spring框架学习笔记7:事务管理及案例
Spring提供了一套管理项目中的事务的机制 以前写过一篇简单的介绍事务的随笔:http://www.cnblogs.com/xuyiqing/p/8430214.html 还有一篇Hibernate ...
- Spring+Mybatis+MySql+Maven 简单的事务管理案例
利用Maven来管理项目中的JAR包,同时使用Spring在业务处理层进行事务管理.数据库使用MySq,数据处理层使用Spring和Mybatis结合. 本案例代码主要结构如图: 1.数据库脚本 -- ...
- Spring整合JMS(四)——事务管理
原文链接:http://haohaoxuexi.iteye.com/blog/1983532 Spring提供了一个JmsTransactionManager用于对JMS ConnectionFact ...
- Spring整合JMS(四)——事务管理(转)
*注:别人那复制来的 Spring提供了一个JmsTransactionManager用于对JMS ConnectionFactory做事务管理.这将允许JMS应用利用Spring的事务管理特性.Jm ...
- Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)
Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...
- Spring Cloud 学习 之 Spring Cloud Eureka(搭建)
Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 搭建服务注册中心: 注册服务提供者: 高可用注册中心: 搭建服务注册中心: ...
- spring boot中的声明式事务管理及编程式事务管理
这几天在做一个功能,具体的情况是这样的: 项目中原有的几个功能模块中有数据上报的功能,现在需要在这几个功能模块的上报之后生成一条消息记录,然后入库,在写个接口供前台来拉取消息记录. 看到这个需求,首先 ...
随机推荐
- vue 实战总结
相对angular 和react ,本人比较喜欢vue,现在的工作项目也在用vue,前两个有朋友在问我在使用vue中有没有遇到一些很难解决的问题,一下我也只能说出一两个,所以索性就抽时间总结一下我在项 ...
- test20191210 钟子谦
100+40+0=140.暴力没写满-- 简单模拟 很久很久以前,有一个 \(1\sim n\) 的排列 \(a\),还有一个长度为 \(q\) 的,每个元素在 \(1\) 到 \(n\) 之间的序列 ...
- 第一章 Java起源
1.计算机语言发展史:B语言-->C语言-->C++语言-->Java语言.通过C和C++反过来理解Java的设计,理解更深: 复杂性:结构化变成=>面向对象编程:继承.封装. ...
- 谷歌浏览器打开不了Axure生成的html文件
1.首先要进行翻墙.https://www.google.com 搜索Axure chrome软件 2. 3.安装axure插件即可. 4.管理扩展程序,允许访问文件网址.
- The difference between Virtual DOM and DOM
dom是结构化的文本信息的抽象,是结构化的文本信息在内存中的表示 是操作结构化文本信息的api. Follow: Follow React attacks us with the virtual DO ...
- 22-1 web传输视频 Opencv+usb摄像头 树莓派+Flask实现视频流媒体WEB服务器
第一篇 讲解原理 https://blog.miguelgrinberg.com/post/video-streaming-with-flask 第二篇 加入多线程可以直接用 https://gith ...
- MongoDB 聚合查询报错
1.Distinct聚合查询报错 db.users.distinct("uname") db.runCommand({"distinct":"user ...
- 在服务器搭建git仓库
使用root登录服务器 添加一个新用户(git仓库的所有者) useradd gituser # gituser---> 用户名字 设置密码 passwd gituser 配置sshd服务参数 ...
- 0.学习springmvc补充
一.我的截图中的程序错误: 其中的路径写的是:"/user/testString" 这样写会错误当tomcat中配置的根目录为"/"或” “成功,但当配置为”x ...
- %lld 和 %I64d
在Linux下输出long long 类型的是 printf("%lld", a); 在Windows下输出是 printf("%I64d", a); xxy学 ...