一、实验目的
熟练掌握Spring声明式事务管理。
二、实验任务
编写一个模拟银行转账的程序,要求在转账时通过Spring对事务进行控制。
三、实验内容与要求
1. 搭建项目环境
2. 在数据库中创建账户的数据表
3. 创建账户的业务层和持久化层,模拟事务的操作过程和异常处理
4. 分别使用基于XML和基于注解的声明式事务管理方式来实现
5. 通过编写代码实验事务的不同属性(传播机制、隔离级别、是否只读等)
6. 编写测试用例
四、程序设计
一、事务的操作过程和异常处理
正常情况下结果:
产生异常的情况下的结果:
异常处理之后的结果:
关键部分代码
使用全注解方式
Dao层:
@Repository
public class TxDaoImpl implements TxDao {
@Autowired
private JdbcTemplate jdbcTemplate;
// 增加钱的方法
@Override
public void addMoney(String name){
String sql="update account set money=money+100 where name=?";
int update = jdbcTemplate.update(sql, name);
System.out.println(update);
}
// 减少钱的方法
@Override
public void reduceMoney(String name){
String sql="update account set money=money-100 where name=?";
int update = jdbcTemplate.update(sql, name);
System.out.println(update);
}
}
Service层:
@Service
public class TxService {
@Autowired
private TxDao txDao;
//1,正常情况下事务
public void TxDemo1(){
txDao.addMoney("张三");
txDao.reduceMoney("李四");
}
//2,产生异常情况
public void TxDemo2(){
txDao.addMoney("张三");
int i=1/0;
txDao.reduceMoney("李四");
}
// 加入事务transational注解,异常处理之后
public void TxDemo3(){
txDao.addMoney("张三");
int i=1/0;
txDao.reduceMoney("李四");
}
测试类:
public class TestSpring {
@Test
public void txDemo1(){
ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
TxService txService = context.getBean("txService", TxService.class);
txService.TxDemo1();
}
配置类:
@Configuration
@ComponentScan(basePackages = {"com.wlb.spring"})
@EnableTransactionManagement//开启事务注解
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring?characterEncoding=UTF-8");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
return druidDataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate=new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器对象
@Bean
public DataSourceTransactionManager getManger(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
- 使用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">
<!--1.引入jdbc,properties文件-->
<context:property-placeholder location="classpath:jdbc.properties" />
<!--2.创建数据库连接池-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${prop.driverClass}" />
<property name="url" value="${prop.url}"/>
<property name="username" value="${prop.username}"/>
<property name="password" value="${prop.password}"/>
</bean>
<!--3.创建JdbcTemplate对象-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--4.开启组件扫描-->
<context:component-scan base-package="com.xg.spring"/>
<!--5.创建事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--6.配置通知-->
<tx:advice transaction-manager="dataSourceTransactionManager" id="transactionInterceptor">
<!--配置通知相关参数-->
<tx:attributes>
<!--指定哪种规则的方法上添加事务-->
<tx:method name="transfer" propagation="REQUIRED" isolation="READ_COMMITTED"/>
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pc" expression="execution(* com.xg.spring.service.AccountService.transfer(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pc"/>
</aop:config>
</beans>
不同属性:
1、传播行为(required_new)
//关闭事务addbook()
@Repository
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class BookDaoImpl implements BookDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addBook(Book book) {
String sql="insert into book(name,status) values(?,?)";
int update = jdbcTemplate.update(sql, book.getName(), book.getStatus());
System.out.println(update);
}
}
开启required_NEW事务:
@Transactional(propagation= Propagation.REQUIRED_NEW)
public class TxsService {
@Autowired
private BookDao bookDao;
@Autowired
private TxDao txDao;
//测试事务的不通属性
public void TxDemo2(){
Book book = new Book();
book.setName("java");
book.setStatus("1");
bookDao.addBook(book);
txDao.addMoney("张三");
}
2、是否只读readonly
@Service
@Transactional(readOnly = true)
public class TxsService {
@Autowired
private BookDao bookDao;
@Autowired
private TxDao txDao;
//测试是否只读属性
public void TxDemo3(){
bookDao.updateBook("数据结构",1);
}
3、测试是否超时
@Service
@Transactional(timeout = 0)
public class TxsService {
@Autowired
private BookDao bookDao;
@Autowired
private TxDao txDao;
//测试是否只读属性
public void TxDemo3(){
bookDao.updateBook("数据结构",1);
}
4、测试事务回滚
public void TxDemo4(){
bookDao.updateBook("C++",2);
int i = 1/0;
txDao.reduceMoney("李四");
}}
实验总结
通过这次实验,我在理论基础之上,更深入地理解了事务对于spring所产生的重要作用,掌握了xml和注解形式配置事务的方式,不同方法的事务属性的配置不同,执行的事务也不同。