博客
关于我
基于注解的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/

你可能感兴趣的文章
mysql5.7的安装和Navicat的安装
查看>>
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>
mysql8的安装与卸载
查看>>
MySQL8,体验不一样的安装方式!
查看>>
MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
查看>>
Mysql: 对换(替换)两条记录的同一个字段值
查看>>
mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
查看>>