数据库
简单的两个字段,一个用户,一个金额
Idea
- dao层
-
首先分析转账涉及到的数据:汇款方(outer)、收款方(inner)、转账金额(money)
-
所以dao层有两个对象:
-
汇款方(谁汇款、汇多少钱) → outer(outerName,money)
-
收款方(谁收款,收多少钱) → inner(innerName,money)
-
因为dao层跟JDBC模板挂钩,所以会用到一个类 --> JdbcDaoSupport(该类可获得JdbcTemplate,同时需在XML文件里将dataSource注入进JdbcTemplate)
*参考代码(接口)*
public interface UserDao {
public void in(String inner,int money);
public void out(String outer,int money);
}
因为此处继承了JdbcDaoSupport ,所以可以直接获得Jdbc的模板 JdbcTemplate
*参考代码(接口实现类)*
public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
@Override
public void in(String inner, int money) {
this.getJdbcTemplate().update("update t_account_lv set money = money + ? where user = ?",money,inner);
}
@Override
public void out(String outer, int money) {
this.getJdbcTemplate().update("update t_account_lv set money = money - ? where user = ?",money,outer);
}
}
service层
-service层可以简单的理解成转账操作(transfer),通过service层调用dao层的数据,从而完成转账。
-所以service层里就一个转账的方法:transfer(inner,outer,money)
-然后将dao层里的数据注入到service层里,提供一个set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
配置XML文件
首先肯定是要用到service,但是service需要有dao,dao又需要有DataSource
所以
第一步:配置数据源(即数据库连接的一些列操作)
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/db_account_lv?characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
第二步:配置dao
<bean id="userDao" class="NulLV.dao.UserDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
第三步:配置service
<bean id="accountService" class="NulLV.service.AccountServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
完成上述后便可以简单的测试一下转账操作了
测试类
public class TransferTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.transfer("威威","威威猫",1000);
}
}
实施效果
可以看到威威猫给威威转了1000块钱
然后我们在转账的过程中人为的添加一个错误后再运行,发现汇款方钱减少了,但是收款方却没有收到钱,这种现象是不符合日常规律的,所以就需要用到我们的事务管理器。
这里两个字段写反了,见谅,哈哈
- 简单理解一下事务管理器:
假如我按执行一系列操作,我执行到了一半,发生了异常,但是之前完成的操作导致一些数据发生了变更,这个时候因为有了事务管理器,这些发生变更的数据会因为事务管理器回调到没变更时的样子。
使用事务管理器
-
首先Spring底层是使用TransactionTemplate事务模板进行操作的
-
(重点)转账方法在service里进行,所以需要将TransactionTemplate模板放到service里去(这里就要去XML里配置模板,并且注入到service里去)
-
(重点)但是此时还只是一个模板,模板想要真正管理事务(这里的事务即转账),就得用到事务管理器(DataSourceTransactionManager)才能进行管理。
-
(重点)要用到事务管理器,也得在XML文件里进行配置和注入(跟使用service就得配置dao,要得到dao又需要配置DataSource同理,一环扣一环)
——————————————有了思路我们就开始进行注入和配置——————————————
第一步:
在service里注入模板,并提供set方法得到模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
第二步:
- 使用transactionTemplate的execute方法里的TransactionCallbackWithoutResult()回调函数
- 该回调函数里又包含了一个方法:
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus)()
我们要做的就是将转账的操作放到上述的方法里,因为是匿名内部类的方式,需要给参数添加final修饰
@Override
public void transfer(final String inner,final String outer,final int money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
userDao.in(inner, money);
// int i = 1/0;
userDao.out(outer, money);
}
});
}
第三步:
在XML文件中配置模板和事务管理器
- 首先service需要用到模板,先把模板注入到service里
- 此时还没有模板,所以需要创建模板
- 然后之前提到模板还没有真正管理事务,所以需要配置事务管理器并注入到模板中
事务管理器的名字一般都叫做txManager(理解成约定俗成的就行)
事务管理器需要事务,此时事务就需要从Connection获得,而连接则是从数据源DataSource获得
测试对比
可以发现尽管出现了错误异常,但是数据库中的数据还是没有发生变化