spring ——四种事务管理的实现

目录

说明

本例子不是web项目,主要内容是介绍四个spring事务管理方式。
需要引入spring-jdbc.jar(事务管理器)和spring-tx.jar(事务管理模板)
使用了连接池,资源文件,spring JDBC模板

项目

在四种事务管理的实现中有些内容是重复的,在下面只展示一次。

重复的内容有一下部分

资源文件jdbc.properties

代码片`.

jdbc.driverClassName=com.hxtt.sql.access.AccessDriver
jdbc.url=jdbc:Access:///F://HrMS.accdb
jdbc.username=
jdbc.password=

说明:
key值要和配置文件的${ }中的值一样。

DAO层类AccountDAO.java

代码片`.

package text_transaction;
import java.math.BigDecimal;
import org.springframework.jdbc.core.JdbcTemplate;

//DAO层
public class AccountDAO {

	JdbcTemplate jdbcTemplate;//JDBC模板

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public AccountDAO() {
	}

	public void inMoney(String name, double money) {
		// 转入
		String sql = "update account set money = money + ? where name= ?";
		jdbcTemplate.update(sql, money, name);
		System.out.println("给" + name + "转入" + money + "元钱");
	}

	public void outMoney(String name, double money) throws MoneyException  {
		// 转出
		//查询余额
		double conMoney = jdbcTemplate.queryForObject("select money from account where name=?", Double.class, name);
		
		BigDecimal data1 = new BigDecimal(conMoney); 
		BigDecimal data2 = new BigDecimal(money); 
		
		if(data1.compareTo(data2)==-1){//比较double类型的数的大小
			throw new MoneyException("余额不足");//手动抛出异常
		}
		String sql = "update account set money = money - ? where name= ?";
		jdbcTemplate.update(sql, money, name);
		System.out.println("从" + name + "转出" + money + "元钱");
	}

}
 

说明:
1. 使用了springJDBC模板。
2. 类的包名记得根据下面的配置文件进行修改。

自定义异常类

代码片.

package text_transaction1;
//自定义异常
public class MoneyException extends Exception {
	String message;
	public MoneyException(String message) {
		this.message=message;
	}
	
	@Override
	public String getMessage() {
		// TODO Auto-generated method stub
		return message;
	}
}

 

说明:

  1. 在赚钱事务中,需要判断余额情况,所以在余额不足时需要主动抛出异常。
测试类text.java

代码片.

package text_transaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class text {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("text_transaction/applicationContext.xml");
		AccountService accountService = (AccountService) ctx.getBean("accountService");
		//转出账号,转入账号,金额
		accountService.transfer("李四", "张三", 1000);
	}
}
 

说明:

  1. 用主方法进行测试运行的,没有用Junit。
  2. 类的包名记得根据下面的配置文件进行修改。
  3. 创建上下文对象时引用配置文件的路径也要根据实际情况修改。

【下面分别展示 四种不同的部分】

第一种——编程式的事务管理

通过事务管理模板来实现对事务的管理,在当前类中操作方法。

配置文件

代码片.

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	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
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    
	<!-- 进行jdbc事务管理时:在配置url时,数据库的路径要写成 F://HrMS.accdb,而不能写成F:HrMS.accdb,写错了找不到;但是配置hibernate事务时F:HrMS.accdb写也行-->
    
<!-- 配置连接池,引入外部属性文件
	<context:property-placeholder location="text_transaction1/jdbc.properties" />
-->
<!-- 配置连接池  c3p0
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driverClassName}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
-->
	
<!-- 配置连接池  Apache
	 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
-->
	
<!-- 配置连接池  ODBC jdk 1.8一下版本可以使用
	<bean id="dataSource" class="XXX.XXX.XXX">
		<property name="driverClass" value="sun.jdbc.odbc.JdbcOdbcDriver"></property>
		<property name="jdbcUrl" value="jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=F://HrMS.accdb "></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
