Spring?模擬轉(zhuǎn)賬開發(fā)實(shí)戰(zhàn)小結(jié)
一、轉(zhuǎn)賬業(yè)務(wù)場景分析
轉(zhuǎn)賬是金融類應(yīng)用的核心場景之一,涉及付款方扣減金額和收款方增加金額兩個關(guān)鍵操作。在開發(fā)中需解決以下問題:
- 業(yè)務(wù)層與數(shù)據(jù)層解耦:通過分層架構(gòu)(Service 層調(diào)用 Dao 層)實(shí)現(xiàn)邏輯分離。
- 數(shù)據(jù)庫事務(wù)管理:確保兩個操作要么同時成功,要么同時失敗,避免資金不一致。
- 代碼復(fù)用與簡化:利用 Spring 框架的模板類和依賴注入機(jī)制,減少樣板代碼。
二、基于 Spring 的轉(zhuǎn)賬業(yè)務(wù)開發(fā)(第一種方式)
1. 分層架構(gòu)設(shè)計
(1)Service 層:定義業(yè)務(wù)邏輯
// 接口:聲明轉(zhuǎn)賬方法
public interface AccountService {
void pay(String out, String in, double money); // 付款人、收款人、金額
}
// 實(shí)現(xiàn)類:調(diào)用Dao完成轉(zhuǎn)賬
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao; // 注入Dao層對象
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void pay(String out, String in, double money) {
accountDao.outMoney(out, money); // 付款方扣款
accountDao.inMoney(in, money); // 收款方加款
}
}(2)Dao 層:操作數(shù)據(jù)庫
// 接口:定義數(shù)據(jù)庫操作
public interface AccountDao {
void outMoney(String out, double money); // 扣款
void inMoney(String in, double money); // 加款
}
// 實(shí)現(xiàn)類:使用JdbcTemplate操作數(shù)據(jù)庫
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate; // 注入JdbcTemplate
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void outMoney(String out, double money) {
jdbcTemplate.update("update account set money=money-? where name=?", money, out);
}
@Override
public void inMoney(String in, double money) {
jdbcTemplate.update("update account set money=money+? where name=?", money, in);
}
}2. Spring 配置文件(applicationContext_dao1.xml)
<beans ...>
<!-- 加載數(shù)據(jù)庫配置 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置Druid連接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<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="dataSource"/>
</bean>
<!-- 配置Service和Dao,注入依賴 -->
<bean id="accountService" class="com.qcbyjy.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<bean id="accountDao" class="com.qcbyjy.demo2.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
</beans>3. 測試代碼
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext_dao1.xml")
public class Demo2 {
@Autowired
private AccountService accountService;
@Test
public void testPay() {
accountService.pay("熊大", "熊二", 100); // 模擬熊大給熊二轉(zhuǎn)賬100元
}
}三、Dao 層的簡化寫法(第二種方式)
1. 繼承 JdbcDaoSupport
Spring 提供JdbcDaoSupport抽象類,內(nèi)置JdbcTemplate管理,可簡化 Dao 層代碼:
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void outMoney(String out, double money) {
// 通過getJdbcTemplate()獲取模板對象
this.getJdbcTemplate().update("update account set money=money-? where name=?", money, out);
}
@Override
public void inMoney(String in, double money) {
this.getJdbcTemplate().update("update account set money=money+? where name=?", money, in);
}
}2. Spring 配置優(yōu)化
無需顯式配置JdbcTemplate,直接注入數(shù)據(jù)源(dataSource)即可:
<bean id="accountDao" class="com.qcbyjy.demo3.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/> <!-- 注入數(shù)據(jù)源 -->
</bean>原理:JdbcDaoSupport會自動根據(jù)dataSource創(chuàng)建JdbcTemplate,避免手動綁定模板對象。
四、轉(zhuǎn)賬業(yè)務(wù)的事務(wù)管理(關(guān)鍵?。?/h2>
為什么需要事務(wù)?
假設(shè)轉(zhuǎn)賬過程中,付款方扣款成功后系統(tǒng)崩潰,收款方未加款,會導(dǎo)致資金丟失。事務(wù)確保兩個操作要么都成功,要么都回滾。
1. 未加事務(wù)的問題演示
- 場景:付款方余額不足時,扣款操作拋出異常,但收款方已加款。
- 代碼問題:默認(rèn)情況下,Spring 的
JdbcTemplate操作是自動提交的,異常不會回滾。
2. 添加事務(wù)控制
(1)在 Spring 配置中啟用事務(wù)管理
<beans ...>
<!-- 配置事務(wù)管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> <!-- 綁定數(shù)據(jù)源 -->
</bean>
<!-- 啟用注解事務(wù) -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans> (2)在 Service 方法上添加@Transactional注解
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
// 聲明該方法需要事務(wù)支持
@Transactional
@Override
public void pay(String out, String in, double money) {
accountDao.outMoney(out, money); // 若此處拋出異常,兩個操作都會回滾
accountDao.inMoney(in, money);
}
}3. 事務(wù)關(guān)鍵特性
- 原子性:兩個更新操作視為一個不可分割的整體。
- 隔離性:避免其他事務(wù)看到中間狀態(tài)(通過數(shù)據(jù)庫隔離級別實(shí)現(xiàn))。
- 傳播行為:默認(rèn)
REQUIRED(當(dāng)前有事務(wù)則加入,無則創(chuàng)建新事務(wù))。
五、兩種 Dao 實(shí)現(xiàn)方式對比

