1. 程式人生 > >Spring_事務管理(轉賬案例)

Spring_事務管理(轉賬案例)

實現一個轉賬的業務:

OrderDao.java:

package h.l.tx;

import org.springframework.jdbc.core.JdbcTemplate;

public class OrderDao {

	private JdbcTemplate jdbcTemplate;

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	// 模擬轉賬功能:少錢的方法
	public void desMoney() {
		String sql = "update account set balance=balance-? where username=?";
		jdbcTemplate.update(sql, 1000, "zs");
	}
	// 模擬轉賬功能:多錢的方法
	public void incMoney() {
		String sql = "update account set balance=balance+? where username=?";
		jdbcTemplate.update(sql, 1000, "ls");
	}
}

OrderService.java:

package h.l.tx;

public class OrderService {

	private OrderDao orderDao;

	public void setOrderDao(OrderDao orderDao) {
		this.orderDao = orderDao;
	}

	// 業務邏輯:轉賬功能
	public void accountMoney() {
		// 甲少錢
		orderDao.desMoney();
		//手動新增異常
		int i=1/0;
		// 乙多錢
		orderDao.incMoney();
	}
}

Spring配置檔案:ApplicationContext.xml檔案:

<?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"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

	<!-- 配置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/name?useSSL=true"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>

	<!-- 配置OrderService和OrderDao物件 -->
	<bean id="orderService" class="h.l.tx.OrderService">
		<property name="orderDao" ref="orderDao"></property>
	</bean>
	<bean id="orderDao" class="h.l.tx.OrderDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	
	<!-- 建立JdbcTemplate物件 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

測試程式:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

class OrderServiceTest {

	ApplicationContext context;
	@BeforeEach
	void setUp() throws Exception {
		context = new ClassPathXmlApplicationContext(
				"springConfig/ApplicationContext.xml");
	}
	@Test
	void test() {
		OrderService orderService=(OrderService)context.getBean("orderService");
		orderService.accountMoney();
	}

}

執行了上述程式碼之後,會出現個很嚴重的問題,就是單元測試沒有通過,因為int i=1/0;但是在資料庫中zs的錢已經少了1000,,因此解決方法就是加上事務管理:出現異常時,回滾。下面給該功能新增事務功能:

配置檔案方式實現:修改上面的ApplicationContext.xml檔案即可保證在轉賬過程中如果出現了異常會進行回滾。

<?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">
		
	<!-- 配置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/name?useSSL=true"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<!-- 配置事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 注入dataSource -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 配置事務增強 -->
	<tx:advice id="txadvice" transaction-manager="transactionManager">
		<!-- 做事務操作 -->
		<tx:attributes>
			<!-- 設定進行事務操作的方法匹配規則 -->
			<tx:method name="account*"/>
		</tx:attributes>
	</tx:advice>
	<!-- 配置切面 -->
	<aop:config>
		<!-- 配置切入點 -->
		<aop:pointcut expression="execution(* h.l.tx.OrderService.*(..))" id="pointcut1"/>
		<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
	</aop:config>
	
	<!-- 配置OrderService和OrderDao物件 -->
	<bean id="orderService" class="h.l.tx.OrderService">
		<property name="orderDao" ref="orderDao"></property>
	</bean>
	<bean id="orderDao" class="h.l.tx.OrderDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>

	<!-- 建立JdbcTemplate物件 -->
	<bean id="jdbcTemplate"
		class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

註解方式實現:

第一步:修改ApplicationContext.xml檔案:

<?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">
		
	<!-- 配置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/name?useSSL=true"></property>
		<property name="user" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	<!-- 配置事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 注入dataSource -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 開啟事務註解 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
	
	<!-- 配置OrderService和OrderDao物件 -->
	<bean id="orderService" class="h.l.tx.OrderService">
		<property name="orderDao" ref="orderDao"></property>
	</bean>
	<bean id="orderDao" class="h.l.tx.OrderDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>

	<!-- 建立JdbcTemplate物件 -->
	<bean id="jdbcTemplate"
		class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>

第二步在需要新增事務功能的類上加上@Transactional註解:如下即可:

package h.l.tx;

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class OrderService {

	private OrderDao orderDao;

	public void setOrderDao(OrderDao orderDao) {
		this.orderDao = orderDao;
	}

	// 業務邏輯:轉賬功能
	public void accountMoney() {
		// 甲少錢
		orderDao.desMoney();
		//出現異常
		int i=1/0;
		// 乙多錢
		orderDao.incMoney();
	}
}

注:以上文章僅是個人學習過程總結,若有不當之處,望不吝賜教