Spring 学习笔记(十一)- Spring 事务处理(一)

1. 什么是事物

事务就是一系列的动作,它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用。也可以这样说,把一些列的sql语句,组合成一个整体,要么所有的sql都执行成功,要么一句sql都不能被执行。

例如:银行转账,A给B转1000元,这时应有两个操作,A的账户减1000,B的账户加1000.要么都完成,要么都不完成,不然要么就是凭空多了1000,这样数据就会被破坏。

2. Spring 的声明式事务的使用(买衣服为例)

1. 创建数据表

image

2. 添加 jar 包


<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.1.4.RELEASE</version>
</dependency>

<!--JdbcTemplate-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>5.1.4.RELEASE</version>
</dependency>
<!--c3p0-->
<dependency>
	<groupId>c3p0</groupId>
	<artifactId>c3p0</artifactId>
	<version>0.9.1</version>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.41</version>
</dependency>

3. Spring 配置文件

在 resources 下 创建 dbconfig.properties 用来存放连接数据库的数据源

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring5
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=123456

applicationContext.xml

<context:component-scan base-package="www.xq.spring"></context:component-scan>
	
<!-- 配置数据源 -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
	<property name="driverClass" value="${jdbc.driverClass}"></property>
	<property name="user" value="${jdbc.user}"></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>

4. 设计 bean 类

User类

public class User {
	private int id;
	private String useranme;
	private double balance;

	public User() {
		super();
	}

	public User(int id, String useranme, double balance) {
		super();
		this.id = id;
		this.useranme = useranme;
		this.balance = balance;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUseranme() {
		return useranme;
	}

	public void setUseranme(String useranme) {
		this.useranme = useranme;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

}

Clothes 类

public class Clothes {

	private int id;
	private double price;
	private double inventory;

	public Clothes() {
		super();
	}

	public Clothes(int id, double price, double inventory) {
		super();
		this.id = id;
		this.price = price;
		this.inventory = inventory;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public double getInventory() {
		return inventory;
	}

	public void setInventory(double inventory) {
		this.inventory = inventory;
	}

}

5. 设计 dao 接口以及其实现类

UserDao

public interface UserDao {
	//更新余额 
	public void upateBalance(int userid,double amount);
	//获得余额
	public double getBalance(int id);
}

UserDaoImpl

@Repository("userDao")
public class UserDaoImpl implements UserDao{
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public void upateBalance(int userid, double amount) {
		// 同样考虑到余额不足情况
		if(getBalance(userid) < amount) {
			throw new RuntimeException("用户余额不足");
		}
		String sql = "UPDATE users SET balance = balance - ? WHERE id =?";
		jdbcTemplate.update(sql, amount,userid);
	}

	public double getBalance(int id) {
		String sql = "SELECT balance FROM users WHERE id=?";
		return jdbcTemplate.queryForObject(sql,Double.class,id);
	}
}

ClothesDao

public interface ClothesDao {
	//获取单价
	public double getPrice(int id);
	//获取库存
	public int getInventory(int id);
	//更新库存
	public void upadteInventory(int clothid,int amount) ;
}

ClothesDaoImpl

@Repository("clothesDao")
public class ClothesDaoImpl implements ClothesDao{

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public double getPrice(int id) {
		String sql = "SELECT price FROM clothes WHERE id =?";
		return jdbcTemplate.queryForObject(sql, Double.class, id);
	}

	public int getInventory(int id) {
		String sql = "SELECT inventory FROM clothes WHERE id =?";
		return jdbcTemplate.queryForObject(sql, Integer.class, id);
	}

	public void upadteInventory(int clothid, int amount) {
		//考虑到库存不足的时候,抛出异常
		if(getInventory(clothid) < amount) {
			throw new RuntimeException("库存不足");
		}
		String sql = "UPDATE clothes SET inventory = inventory - ? WHERE id =?";
		jdbcTemplate.update(sql, amount,clothid);
	}
}

6. Service 层设计(买衣服)

PurchaseService

public interface PurchaseService {
	public void purchaseClothes(int uid,int cid,int count);
}

PurchaseServiceImpl

@Service("purchaseService")
public class PurchaseServiceImpl implements PurchaseService {

	@Autowired
	private ClothesDao clothesDao;
	@Autowired
	private UserDao userDao;

	public void purchaseClothes(int uid, int cid, int count) {
		// 1. 通过衣服id获取到衣服的单价,计算出购买衣服的总金额
		double sumAmount = clothesDao.getPrice(cid) * count;
		// 2. 从衣服库存数中减去用户购买的数量
		clothesDao.upadteInventory(cid,count);
		// 3. 从用户的余额中扣除购买衣服的金额
		userDao.upateBalance(uid, sumAmount);
	}
}

7. 测试

public class TestTransactionManager {
	@Test
	public void testClothes() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

		PurchaseService purchaseService = ctx.getBean(PurchaseService.class);
		purchaseService.purchaseClothes(1, 1, 1);
	}
}

假设数据表的数据是这样的:

users

image

clothes

image

执行两次上述方法:

users

image

clothes

image

后台

image

分析:
由于用户的余额只能买一本书,所以连续买两本书时,就会包用户余额不足的异常,但是库存却减少了两件,这是不符合现实生活的,所以我们就应该用事物来解决上述异常。

8. 最终工程目录

image

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值