您现在的位置是:首页 >其他 >实验三 Spring JDBC与事务管理网站首页其他
实验三 Spring JDBC与事务管理
实验三 Spring JDBC与事务管理
- 实验目的
1、掌握Spring JDBC的配置;
2、掌握JdbcTemplae类中增删改查方法的使用;
3、了解Spring事务管理的3个核心接口;
4、了解Spring事务管理的两种方式;
5、掌握基于XML和Annotation的声明式事务管理的使用。
- 实验内容
1、在MySQL中创建以下三张表,其中account为账户表,book为书籍信息表,book_stock为书籍库存表。
(1)使用Spring JDBC实现书店的购书过程,即有如下一个BookShopDao接口,编写BookShopDaoImp类实现该接口中的所有方法,并通过JUnit测试这些方法。
public interface BookShopDao
{
//根据书号获取书的单价
//jdbcTemplate.queryForObject(sql, Double.class, isbn);rowMapper
public double findBookPriceByIsbn(String isbn);
//更新书的库存,使书号对应的库存减num,若库存不足,则给出提示,并且不更新
public void updateBookStock(String isbn, int num);
//更新用户的账户余额:使 username 的 balance – price*num,若余额不足,则给出提示,并且不更新
public void updateUserAccount(String username,double price,int num);
}
(2) 在BookShopDao中添加一个purchase购书方法,其操作流程是获取书的单价->买书(更新库存)->更新账户余额,在BookShopDaoImp中实现该方法,并使用基于XML和Annotation的声明式事务管理来确保该购书过程能正常执行(通过异常的方式来模拟更新库存和更新账户余额时出现的突发性问题),通过JUnit对该方法进行测试。
2.两题实验结果:
a. 根据书号获取书的单价
b.更新书的库存,使书号对应的库存减num。
c. 若库存不足,则给出提示,并且不更新
d. 更新用户的账户余额:使 username 的 balance – price*num,若余额不足,则给出提示,并且不更新
e. .更新用户的账户余额:使 username 的 balance – price*num
f. 测试purchase()余额不足抛异常
g. 测试purchase()获取书的单价->买书(更新库存)->更新账户余额
3.实验代码
package com;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public interface BookShopDao
{
//根据书号获取书的单价
//jdbcTemplate.queryForObject(sql, Double.class, isbn);rowMapper
public double findBookPriceByIsbn(String isbn);
//更新书的库存,使书号对应的库存减num,若库存不足,则给出提示,并且不更新
public void updateBookStock(String isbn, int num);
//更新用户的账户余额:使 username 的 balance – price*num,若余额不足,则给出提示,并且不更新
public void updateUserAccount(String username,double price,int num);
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
void purchase(String username, String isbn, int num);
}
package com;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class BookShopDaoImp implements BookShopDao {
private JdbcTemplate jdbcTemplate;
public BookShopDaoImp(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public double findBookPriceByIsbn(String isbn) {
String sql = "SELECT price FROM book WHERE isbn = ?";
return jdbcTemplate.queryForObject(sql, Double.class, isbn);
}
@Override
public void updateBookStock(String isbn, int num) {
String sql = "SELECT stock FROM book_stock WHERE isbn = ?";
int stock = jdbcTemplate.queryForObject(sql, Integer.class, isbn);
if (stock < num) {
throw new RuntimeException("库存不足");
}
sql = "UPDATE book_stock SET stock = stock - ? WHERE isbn = ?";
jdbcTemplate.update(sql, num, isbn);
}
@Override
public void updateUserAccount(String username, double price, int num) {
String sql = "SELECT balance FROM account WHERE username = ?";
double balance = jdbcTemplate.queryForObject(sql, Double.class, username);
if (balance < price * num) {
throw new RuntimeException("余额不足");
}
sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
jdbcTemplate.update(sql, price * num, username);
}
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public void purchase(String username, String isbn, int num) {
double price = findBookPriceByIsbn(isbn);
System.out.println("价格:"+price+"元");
updateBookStock(isbn, num);
System.out.println("库存减"+num);
updateUserAccount(username, price, num);
System.out.println("已扣除账户余额"+price*num);
System.out.println("购买成功!");
}
}
<?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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 数据源配置 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/ssmshiyan" />
<property name="username" value="root" />
<property name="password" value="2636099699" />
</bean>
<!-- 定义JdbcTemplate对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 定义BookShopDaoImp对象,并注入JdbcTemplate对象 -->
<bean id="bookShopDao" class="com.BookShopDaoImp">
<constructor-arg ref="jdbcTemplate" />
</bean>
<!-- 事务管理器配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 启用基于注解的声明式事务管理 -->
<tx:annotation-driven />
<!-- 事务管理器配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务通知配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="purchase"/>
</tx:attributes>
</tx:advice>
<!-- 切面配置 -->
<aop:config>
<aop:pointcut id="purchasePointcut" expression="execution(* com.BookShopDao.purchase(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="purchasePointcut"/>
</aop:config>
</beans>
import com.BookShopDao;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class BookShopDaoImpTest {
@Autowired
private BookShopDao bookShopDao;
@Test
public void testFindBookPriceByIsbn() {
double price = bookShopDao.findBookPriceByIsbn("1001");
System.out.println(price+"元");
}
//更新书的库存,使书号对应的库存减num,若库存不足,则给出提示,并且不更新
@Test
public void testUpdateBookStock() {
bookShopDao.updateBookStock("1001", 100);
}
//更新用户的账户余额:使 username 的 balance – price*num,若余额不足,则给出提示,并且不更新
@Test
public void testUpdateUserAccount() {
bookShopDao.updateUserAccount("Ton", 100, 1);
System.out.println("购买成功");
}
@Test
public void testPurchase() {
bookShopDao.purchase("Ton", "1001", 1);
}
}
4.实验心得
在这个实验中,我们使用Spring JDBC和声明式事务管理实现了一个简单的书店购书过程。这个实验让我深刻认识到Spring框架的便利性和高效性,也更深入了解了JDBC编程和声明式事务的使用方法。
实验中,我们先通过配置数据源,建立了数据库连接池,并使用JdbcTemplate类来方便地执行SQL语句。通过JdbcTemplate的帮助,我们可以在代码中直接调用SQL语句,省去了手动连接数据库和释放资源的步骤,大大简化了数据库操作的流程。
在实现购书过程的过程中,我们使用了声明式事务管理,这样可以在出现异常时自动回滚事务,确保数据的一致性和完整性。使用Spring框架的事务管理器,我们可以通过XML和注解两种方式来配置声明式事务。通过这个实验,我更深入了解了Spring框架的事务管理机制,并学会了如何在XML和注解两种方式中配置声明式事务。
这个实验是一个非常好的练习,让我更加深入了解了Spring框架的使用方法,提升了我的编程能力和实践经验。同时,我也更深入理解了JDBC编程和事务管理的原理,这对我的学习和工作都有很大的帮助。