读书人

Spring的事务管理例证代码

发布时间: 2012-10-25 10:58:57 作者: rapoo

Spring的事务管理例子代码

事务管理:

? 分global事务管理和local事务管理,global要跨越多个事务资源,而local一般是本地资源,如JDBC,比较好控制。

?

下面的例子展示怎么Spring的事务管理。声明式事务管理

?

?

其实个人感觉还是手工控制事务舒服一些,因为被Spring管理后,觉得真的很简单了,特感觉没有深度东西可以做了。。。个人感受。

此代码是ProSpring书上面,经过简单改造,用Mysql数据库,把不完整的代码补充完整。

?

数据库:


DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
? `AccountId` int(10) unsigned NOT NULL auto_increment,
? `AccountNumber` varchar(20) NOT NULL,
? `Balance` decimal(10,2) NOT NULL,
? PRIMARY KEY? (`AccountId`),
? UNIQUE KEY `AccountId` (`AccountNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

?

DROP TABLE IF EXISTS `history`;
CREATE TABLE `history` (
? `HistoryId` bigint(20) unsigned NOT NULL auto_increment,
? `Account` varchar(20) NOT NULL,
? `Operation` varchar(50) NOT NULL,
? `Amount` decimal(10,2) NOT NULL,
? `TransactionDate` timestamp NOT NULL,
? `TargetAccount` varchar(20) default NULL,
? UNIQUE KEY `HistoryId` (`HistoryId`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

--
-- Dumping data for table `history`
--

?

接口操作方法:

? package com.apress.prospring.ch12.business;

import java.math.BigDecimal;

import com.apress.prospring.ch12.domain.Account;
???
public interface AccountManager {
?
??? /**
???? * 插入账户
???? * @param account
???? */
??? public void insert(Account account);
???
??? /**
???? * 往账户里面存钱
???? * @param accountId
???? * @param amount
???? */
??? public void deposit(String accountId, BigDecimal amount);
???
??? /**
???? * 从sourceAccount往targetAccount转账
???? * @param sourceAccount
???? * @param targetAccount
???? * @param amount
???? */
??? public void transfer(String sourceAccount, String targetAccount, BigDecimal amount);
???
??? /**
???? * 数据库中账户的数量
???? * @return
???? */
??? public int count();
}

?

抽象类实现:

?

package com.apress.prospring.ch12.business;

import java.math.BigDecimal;
import java.util.Date;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;

import com.apress.prospring.ch12.domain.Account;
import com.apress.prospring.ch12.domain.AccountDao;
import com.apress.prospring.ch12.domain.History;
import com.apress.prospring.ch12.domain.HistoryDao;

public abstract class AbstractAccountManager
implements InitializingBean, AccountManager {
private AccountDao accountDao;
private HistoryDao historyDao;

protected void doInsert(Account account) {
??? getAccountDao().insert(account);
??? History history = new History();
??? history.setAccount(account.getAccountNumber());
??? history.setAmount(account.getBalance());
??? history.setOperation("Initial deposit");
??? history.setTargetAccount(null);
??? history.setTransactionDate(new Date());
??? getHistoryDao().insert(history);
}

protected void doDeposit(String accountId, BigDecimal amount) {
??? History history = new History();
??? history.setAccount(accountId);
??? history.setAmount(amount);
??? history.setOperation("Deposit");
??? history.setTargetAccount(null);
??? history.setTransactionDate(new Date());

??? getAccountDao().updateBalance(accountId, amount);
??? getHistoryDao().insert(history);
}

protected void doTransfer(String sourceAccount,
??String targetAccount, BigDecimal amount) {
??? Account source = getAccountDao().getAccountById(sourceAccount);

??? if (source.getBalance().compareTo(amount) > 0) {
??????? // transfer allowed
??????? getAccountDao().updateBalance(sourceAccount, amount.negate());
??????? getAccountDao().updateBalance(targetAccount, amount);

??????? History history = new History();
??????? history.setAccount(sourceAccount);
??????? history.setAmount(amount);
??????? history.setOperation("Paid out");
??????? history.setTargetAccount(targetAccount);
??????? history.setTransactionDate(new Date());
??????? getHistoryDao().insert(history);

??????? history = new History();
??????? history.setAccount(targetAccount);
??????? history.setAmount(amount);
??????? history.setOperation("Paid in");
??????? history.setTargetAccount(sourceAccount);
??????? history.setTransactionDate(new Date());
??????? getHistoryDao().insert(history);
??? } else {
??????? throw new RuntimeException("Not enough money");
??? }
}

protected int doCount() {
??? return getAccountDao().getCount();
}???


public final void afterPropertiesSet() throws Exception {
??? if (accountDao == null) throw new
??????? BeanCreationException("Must set accountDao");
??? if (historyDao == null) throw new
??????? BeanCreationException("Must set historyDao");
??? initManager();
}

protected void initManager() {
???
}

protected AccountDao getAccountDao() {
??? return accountDao;
}

public void setAccountDao(AccountDao accountDao) {
??? this.accountDao = accountDao;
}

protected HistoryDao getHistoryDao() {
??? return historyDao;
}

public void setHistoryDao(HistoryDao historyDao) {
??? this.historyDao = historyDao;
}
}

默认实现:

package com.apress.prospring.ch12.business;

import java.math.BigDecimal;

import com.apress.prospring.ch12.domain.Account;

public class DefaultAccountManager extends AbstractAccountManager {
???
??? public void insert(Account account) {
??????? doInsert(account);
??? }
???
??? public void deposit(String accountId, BigDecimal amount) {
??????? doDeposit(accountId, amount);
??? }
???
??? public void transfer(String sourceAccount, String targetAccount, BigDecimal amount) {
??????? doTransfer(sourceAccount, targetAccount, amount);
??? }

?public int count() {
??return 0;
?}
???
}

?

数据库操作的两个接口类dao

?

?

?

package com.apress.prospring.ch12.domain;

import java.math.BigDecimal;

public interface AccountDao {
???
?
?/**
? * get account by account number
? * @param accountId
? * @return
? */
?public Account getAccountById(String accountId);

?/**
? * @param sourceAccount
? * @param amount
? */
?public void updateBalance(String sourceAccount, BigDecimal amount);

?/**
? * @param account
? */
?public void insert(Account account);

?/**
? * @return
? */
?public int getCount();

}

package com.apress.prospring.ch12.domain;
???
// in HistoryDao.java:
import java.util.List;
???
public interface HistoryDao {
??? public List getByAccount(int account);
??? public History getById(int historyId);
??? public void insert(History history);
}

AccountDao.xml

?

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>

??? <typeAlias type="com.apress.prospring.ch12.domain.Account" alias="account"/>
??? <resultMap id="result">
??????? <result property="accountNumber" column="AccountNumber"/>
??????? <result property="balance" column="Balance"/>
??? </resultMap>???
???? <insert id="insertAccout" parameterresultMap="result" parameter>
??????? select * from accounts where AccountNumber=#value#
??? </select>
???
???
???
??? <update id="update" parameterencoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>

??? <typeAlias type="com.apress.prospring.ch12.domain.History" alias="history"/>
??? <resultMap id="result">
??????? <result property="account" column="Account"/>
??????? <result property="operation" column="Operation"/>
??????? <result property="amount" column="Amount"/>
??????? <result property="transactionDate" column="TransactionDate"/>
??????? <result property="targetAccount" column="TargetAccount"/>
??? </resultMap>???
???? <insert id="insertHistory" parameterencoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
???
<beans>
???
??? <!-- Data source bean -->
??? <bean id="dataSource" >
??????? <property name="driverClassName">
??????????? <value>com.mysql.jdbc.Driver</value>
??????? </property>
??????? <property name="url">
??????????? <value>jdbc:mysql://localhost/test</value></property>
??????? <property name="username"><value>root</value></property>
??????? <property name="password"><value>G@111111</value></property>
??? </bean>
???
??? <bean id="transactionManager"
???????
???????
???????
???????
???????
??????? });
??????? AccountManager manager = (AccountManager)context.getBean(
??????????? "accountManager");
???????
??????? int count = manager.count();
??????? int failures = 0;
??????? int attempts = 100;
???????
??????? for (int i = 0; i < attempts; i++) {
??????????? Account a = new Account();
??????????? a.setBalance(new BigDecimal(10));
??????????? a.setAccountNumber("123 " + i);

??????????? try {
??????????????? manager.insert(a);
??????????? } catch (RuntimeException ex) {
??????????????? System.out.println("Failed to insert account " + ex.getMessage());
??????????????? failures++;
??????????? }
??????? }
???????
??????? System.out.println("Attempts? : " + attempts);
??????? System.out.println("Failures? : " + failures);
??????? System.out.println("Prev count: " + count);
??????? System.out.println("New count : " + manager.count());
???????
??????? System.out.println("Done");
??? }
???
??? public static void main(String[] args) {
??????? new AccountManagerTest().run();
??? }
???
}

?

?

?

读书人网 >软件架构设计

热点推荐