六、總結(jié)與最佳實(shí)踐
核心流程總結(jié)
- 分層設(shè)計:Service 層處理業(yè)務(wù)邏輯,Dao 層封裝數(shù)據(jù)庫操作。
- 依賴注入:通過 Spring 配置文件管理對象依賴,避免硬編碼。
- 事務(wù)控制:使用
@Transactional注解確保數(shù)據(jù)一致性,必須配置事務(wù)管理器。 - 連接池優(yōu)化:優(yōu)先使用 Druid 等開源連接池,提升數(shù)據(jù)庫性能。
常見問題與解決方案
- 事務(wù)不生效:檢查是否配置事務(wù)管理器、注解是否添加在 public 方法上、是否使用了代理對象。
- SQL 注入風(fēng)險:使用
JdbcTemplate的參數(shù)化查詢(?占位符),避免拼接 SQL。 - 異常處理:在 Service 層捕獲異常并按需回滾(通過
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly())。
到此這篇關(guān)于Spring 模擬轉(zhuǎn)賬開發(fā)實(shí)戰(zhàn)小結(jié)的文章就介紹到這了,更多相關(guān)Spring 模擬轉(zhuǎn)賬開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java?JIT調(diào)優(yōu)的實(shí)現(xiàn)
JIT編譯器調(diào)優(yōu)方法包括啟用JIT日志、優(yōu)化熱點(diǎn)代碼、循環(huán)展開、內(nèi)聯(lián)優(yōu)化、逃逸分析以及使用性能分析工具等,本文主要介紹了java?JIT調(diào)優(yōu)的實(shí)現(xiàn),感興趣的可以了解一下2025-02-02
基于spring+hibernate+JQuery開發(fā)之電子相冊(附源碼下載)
本篇文章介紹了,基于spring+hibernate+JQuery開發(fā)之電子相冊(附源碼下載)。需要的朋友參考下2013-05-05
SpringBoot整合Flyway實(shí)現(xiàn)數(shù)據(jù)庫的初始化和版本管理操作
Flyway?是一款開源的數(shù)據(jù)庫版本管理工具,它可以很方便的在命令行中使用,或者在Java應(yīng)用程序中引入,用于管理我們的數(shù)據(jù)庫版本,這篇文章主要介紹了SpringBoot整合Flyway實(shí)現(xiàn)數(shù)據(jù)庫的初始化和版本管理,需要的朋友可以參考下2023-06-06
Java?Stream比較兩個List的差異并取出不同的對象四種方法
今天開發(fā)一個需求時要對A和B兩個List集合遍歷,并比較出集合A有,而集合B沒有的值,下面這篇文章主要給大家介紹了關(guān)于Java?Stream比較兩個List的差異并取出不同對象的四種方法,需要的朋友可以參考下2024-01-01

