博客
关于我
基于注解的AOP实现事务控制
阅读量:687 次
发布时间:2019-03-17

本文共 11070 字,大约阅读时间需要 36 分钟。

需要注意在使用注解时,后置通知与异常通知执行顺序颠倒,所以要用环绕通知来解决此问题。

pom.xml

4.0.0
com.qublog
spring04_account_aoptx_anno
1.0-SNAPSHOT
jar
org.springframework
spring-context
5.0.2.RELEASE
commons-dbutils
commons-dbutils
1.4
mysql
mysql-connector-java
8.0.16
c3p0
c3p0
0.9.1.2
junit
junit
4.12
org.springframework
spring-test
5.0.2.RELEASE
org.aspectj
aspectjweaver
1.8.7

Account类:

package com.qublog.domain;import java.io.Serializable;//账户的实体类public class Account implements Serializable {       private Integer id;    private String name;    private Float money;    public Integer getId() {           return id;    }    public void setId(Integer id) {           this.id = id;    }    public String getName() {           return name;    }    public void setName(String name) {           this.name = name;    }    public Float getMoney() {           return money;    }    public void setMoney(Float money) {           this.money = money;    }    @Override    public String toString() {           return "Account{" +                "id=" + id +                ", name='" + name + '\'' +                ", money=" + money +                '}';    }}

AccountDao接口:

package com.qublog.dao;import com.qublog.domain.Account;import java.util.List;//账户的持久层接口public interface AccountDao {       //查询所有    List
findAllAccount(); //查询一个 Account findAccountById(Integer id); //保存 void saveAccount(Account account); //更新 void updateAccount(Account account); //删除 void deleteAccount(Integer id); //根据名称查找账户,如果有唯一结果就返回,如果没有结果就返回null,如果结果集超过一个就抛异常 Account findAccountByName(String accountName);}

AccountDaoImpl类:

package com.qublog.dao.impl;import com.qublog.dao.AccountDao;import com.qublog.domain.Account;import com.qublog.utils.ConnectionUtils;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import org.apache.commons.dbutils.handlers.BeanListHandler;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import java.util.List;//账户的持久层实现类@Repository("accountDao")public class AccountDaoImpl implements AccountDao {       @Autowired    private QueryRunner runner;    @Autowired    private ConnectionUtils connectionUtils;    public List
findAllAccount() { try{ return runner.query(connectionUtils.getThreadConnection(),"select * from account;",new BeanListHandler
(Account.class)); } catch (Exception e) { throw new RuntimeException(e); } } public Account findAccountById(Integer id) { try{ return runner.query(connectionUtils.getThreadConnection(),"select * from account where id=?;",new BeanHandler
(Account.class),id); } catch (Exception e) { throw new RuntimeException(e); } } public void saveAccount(Account account) { try{ runner.update(connectionUtils.getThreadConnection(),"insert into account(name,money) values(?,?);", account.getName(), account.getMoney()); } catch (Exception e) { throw new RuntimeException(e); } } public void updateAccount(Account account) { try{ runner.update(connectionUtils.getThreadConnection(),"update account set name=?,money=? where id=?;", account.getName(), account.getMoney(),account.getId()); } catch (Exception e) { throw new RuntimeException(e); } } public void deleteAccount(Integer id) { try{ runner.update(connectionUtils.getThreadConnection(),"delete from account where id=?;",id); } catch (Exception e) { throw new RuntimeException(e); } } public Account findAccountByName(String accountName) { try { List
accounts = runner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",new BeanListHandler
(Account.class),accountName); if (accounts == null || accounts.size() == 0) { return null; } if (accounts.size() > 1) { throw new RuntimeException("结果集不唯一,数据有问题"); } return accounts.get(0); } catch (Exception e) { throw new RuntimeException(e); } }}

AccountService接口:

package com.qublog.service;import com.qublog.domain.Account;import java.util.List;//账户的业务层接口public interface AccountService {       //查询所有    List
findAllAccount(); //查询一个 Account findAccountById(Integer id); //保存 void saveAccount(Account account); //更新 void updateAccount(Account account); //删除 void deleteAccount(Integer id); //转账 void transfer(String sourceName, String targetName, Float money); //void test();}

AccountServiceImpl类:

