前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 中实现事务的方式

Spring 中实现事务的方式

作者头像
水货程序员
修改2018-11-20 22:06:08
3.5K0
修改2018-11-20 22:06:08
举报
文章被收录于专栏:javathingsjavathings

Spring 并不直接支持事务,只有当数据库支持事务时,Spring 才支持事务,Spring 只不过简化了开发人员实现事务的步骤。 Spring 提供了两种方式实现事务。

声明式和编程式。

如何选择

当需要用到事务操作的地方很少的时候,那么就可以使用编程方式 TransactionTemplate,它不会建立很多事务代理。但是,如果程序中用到大力的事务操作,声明式事务方式更适合,它使得事务管理和业务逻辑分离。

声明式事务管理

声明式事务管理只需要用到@Transactional 注解和@EnableTransactionManagement。它是基于 Spring AOP 实现的,并且通过注解实现,实现起来简单,对原有代码没有入侵性。

例子

使用 JDBCTemplate 的方式操作 Mysql,实现事务演示。

1,Mave 中需要引入相关的包。

代码语言:javascript
复制
<dependency> 
      <groupId>org.springframework</groupId>  
      <artifactId>spring-jdbc</artifactId>  
      <version>4.3.12.RELEASE</version> 
    </dependency> 
    <dependency> 
      <groupId>c3p0</groupId>  
      <artifactId>c3p0</artifactId>  
      <version>0.9.1.2</version> 
    </dependency>  
    <dependency> 
      <groupId>mysql</groupId>  
      <artifactId>mysql-connector-java</artifactId>  
      <version>5.1.44</version> 
    </dependency>

2. 配置类

代码语言:javascript
复制
package com.learn;
 
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.*;
 
@Configuration
@ComponentScan(value = "com.learn")
@EnableTransactionManagement
public class Config {
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("112233");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/blog?useSSL=false");
		return dataSource;
	}
	
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//注册事务管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
 
}

配置文件中有一个要注意的点:

Spring 对@Configuration 类会特殊处理;dataSource() 方法虽然在 jdbcTemplate 方法和 transactionManager 方法中调用,但是实际返回的都是容器中的那个对象,都是同一个对象,这就保证了 JDBCTemplate 和事务操作所用的数据源是同一个。

3.Dao 层代码,实现往 blog_article 插数据的功能

代码语言:javascript
复制
package com.learn.entity;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BlogDao {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	public void insert(String title,String content){
		String sql = "INSERT INTO `blog_article`(title,content) VALUES(?,?)";
		jdbcTemplate.update(sql, title,content);		
	} 
}

4.Service 层,调用 dao 方法,事务注解在这一层中。

代码语言:javascript
复制
package com.learn.entity;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
@Service
public class BlogService {
 
	@Autowired
	private BlogDao blogDao;
	@Autowired
	private PlatformTransactionManager transactionManager;
 
	@Transactional
	public void insertBlog(String title, String content) {
		blogDao.insert(title, content);
		System.out.println("插入完成...");
	
		//transactionManager.rollback(TransactionAspectSupport.currentTransactionStatus()); // 手动开启事务回滚
		TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); // 手动开启事务回滚
	}
 
}

上面两句 transactionManager.rollback(TransactionAspectSupport.currentTransactionStatus()) 和 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 都能实现手动回滚事务。实际上,当方法出现任何异常的时候,就会自动回滚操作。

5.Main 方法,入口

代码语言:javascript
复制
public class Main {
 
	public static void main(String[] args) {
 
		// 使用Config.class这个配置类
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
 
		BlogService blogService = applicationContext.getBean(BlogService.class);
		blogService.insertBlog("my news", "Hello world");
		applicationContext.close();
	}
}

细说

Maven 中 C3P0 是一个开源的 JDBC 连接池, 是对 JDBC 驱动管理的一个封装。

配置类中有一个注解@EnableTransactionManagement,作用很简单,就是开启事务管理功能;

配置类中的 DataSource 接口类型的 Bean 是一个数据源

配置类中,PlatformTransactionManager 接口类型的 Bean,是一个事务管理器,此接口是事务管理的核心,用来控制事务的,比如回滚事务。该接口有如下几个方法需要实现:

代码语言:javascript
复制
commit(TransactionStatus status) ;     
getTransaction(TransactionDefinition definition) ;     
rollback(TransactionStatus status) ;

这个接口有很多具体的实现类。如图:

比较常用的就是 DataSourceTransactionManager,HibernateTransactionManager,JpaTransactionManager 等。

DataSourceTransactionManager 事务管理器,是基于 JDBC 连接提供的事务处理器实现。jdbcTemplate,MyBatis 这些框架都是基于 JDBC 的,因此对于这些技术实现的数据库操作,都是可以使用 DataSourceTransactionManager 作为事务管理器。JpaTransactionManager 用于 JPA 操作数据库, HibernateTransactionManager 则用于 Hibernate 操作数据库。每个具体的实现类,都是基于不同的数据库操作方式实现的。

编程式实现方式

对于编程式实现的事务管理方式,Spring 也提供两种方法实现: 使用 TransactionTemplate 和使用 PlatformTransactionManager。 Spring 团队推荐使用 TransactionTemplate。

TransactionTemplate 采用了和模范化的方式,类似使用 JDBCTemplate 那样,减少了大量的样板代码,使得开发人员可以转注于业务代码的实现。

代码举例:

1. 配置类

Config配置类

代码语言:javascript
复制
@Configuration
@ComponentScan(value = "com.learn")
public class Config {
 
	
	@Bean
	public DataSource dataSource() throws Exception {
	ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("112233");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/blog?useSSL=false");
		return dataSource;
	}
 
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception {
		System.out.println(dataSource().hashCode());
 
		// Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
 
	// 注册事务管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception {
		System.out.println(dataSource().hashCode());
		return new DataSourceTransactionManager(dataSource());
	}
 
	@Bean
	public TransactionTemplate transactionTemplate() throws Exception {
		
		TransactionTemplate t = new TransactionTemplate();
		t.setTransactionManager(transactionManager());
		return t;
	}
}

注意,这里使用到了 TransactionTemplate 类,但仍然是依赖于一个 PlatformTransactionManager 。

2.Dao 层代码,和上面的代码一样,没有什么变化,实现往 blog_article 插数据的功能。

代码语言:javascript
复制
package com.learn.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BlogDao {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	public void insert(String title,String content){
		String sql = "INSERT INTO `blog_article`(title,content) VALUES(?,?)";
		jdbcTemplate.update(sql, title,content);		
	} 
}

3.Service 层的代码

代码语言:javascript
复制
@Service
public class BlogService {
	@Autowired
	private BlogDao blogDao;
 
	@Autowired
	private TransactionTemplate transactionTemplate;
 
	public void insertBlog(final String title, final String content) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				blogDao.insert(title, content);
				blogDao.insert(title + "2", content + "2");
				if (new Date().getMinutes() > 30)
				{
					status.setRollbackOnly();
				}
			}
		});
	}
}

4.Main 方法入口,同上例。

上述代码,通过 TransactionTemplate 执行数据库操作逻辑,逻辑实际包含在 doInTransactionWithoutResult 方法中,该方法有异常的时候,事务会回滚,也可以通过代码判断手动回滚,比如,判断当前时间分钟数大于 30 的时候,手动回滚。

另一种采用 PlatformTransactionManager 的实现方式不举例了。

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档