【spring框架】通过XML配置事务(Transaction)
1 前言
在 通过注解配置事务 中介绍了使用注解配置事务(Transaction),本文将介绍通过 XML 配置事务,并沿用前面的案例。
通过 XML 配置事务,其原理是 AOP,即将事务当做一个切面,作用于切入点。关于 AOP 的介绍,见 XML配置AOP 。
需要导入的 jar 包如下,其中最后三个包是 JdbcTemplate 所需的 jar 包。
2 案例
首先在 MySQL 中创建数据库:taobao,再在此数据库中创建表:users(uid int, balance int),books(bid varchar, price int, num int),users 和 books 表中数据如下:
Dao.java
package com.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class Dao {
@Autowired
private JdbcTemplate jdbcTemplate;
public Integer queryPrice(String bid) { //查询书的价格
Integer price=jdbcTemplate.queryForObject("select price from books where bid=?", new Object[] {bid},Integer.class);
return price;
}
public Integer queryNum(String bid) { //查询书的库存量
Integer num=jdbcTemplate.queryForObject("select num from books where bid=?", new Object[] {bid},Integer.class);
return num;
}
public Integer queryBalance(Integer uid) { //查询用户的余额
Integer balance=jdbcTemplate.queryForObject("select balance from users where uid=?", new Object[] {uid},Integer.class);
return balance;
}
public void updateBook(String bid,Integer buy_num) { //更新书的数量
Integer num=queryNum(bid);
if(num<buy_num) {
throw new RuntimeException();
}else {
jdbcTemplate.update("update books set num=num-? where bid=?", buy_num,bid);
}
}
public void updateUser(Integer uid,Integer price,Integer buy_num) { //更新用户的余额
Integer balance=queryBalance(uid);
if(balance<price*buy_num) {
throw new RuntimeException();
}else {
jdbcTemplate.update("update users set balance=balance-? where uid=?", price*buy_num,uid);
}
}
}
其中,@Repository 用于将 Dao 标注为持久层,并由 IOC 容器生成名为 dao 的 bean;@Autowired 用于自动注入属性。@Repository 和 @Autowired 的具体用法见 通过注解配置bean。
BookService.java
package com.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
private Dao dao;
public void buyBook(Integer uid,String bid,Integer buy_num) {
Integer price=dao.queryPrice(bid);
dao.updateUser(uid, price, buy_num); //用户扣钱
dao.updateBook(bid, buy_num); //书店减书
}
}
其中, @Service 用于将 BookService 标注为服务层,并由 IOC 容器生成名为 bookService 的 bean;buyBook() 方法将在 xml 文件中配置为事务,使其内部操作为一个整体,要么全部执行,要么全不执行(因为可能存在用户扣了钱,书店缺书的情况)。
transaction.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:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 引入属性文件 -->
<context:property-placeholder location="db.properties"/>
<!-- 创建数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 通过数据源配置JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 扫描组件 -->
<context:component-scan base-package="com.transaction"></context:component-scan>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="adv" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="buyBook"/>
</tx:attributes>
</tx:advice>
<!-- 配置切入点表达式 -->
<aop:config>
<aop:pointcut expression="execution(* com.transaction.*.*(..))" id="pcut"/>
<aop:advisor advice-ref="adv" pointcut="pcut"/>
</aop:config>
</beans>
注意:需要导入 context、tx、aop 命名空间;tx:method 标签中可以设置 propagation(传播级别)、isolation(隔离级别)、timeout、read-only、rollback-for 等属性,如下:
Test.java
package com.transaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("transaction.xml");
BookService service=ac.getBean("bookService",BookService.class);
service.buyBook(1002, "b2", 1);
}
}
由于用户 1002 有钱(100元),但书店缺书 b2(0本),因此事务没有执行,即用户没有扣钱。如果没有将 buyBook() 方法配置为一个事务,即使书店缺书,用户也会扣钱。
相关文章
- word使用dot模板以spring word 模板为例
- Spring MVC
- 在Spring框架中实现属性配置动态刷新,不需要重启应用。
- spring MongoDB 配置以及开启事务
- Spring Kafka中通过参数配置解决超时问题
- 《精通Spring MVC 4》——1.8 嵌入式Servlet容器(Tomcat)的配置
- Spring Security 5.7 最新配置细节(直接就能用),WebSecurityConfigurerAdapter 已废弃
- 【Spring Cloud】Ribbon负载均衡原理与实战(源码级讲解)
- Spring Boot 2 使用自定义配置
- Spring启动报错org.springframework.boot.builder.SpringApplicationBuilder
- [转] Spring Boot 自动配置之@Enable* 与@Import注解
- Spring Remoting by HTTP Invoker Example--reference
- Java中核心注解的作用及其使用,了解Spring容器装载的过程和机制,自定义注解来实现自动配置项目依赖环境,包括mybatis、Dubbo、log4j、RabbitMQ、redis相关等自动配置