package com.qublog.service.impl;import com.qublog.dao.AccountDao;import com.qublog.domain.Account;import com.qublog.service.AccountService;import com.qublog.utils.TransactionManager;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;//账户的业务层实现类//事务的控制应该都是在业务层的@Service("accountService")public class AccountServiceImpl implements AccountService {       @Autowired    private AccountDao accountDao;    public List
findAllAccount() { return accountDao.findAllAccount(); } public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } public void saveAccount(Account account) { accountDao.saveAccount(account); } public void updateAccount(Account account) { accountDao.updateAccount(account); } public void deleteAccount(Integer id) { accountDao.deleteAccount(id); } public void transfer(String sourceName, String targetName, Float money) { System.out.println("transfer..."); //根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //转出账户减钱 source.setMoney(source.getMoney()-money); //转入账户加钱 target.setMoney(target.getMoney()+money); //更新转出账户 accountDao.updateAccount(source); int i=1/0; //更新转入账户 accountDao.updateAccount(target); }}

ConnectionUtils类:

package com.qublog.utils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import javax.sql.DataSource;import java.sql.Connection;//连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定@Component("connectionUtils")public class ConnectionUtils {       private ThreadLocal
tl = new ThreadLocal
(); @Autowired private DataSource dataSource; //获取当前线程上的连接 public Connection getThreadConnection() { try { //先从ThreadLocal上获取 Connection conn = tl.get(); //判断当前线程上是否有连接 if (conn == null) { //从数据源中获取一个连接,并且存入ThreadLocal中 conn = dataSource.getConnection(); tl.set(conn); } //返回当前线程上的连接 return conn; } catch (Exception e) { throw new RuntimeException(e); } } //把连接和线程解绑 public void removeConnection() { tl.remove(); }}

TransactionManager类:

package com.qublog.utils;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;//和事务管理相关的工具类,包含了,开启事务,提交事务,回滚事务,释放连接@Component("txManager")@Aspectpublic class TransactionManager {       @Autowired    private ConnectionUtils connectionUtils;    @Pointcut("execution(* com.qublog.service.impl.*.*(..))")    private void pt1() {   }    //开启事务    public void beginTransaction() {           try {               connectionUtils.getThreadConnection().setAutoCommit(false);        } catch (Exception e) {               e.printStackTrace();        }    }    //提交事务    public void commit() {           try {               connectionUtils.getThreadConnection().commit();        } catch (Exception e) {               e.printStackTrace();        }    }    //回滚事务    public void rollback() {           try {               connectionUtils.getThreadConnection().rollback();        } catch (Exception e) {               e.printStackTrace();        }    }    //释放连接    public void release() {           try {               connectionUtils.getThreadConnection().close();//还回连接池中            connectionUtils.removeConnection();        } catch (Exception e) {               e.printStackTrace();        }    }    @Around("pt1()")    public Object aroundAdvice(ProceedingJoinPoint pjp) {           Object rtValue = null;        try {               //获取参数            Object[] args = pjp.getArgs();            //开启事务            this.beginTransaction();            //执行方法            rtValue = pjp.proceed(args);            //提交事务            this.commit();            //返回结果            return rtValue;        } catch (Throwable t) {               //回滚事务            this.rollback();            throw new RuntimeException(t);        } finally {               //释放资源            this.release();        }    }}

bean.xml

AccountServiceTest类:

package com.qublog.test;import com.qublog.service.AccountService;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;//使用Junit单元测试,测试我们的配置@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath:bean.xml")public class AccountServiceTest {       @Autowired    private AccountService as;    @Test    public void testTransfer() {           as.transfer("aaa","bbb",100f);    }}

转载地址:http://dfchz.baihongyu.com/

你可能感兴趣的文章
Mysql-存储引擎
查看>>
mysql-开启慢查询&所有操作记录日志
查看>>
MySQL-数据目录
查看>>
MySQL-数据页的结构
查看>>
MySQL-架构篇
查看>>
MySQL-索引的分类(聚簇索引、二级索引、联合索引)
查看>>
Mysql-触发器及创建触发器失败原因
查看>>
MySQL-连接
查看>>
mysql-递归查询(二)
查看>>
MySQL5.1安装
查看>>
mysql5.5和5.6版本间的坑
查看>>
mysql5.5最简安装教程
查看>>
mysql5.6 TIME,DATETIME,TIMESTAMP
查看>>
mysql5.6.21重置数据库的root密码
查看>>
Mysql5.6主从复制-基于binlog
查看>>
MySQL5.6忘记root密码(win平台)
查看>>
MySQL5.6的Linux安装shell脚本之二进制安装(一)
查看>>
MySQL5.6的zip包安装教程
查看>>
mysql5.7 for windows_MySQL 5.7 for Windows 解压缩版配置安装
查看>>
Webpack 基本环境搭建
查看>>