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

Spring事务管理

作者头像
布禾
修改2020-11-19 10:09:12
2700
修改2020-11-19 10:09:12
举报

Spring事务管理分为声明式事务管理编程式事务管理,声明式事务管理又分为xml注解两种配置方式。应该优先选择声明式事务,因为声明式事务对程序代码的影响最小,因此最符合非侵入式轻量级容器的理想 。只有在进行少量事务操作时,才应该选择编程式事务管理的方式。

声明式事务管理

xml配置方式

Spring配置文件:
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
		https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 导入数据库配置文件 -->
    <context:property-placeholder location="config.properties"/>
    
    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
		init-method="init" destroy-method="close">
		<property name="driverClassName"><value>${jdbc_driverClassName}</value></property>
		<property name="url"><value>${jdbc_url}</value></property>
		<property name="username"><value>${jdbc_username}</value></property>
		<property name="password"><value>${jdbc_password}</value></property>
		<!-- ... -->
    </bean>
    
    <!-- 配置jdbcTemplate,使用jdbcTemplate操作数据库 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    	<property name="dataSource" ref="dataSource"/>
    </bean>
    
    <bean id="userService" class="com.springdemo.tx.UserService">
    	<property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
    
    <!-- 配置事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- xml方式的配置声明式事务 start-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.springdemo.tx.UserService.*(..))"/>
    </aop:config>
    <!-- xml方式的配置声明式事务 end-->
</beans>
config.properties:
代码语言:javascript
复制
jdbc_driverClassName=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://192.168.1.77:3306/testdb?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
jdbc_username=root
jdbc_password=root
UserService.java:
代码语言:javascript
复制
public class UserService {
	private JdbcTemplate jdbcTemplate;

	public void addUser(String name, int age){
		jdbcTemplate.update("insert into test007 (name,age) values (name,age)", name, age);
	}
	
	public void updateUserName(String name, int id){
		jdbcTemplate.update("update test007 set name=? where id=?", name, id);
	}
	
	public void updateUserAge(int age, int id){
		jdbcTemplate.update("update test007 set age=? where id=?", age, id);
	}
	
	public void updateUser(String name, int age, int id){
		updateUserName(name, id);
		//模拟异常
		Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
		updateUserAge(age, id);
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
}
main方法:
代码语言:javascript
复制
public static void main(String[] args) {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-config.xml");
		UserService userService = (UserService) ac.getBean("userService");
		userService.updateUser("小王", 18, 1);
}

使用注解方式

Spring配置文件中添加:
代码语言:javascript
复制
	<!-- 开启注解配置 -->
	<tx:annotation-driven transaction-manager="txManager"/>

然后在需要事务管理的方法上添加@Transactional注解

代码语言:javascript
复制
	@Transactional
	public void updateUser(String name, int age, int id){
		updateUserName(name, id);
		//模拟异常
		Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
		updateUserAge(age, id);
	}

注意:注解方式和xml方式可以二选一,也可以结合使用,两者没有依赖关系。

异常捕获和回滚

异常捕获会导致事务机制失效,继而不会触发回滚。 可以调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手动回滚。

代码语言:javascript
复制
    @Transactional
	public void updateUser(String name, int age, int id){
		try{
			updateUserName(name, id);
			//模拟异常
			Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
			updateUserAge(age, id);
		}catch(NumberFormatException ex){
			//手动回滚
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			ex.printStackTrace();
		}
	}

非RuntimeException时回滚

Spring事务管理机制默认只在抛出RuntimeException时才会触发回滚,可以设置rollbackFor属性来指定其他类型的异常也能回滚。

代码语言:javascript
复制
    //rollbackFor指定抛出Exception类型异常时回滚
    @Transactional(rollbackFor=Exception.class)
	public void updateUser(String name, int age, int id) throws Exception{
		updateUserName(name, id);
		if(id == 1){
			throw new Exception("Id为1的用户不可修改");
		}
		updateUserAge(age, id);
	}

编程式事务管理

修改Spring配置文件:
代码语言:javascript
复制
	<bean id="userService" class="com.springdemo.tx.UserService">
    	<property name="jdbcTemplate" ref="jdbcTemplate"/>
    	<property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
    
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> 
    	<property name="transactionManager" ref="txManager"/>
    </bean>
	
	<!-- 注释声明式事务管理配置 -->
	<!-- <tx:annotation-driven transaction-manager="txManager"/>
    
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.springdemo.tx.UserService.*(..))"/>
    </aop:config> -->
修改UserService:
代码语言:javascript
复制
    private TransactionTemplate transactionTemplate;

    public void updateUser(final String name, final int age, final int id){
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
		    protected void doInTransactionWithoutResult(TransactionStatus status) {
		    	updateUserName(name, id);
				//模拟异常
				Double.parseDouble("我不是Double,所以会抛出NumberFormatException异常");
				updateUserAge(age, id);
		    }
		});
	}

    public TransactionTemplate getTransactionTemplate() {
		return transactionTemplate;
	}

	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-07-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 声明式事务管理
    • xml配置方式
      • Spring配置文件:
      • config.properties:
      • UserService.java:
      • main方法:
    • 使用注解方式
      • Spring配置文件中添加:
    • 异常捕获和回滚
      • 非RuntimeException时回滚
        • 修改Spring配置文件:
        • 修改UserService:
    • 编程式事务管理
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档