手写spring编程事务

使用事务注意事项

事务是程序运行如果没有错误,会自动提交事物,如果程序运行发生异常,则会自动回滚。 
如果使用了try捕获异常时.一定要在catch里面手动回滚。
事务手动回滚代码
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

声明事务实现
概述
管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,
在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,
这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明
(或通过基于@Transactional注解的方式),
便可以将事务规则应用到业务逻辑中。
       显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。

声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,
声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.learn</groupId>
  <artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<!-- https://mvnrepository.com/artifact/javassist/javassist -->
		<dependency>
			<groupId>javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.12.1.GA</version>
		</dependency>
		<!-- 引入Spring-AOP等相关Jar -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>3.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.6.1</version>
		</dependency>
		<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.5.3</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.1_2</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.5.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.37</version>
		</dependency>
	</dependencies>

</project>
<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    <!-- 这里表示扫包范围 
    	因为我们是使用注解的,
    -->
	<context:component-scan base-package="com.learn"></context:component-scan>
	
	<!-- 这里表示开启事务的注解 
		你如果想要事务的话,你必须开启一个事务注解,
	-->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 开启事物注解 -->

	<!-- 1. 数据源对象: C3P0连接池 -->
	<!-- 第一步我们加载C3P0数据源 
		DBCP和C3P0的区别讲一下,数据库的连接池,
	-->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day20"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>

	<!-- 2. JdbcTemplate工具类实例  -->
	<!-- 这里要引用到我的数据源 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 3.配置事务 -->
	<bean id="dataSourceTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>
package com.learn.service;

public interface UserService {

	public void add();
}
package com.learn.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;

import com.learn.dao.UserDao;
import com.learn.service.UserService;
import com.learn.transaction.TransactionUtils;

/**
 * 这就是编程式事务
 * 
 * @author Leon.Sun
 *
 */
@Service
public class UserServiceImpl implements UserService {
	
	@Autowired
	private TransactionUtils transactionUtils;
	
	@Autowired
	private UserDao userDao;

	public void add() {
		/**
		 * transactionStatus这样起名还是规范一点
		 * 
		 */
		TransactionStatus transactionStatus = null;
		/**
		 * 这里一定要try起来
		 * 事务没问题才会提交
		 * 有问题就会回滚
		 * 
		 */
		try {
			/**
			 * 开启事务
			 */
			transactionStatus = transactionUtils.begin();
			userDao.add("test001", 20);
			/**
			 * 这个时候test001会不会提交到数据库里面去
			 * 肯定不会的
			 * 因为你的事务还没有提交
			 * 我怎么可能到数据库里面查到呢
			 * 是肯定不会到数据库里面去的
			 * 因为你没有commit我怎么能到数据库里面查的到呢
			 * 肯定是不会的
			 * 我们打个断点看一下
			 * 已经走完了
			 * 有没有数据你们说
			 * 是不是没有
			 * 因为你没有提交到数据库里面去
			 * 报错他就会走到catch里面去
			 * 他就会把事务回滚
			 * 数据库里面是不是没有
			 * 
			 * 比如我们搞一个不报错的
			 * 我再运行一遍
			 * 只要你不提交肯定是查不到的
			 * 到这里是不是查不到
			 * 当transactionUtils.commit(transactionStatus)这段代码执行完毕的情况下
			 * 你这两个数据都是可以查到的
			 * 是不是提交了
			 * 提交了之后test001和test002是不是都有了
			 * 这就是事务的一个基本原理
			 * 到时候我们结合AOP自己封装一个事务
			 * 
			 * 
			 */
			System.out.println("开始报错了..........................");
//			int i = 1/0;
			System.out.println("####################################");
			userDao.add("test002", 21);
			/**
			 * 提交事务
			 * transactionStatus!=null这个是为了安全起见
			 */
			if(transactionStatus!=null) {				
				transactionUtils.commit(transactionStatus);
			}
		} catch (Exception e) {
			e.printStackTrace();
			/**
			 * 异常我们最好这样子做
			 * 如果发生异常的情况下
			 * 走到这里一定要调用rollback
			 * 回滚事务
			 * transactionStatus!=null这个是为了安全起见
			 */
			if(transactionStatus!=null) {				
				transactionUtils.rollback(transactionStatus);
			}
		}
	}
}
package com.learn.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

/**
 * 我们今天讲手写事务
 * 我们要他的注解来实现事务
 * 注解其实都是封装起来的
 * 通过编程事务进行封装的
 * 编程事务(需要手动begin 手动回滚  手都提交)
 * 在这里我们要封装几个方法
 * 你们只要拿到ORM框架的接口就行了
 * 我们的数据源接口是哪一个
 * 就是dataSourceTransactionManager这个
 * 我们要拿到事务数据源
 * 然后进行控制事务
 * 
 * 我们要把注入到Spring的容器里面去
 * 你们最好不要用单例的
 * 否则会产生线程安全问题的
 * 
 * 
 * 
 * @author Leon.Sun
 *
 */
@Component
public class TransactionUtils {

	/**
	 * 获取事务源
	 * 
	 * 这里要注入一下@Autowired
	 * 
	 */
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;

	/**
	 * 这个方法干嘛用的
	 * 是不是开启事务
	 * 
	 * 
	 * @return
	 */
	public TransactionStatus begin() {
		/**
		 * 我们调用一下dataSourceTransactionManager
		 * 我们先使用默认的传播级别DefaultTransactionAttribute
		 * 没有学到传播级别
		 * 不知道他里面怎么去用
		 * 拿到了事务的一个状态
		 * 记得要把事务的状态返回回去
		 * 这里是开启一个事务
		 * 我要提交事务怎么提交呢
		 */
		TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
		return transaction;
	}

	/**
	 * 这叫做提交事务
	 * 
	 * 把状态传入进来
	 * 
	 * 
	 * @param transaction
	 */
	public void commit(TransactionStatus transaction) {
		/**
		 * 提价一个事务状态
		 * 
		 */
		dataSourceTransactionManager.commit(transaction);
	}

	/**
	 * 我们再写一个回滚事务
	 * @param transaction
	 */
	public void rollback(TransactionStatus transaction) {
		dataSourceTransactionManager.rollback(transaction);
	}
}
package com.learn.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.learn.service.UserService;

public class Test001 {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
		UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
		userService.add();
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值