Spring事务管理 | 使用ProxyFactoryBean/Transaction Interceptor

控制层:

import java.math.BigDecimal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.prospring.ticket.service.PaymentService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/payment")
public class PaymentController {
    @Autowired
    private PaymentService paymentService;

    @RequestMapping(method = RequestMethod.GET, value = "/transfer")
    @ResponseBody
    public String tranfer(
            @RequestParam(value = "sourceAccount", required = 
true
) String sourceAccount,
            @RequestParam(value = "targetAccount", required = 
true
) String targetAccount,
            @RequestParam(value = "money", required = 
true
) BigDecimal money)
            throws Exception {
        paymentService.transfer(sourceAccount, targetAccount, money);
        return "{rs_code:0}";
    }
}

业务逻辑层:

import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.prospring.ticket.aop.interceptor.DebugInterceptor;
import org.springframework.prospring.ticket.dao.PaymentDao;
import org.springframework.prospring.ticket.domain.Account;

public class PaymentServiceImpl implements PaymentService {
    private PaymentDao paymentDao;
    
    @Override
    public void transfer(String sourceAccountNumber, String targetAccountNumber,
            BigDecimal money) {
        Account sourceAccount = paymentDao.getAccount(sourceAccountNumber);
        Account targetAccount = paymentDao.getAccount(targetAccountNumber);
        paymentDao.updateAccount(sourceAccountNumber, sourceAccount.getBalance().subtract(money));
        paymentDao.updateAccount(targetAccountNumber, targetAccount.getBalance().add(money));
    }

    /**
     * @param paymentDao the paymentDao to set
     */
    public void setPaymentDao(PaymentDao paymentDao) {
        this.paymentDao = paymentDao;
    }

}

Dao层:

 

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.prospring.ticket.domain.Account;

public class PaymentDao {
    private JdbcTemplate jdbcTemplate;
    
    public Account getAccount(String account) {
        return (Account) this.jdbcTemplate.query("select id, name, balance from account where id = ?", new Object[]{account},new RowMapper(){
            @Override
            public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                Account account = new Account();
                account.setId(rs.getString("id"));
                account.setName(rs.getString("name"));
                account.setBalance(rs.getBigDecimal("balance"));
                return account;
            }
            
        }).get(0);
    }
    
    public void updateAccount(final String account, final BigDecimal money) {
        this.jdbcTemplate.execute("update account set balance = ? where id = ?", new PreparedStatementCallback() {
            @Override
            public Object doInPreparedStatement(PreparedStatement ps)
                    throws SQLException, DataAccessException {
                ps.setBigDecimal(1, money);
                ps.setString(2, account);
                ps.executeUpdate();
                return null;
            }
        });
    }

    /**
     * @param jdbcTemplate the jdbcTemplate to set
     */
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
}

配置文件1:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  id="WebApp_ID" version="3.0">
  <display-name>bookstore</display-name>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
     classpath*:spring/*.xml
   </param-value>
  </context-param>
  
  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>classpath:conf/log4j.properties</param-value>
  </context-param>
  
  <context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>bookstore.root</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
  
  <servlet>
    <servlet-name>bookstore</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>bookstore</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
  <!-- session -->
  <session-config>
    <session-timeout>60</session-timeout>
  </session-config>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <error-page>
    <error-code>403</error-code>
    <location>/error.html</location>
  </error-page>

</web-app>

配置文件2: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>
    <!--从配置文件读取配置信息 -->
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
        <property name="ignoreResourceNotFound" value="true" />
        <property name="locations">
            <list>
                <value>classpath*:conf/jdbc.properties</value>
            </list>
        </property>
    </bean>

    <!-- The DBCP DataSource -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName">
            <value>${jdbc.driverClassName}</value>
        </property>
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
    </bean>

    <!-- 配置JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- The DAO class -->
    <bean id="paymentDao" class="org.springframework.prospring.ticket.dao.PaymentDao">
        <property name="jdbcTemplate">
            <ref local="jdbcTemplate" />
        </property>
    </bean>

    <!-- The transactionmanager to use for regular non JTA datasource -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
    </bean>

    <!-- Business Object -->
    <bean id="paymentServiceTarget"
        class="org.springframework.prospring.ticket.service.PaymentServiceImpl">
        <property name="paymentDao">
            <ref local="paymentDao" />
        </property>
    </bean>

    <!-- TransactionInterceptor -->
    <bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="transactionAttributeSource">
            <value>
                org.springframework.prospring.ticket.service.PaymentService.transfer=PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE,timeout_30,-Exception
            </value>
        </property>
    </bean>

    <!-- Transactional proxy for the primary business object -->
    <bean id="paymentService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
            <ref local="paymentServiceTarget" />
        </property>
        <property name="proxyInterfaces">
            <value>org.springframework.prospring.ticket.service.PaymentService
            </value>
        </property>
        <property name="interceptorNames">
          <list>
            <value>transactionInterceptor</value>
          </list>
        </property>
    </bean>
 
</beans>

配置文件3:jdbc.properties

# Mysql驱动
jdbc.driverClassName=com.mysql.jdbc.Driver
# Mysql主机、端口、数据库名
jdbc.url=jdbc:mysql://localhost:6688/spring?useUnicode=true&characterEncoding=UTF-8
# Mysql用户名
jdbc.username=admin
# Mysql密码
jdbc.password=admin

配置文件4:log4j.properties

log4j.rootLogger=INFO,CONSOLE,ROLLING_FILE
#log4j.rootLogger=ERROR,CONSOLE,ROLLING_FILE
log4j.debug=true
###################
# Console Appender
###################

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=INFO
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= [%p] %d %c - %m%n

########################
# Rolling File
########################
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=INFO
log4j.appender.ROLLING_FILE.File=${bookstore.root}/logs/bookstore.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=5000KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=100
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
posted @ 2016-01-19 14:58  xder  阅读(411)  评论(0编辑  收藏  举报