-->
	<!-- 引入资源文件 jdbc.properties -->
	<bean
       class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
       <property name="locations">
           <value>text_transaction1/jdbc.properties</value>
       </property>
   	</bean>
	<!-- 配置连接池  spring自带的类 -->
    <bean id="dataSource" 
    	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
		
	<!-- 事务管理器 -->
	<bean id="transactionManager"	
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 事务管理模板 -->
	<bean id="transactionTemplate"
		class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="transactionManager" />
	</bean>

	<!-- Service层,注入事务管理模板 -->
	<bean id="accountService" class="text_transaction1.AccountService">
		<property name="transactionTemplate" ref="transactionTemplate" />
		<property name="accountDAO" ref="accountDAO" />
	</bean>
	
	<!-- spring jdbc模板 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- DAO,注入jdbc模板 -->
	<bean id="accountDAO" class="text_transaction1.AccountDAO">
		<property name="jdbcTemplate" ref="jdbcTemplate" />
	</bean>
	
</beans>


说明:

  1. 上述介绍了两种引用外部资源文件的方式;三种使用不同缓冲池的方式;两种配置access数据库的方式。
  2. 进行jdbc事务管理时:在配置url时,数据库的路径要写成 F://HrMS.accdb,而不能写成F:HrMS.accdb,写错了找不到;但是配置hibernate事务时F:HrMS.accdb写也行。
  3. ODBC jdk 1.8一下版本可以使用
  4. 使用Access_JDBC30.jar JDBC驱动是有限制的,免费版:查询和插入的次数是受限制的

事务管理代码

代码片.

package text_transaction1;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import text_transaction1.MoneyException;

//Service层
public class AccountService {
	AccountDAO accountDAO;
	TransactionTemplate transactionTemplate;

	//注入DAO类
	public void setAccountDAO(AccountDAO accountDAO) {
		this.accountDAO = accountDAO;
	}

	//注入事务管理模板
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}

	public void transfer(String outName,String inName,double money) {
		
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				// TODO Auto-generated method stub
				try {
					accountDAO.outMoney(outName, money);
					// int d=1/0;//除0异常
					accountDAO.inMoney(inName, money);
				} catch (MoneyException e) {
					System.out.println("转出异常:"+e.getMessage());
				
				}
			}
		});		
	}
}

说明:

  1. 使用事务管理模板类进行事务管理,在transactionTemplate的execute(…)方法中使用匿名类,在doInTransactionWithoutResult(…)方法中进行事务管理。
  2. TransactionStatus :记录事务运行的具体状态。

第二种——基于代理的事务管理的方式

使用事务的代理来管理事务,包装了一个代理对象,增强其功能,用代理bean来代替目标bean进行操作

配置文件

代码片.

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	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
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">


	<!-- 引入资源文件 jdbc.properties -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<value>text_transaction2/jdbc.properties</value>
		</property>
	</bean>
	<!-- 配置连接池 spring自带的类 -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<!-- 事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 事务管理的代理工厂 -->
	<bean id="accountServiceProxyFactory"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<!-- 代理目标 -->
		<property name="target" ref="accountService"></property>
		<!-- 事务管理器 -->
		<property name="transactionManager" ref="transactionManager"></property>
		<!-- 设置事务的属性 -->
		<property name="transactionAttributes">
			<props>
				<!-- 设置事务的属性:传播行为REQUIRED,只读  -->
		<!-- 	<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>  -->
				<!-- 事务管理代理目标的transfer方法,属性是:传播行为REQUIRED和隔离级别默认,回滚异常-Exception,不回滚异常+Exception -->
				<prop key="transfer">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>

	<!-- Service层,注入事务管理模板 -->
	<bean id="accountService" class="text_transaction2.AccountService">
		<property name="accountDAO" ref="accountDAO" />
	</bean>

	<!-- spring jdbc模板 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- DAO,注入jdbc模板 -->
	<bean id="accountDAO" class="text_transaction2.AccountDAO">
		<property name="jdbcTemplate" ref="jdbcTemplate" />
	</bean>

</beans>

说明:
可以定义管理事务的属性

注意
测试类中和其他的方式有所不同:
------这里get的bean是代理的bean,然后强制转换为目标bean来使用的。------

package text_transaction2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class text {

	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("text_transaction2/applicationContext.xml");
		AccountService accountService = (AccountService) ctx.getBean("accountServiceProxyFactory");//使用代理bean来表示目标
		//转出账号,转入账号,金额
		accountService.transfer("张三", "李四", 500);
	}

事务管理代码

代码片.

package text_transaction2;

import text_transaction2.MoneyException;

//Service层
public class AccountService {
	AccountDAO accountDAO;

	// 注入DAO类
	public void setAccountDAO(AccountDAO accountDAO) {
		this.accountDAO = accountDAO;
	}

	public void transfer(String outName,String inName,double money) {

		try {
			accountDAO.outMoney(outName, money);
			// int d=1/0;//除0异常
			accountDAO.inMoney(inName, money);
		} catch (MoneyException e) {
			System.out.println("转出异常:"+e.getMessage());
		
		}
	}
}

说明:
下面三种方式的事务管理代码是相同的。

第三种——基于AOP+tx的事务管理

采用AOP的切面方式来管理一类事务,匹配切点的对象都会进行事务管理

配置文件

代码片.

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	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
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">


	<!-- 引入资源文件 jdbc.properties -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<value>text_transaction3/jdbc.properties</value>
		</property>
	</bean>
	<!-- 配置连接池 spring自带的类 -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>


	<!-- 事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 事务的通知transactionManager,增强的通知  -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<!-- 事务管理的属性 -->
		<tx:attributes>
			<!-- name:目标的方法,
				 propagation:传播行为,
				 isolation:隔离级别,
				 read-only:只读
				 rollback-for:异常回滚
				 no-rollback-for 异常不回滚
				 timeout:过期时间,-1为不过期-->
			<tx:method name="transfer" 
					   propagation="REQUIRED"
					   isolation="DEFAULT" 
					   read-only="false" 
					   timeout="-1"/>
		</tx:attributes>
	</tx:advice>

	<aop:config>
		<!-- 切点 -->
		<aop:pointcut expression="execution(* text_transaction3.AccountService.*(..))" id="pointcut"/>
		<!-- 切面 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
	</aop:config>

	<!-- Service层,注入事务管理模板 -->
	<bean id="accountService" class="text_transaction3.AccountService">
		<property name="accountDAO" ref="accountDAO" />
	</bean>

	<!-- spring jdbc模板 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- DAO,注入jdbc模板 -->
	<bean id="accountDAO" class="text_transaction3.AccountDAO">
		<property name="jdbcTemplate" ref="jdbcTemplate" />
	</bean>

</beans>


说明:
可以定义管理事务的属性

事务管理代码

代码片.
同上二

第四种——基于注解的事务管理

通过注解来标识需要事务管理的bean或者方法

配置文件

代码片.

<?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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	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
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    
	
	<!-- 开启注解扫描 -->
    <context:component-scan base-package="text_transaction4"/>
	
	<!-- 引入资源文件 jdbc.properties -->
	<bean
       class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
       <property name="locations">
           <value>text_transaction4/jdbc.properties</value>
       </property>
   	</bean>
	<!-- 配置连接池  spring自带的类 -->
    <bean id="dataSource" 
    	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
		
	<!-- 事务管理器 -->
	<bean id="transactionManager"	
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>


	<!-- Service层,注入事务管理模板 -->
	<bean id="accountService" class="text_transaction4.AccountService">
		<property name="accountDAO" ref="accountDAO" />
	</bean>
	
	<!-- spring jdbc模板 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- DAO,注入jdbc模板 -->
	<bean id="accountDAO" class="text_transaction4.AccountDAO">
		<property name="jdbcTemplate" ref="jdbcTemplate" />
	</bean>
	
	<!-- 开启注解事务 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>


事务管理代码

代码片.

package text_transaction4;
import org.springframework.transaction.annotation.Transactional;
import text_transaction4.MoneyException;
//Service层
@Transactional(
		isolation=Isolation.DEFAULT,
		propagation=Propagation.REQUIRED,
		readOnly=false,
		timeout=-1)
public class AccountService {
	AccountDAO accountDAO;

	// 注入DAO类
	public void setAccountDAO(AccountDAO accountDAO) {
		this.accountDAO = accountDAO;
	}

	public void transfer(String outName,String inName,double money) {
		try {
			accountDAO.outMoney(outName, money);
			// int d=1/0;//除0异常
			accountDAO.inMoney(inName, money);
			accountDAO.conMoney();
		} catch (MoneyException e) {
			System.out.println("转出异常:"+e.getMessage());
		
		}
	}
}

说明
使用了注解@Transactional,可以定义管理事务的属性

总结

	1. 在进行测试时出现了很多异常,如找不到数据库,因为spring引入的包不是一个版本的出现的异常。
	2. 事务是原子操作,可以对数据的操作进行保护。
	3. 耐心分析异常很重要。
**引用包是最大的困难(一步一步来)**
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值