论坛首页 Java企业应用论坛

Spring的事务管理例子代码

浏览 3760 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (3)
作者 正文
   发表时间:2009-06-27   最后修改:2009-07-01

事务管理:

  分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 class="account" id="result">
        <result property="accountNumber" column="AccountNumber"/>
        <result property="balance" column="Balance"/>
    </resultMap>   
     <insert id="insertAccout" parameterClass="account">
        insert into accounts (AccountNumber, Balance) values (#accountNumber#,#balance#)
    </insert>
   
   
    <select id="getAccountById" resultMap="result" parameterClass="int" >
        select * from accounts where AccountNumber=#value#
    </select>
   
   
   
    <update id="update" parameterClass="map">
        update accounts set  Balance=#balance# where AccountNumber=#accountNumber#
    </update>
   
   
</sqlMap>

 

HistoryDao.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.History" alias="history"/>
    <resultMap class="history" 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" parameterClass="history">
        insert into history (Account,Operation,Amount,TransactionDate, TargetAccount)
        values (#account#,#operation#,#amount#,#transactionDate#,#targetAccount#)
    </insert>
   

   
</sqlMap>

 

applicationContext.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
   
<beans>
   
    <!-- Data source bean -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"    destroy-method="close" >
        <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"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"><ref local="dataSource"/></property>
    </bean>
   
    <bean id="sqlMapClient"
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation"><value>sqlMapConfig.xml</value></property>
    </bean>
   
    <bean id="accountDao"
        class="com.apress.prospring.ch12.data.SqlMapClientAccountDao">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="sqlMapClient"><ref local="sqlMapClient"/></property>
    </bean>
   
    <bean id="historyDao"
        class="com.apress.prospring.ch12.data.UnreliableSqlMapClientHistoryDao">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="sqlMapClient"><ref local="sqlMapClient"/></property>
    </bean>
   
    <bean id="accountManagerTarget"
        class="com.apress.prospring.ch12.business.DefaultAccountManager">
        <property name="accountDao"><ref local="accountDao"/></property>
        <property name="historyDao"><ref local="historyDao"/></property>
    </bean>
   
    <bean id="accountManager"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager"/></property>
        <property name="target"><ref local="accountManagerTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="insert*">
                    PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
                <prop key="transfer*">
                    PROPAGATION_REQUIRED, ISOLATION_SERIALIZABLE</prop>
                <prop key="deposit*">
                    PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
            </props>
        </property>
    </bean>
</beans>

 

 

package com.apress.prospring.ch12.business;

import java.math.BigDecimal;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

public class AccountManagerTest {
   
    private ApplicationContext context;
   
    private void run() {
        System.out.println("Initializing application");
        context = new ClassPathXmlApplicationContext(new String[] {
            "applicationContext.xml" });
        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();
    }
   
}

 

 

 

论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics