环境搭建
- 创建表
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
- 创建
jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=123456
- 创建核心配置文件
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"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--加载属性文件,context方式-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置druid连接池,表达式获取属性文件参数-->
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
<!--key值不能和name一样,加前缀jdbc.-->
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--注入JdbcTemplate模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="druid"/>
</bean>
</beans>
- 创建测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
@Resource(name = "jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
jdbcTemplate.update("insert into account value(null,?,?)", "ls", 10000d);
}
}
如果能插入一条数据,则证明我们已经搭建好环境了!(要注意数据库名有没有写错!)
事务准备
- 业务方法接口
package com.itlike.dao;
public interface AccountDao {
//加钱:给谁?多少钱?
public void addMoney(String name,Double money);
//减钱:减谁?多少钱?
public void minusMoney(String name,Double money);
}
- 实现业务接口,编程业务逻辑
//继承JdbcDaoSupport
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
@Override
public void addMoney(String name, Double money) {
this.getJdbcTemplate().update("update account set money=money+? where name=?",money,name);
}
@Override
public void minusMoney(String name, Double money) {
this.getJdbcTemplate().update("update account set money=money-? where name=?",money,name);
}
}
- 让
Spring
管理实现类AccountDaoImpl
<!--Spirng管理实现类-->
<bean id="accountDao" class="com.itlike.dao.AccountDaoImpl">
<property name="dataSource" ref="druid"/>
</bean>
业务需求
- 业务需求接口
public interface AccountService {
// 转钱,谁给谁转?转多少?
public void transferMoney(String from, String to, Double money);
}
- 实现方法
public class AccountServiceImpl implements AccountService {
//使用xml方式注入
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
this.accountDao.minusMoney(from,money);
this.accountDao.addMoney(to,money);
}
}
applicationContext.xml
<bean id="accountService" class="com.itlike.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
测试方法
现有两条记录:
Image 1.png
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
@Resource(name = "accountService")
private AccountService accountService;
@Test
public void test() {
accountService.transferMoney("zs","ls",50d);
}
}
转账成功!
Image 3.png
事务问题
- 重置数据库记录为100
- 在转账方法中添加除0异常,模拟
断电情况
public void transferMoney(String from, String to, Double money) {
this.accountDao.minusMoney(from,money);
int i = 1/0; //发生异常
this.accountDao.addMoney(to,money);
}
- 再次运行测试方法,会得到如下结果:
1.PNG
会发现,za账户的钱已经减少,但ls账户的钱却没有增加,这是为什么呢?
这就是没有添加事务机制所造成的情况,zs账户钱已经减少了,但ls账户的钱还来不及增加,系统就因为发生了异常而停止运行了!
为此,我们可以添加事务机制,让发生异常时,保证业务安全。
编程式事务
需要手动编写代码
- 配置平台事务管理器
<!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- Spring提供了事务管理的模板类
简化事务操作的模板
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
- 在业务层
添加
事务管理的模板
//添加事务模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
this.accountDao.minusMoney(from,money);
int i = 1/0; //发生异常
this.accountDao.addMoney(to,money);
}
- 配置文件注入
accountService
<bean id="accountService" class="com.itlike.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<!-- ref映射事务管理模板transactionTemplate -->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
- 修改转账方法
事务配置中有
回调方法
@Override
public void transferMoney(String from, String to, Double money) {
//这是回调方法(匿名内部类)
this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//在这里添加业务代码
}
});
}
- 修改后的转账方法
//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//匿名内部类中不能使用this
accountDao.minusMoney(from,money);
int i = 1/0; //发生异常
accountDao.addMoney(to,money);
}
});
}
- 再次运行测试方法,如果在发生异常后,表记录不被修改,则证明事务设置成功!
1.PNG
声明式事务XML方式声明事务管理
把代码重置到使用编程式事务之前。
- 引入Aop的开发包
- 配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druid"/>
</bean>
- AOP增强事务功能
若tx报红,有两个原因:
jar包没导入
和名称空间
<!--AOP增强事务配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
- 织入增强方法
<!--把AOP增强添加到方法里-->
<aop:config>
<!--第一个*是任意返回值,第二个*是指给该类里所有方法都织入Aop方法,..代表任意参数-->
<aop:pointcut id="pointcut" expression="execution(* com.itlike.service.AccountServiceImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
运行测试方法,可以看到,当发生除0异常时,表记录不会发生改变!
声明式事务注解方式声明事务管理
把代码重置到使用编程式事务之前。
- 配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druid"/>
</bean>
- 开启注解事务
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
- 在转账方法
类
上添加@Transactional
注解
@Transactional
//@Transactional(isolation= ,propagation= ) 设置隔离级别、传播行为
public class AccountServiceImpl implements AccountService {
//使用xml方式注入
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
this.accountDao.minusMoney(from,money);
//int i = 1/0; //发生异常
this.accountDao.addMoney(to,money);
}
}
运行测试方法,可以看到,当发生除0异常时,表记录不会发生改变!
网友评论