Spring基础--基于XML配置的事务控制

以AOP的方式实现对事务的控制
相关坐标的导入pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>day02_XmlIocCase</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>day02_XmlIocCase</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.6</version>
    </dependency>
    <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.7</version>
    </dependency>
    <dependency>
      <groupId>c3p0</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.1.2</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.7</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <!--添加配置跳过测试-->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
          <configuration>
            <skipTests>true</skipTests>
          </configuration>
        </plugin>
        <!--添加配置跳过测试-->
      </plugins>
    </pluginManagement>
  </build>
</project>

1.用户实体类

/*
* 用户实体类
* */
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 +
                '}';
    }
}

2.持久层接口

/*
* 账户的持久层接口
* */
public interface IAccountDao {
    
    
    // 查询所有
    List<Account> findAll();

    // 根据id查询
    Account findById(Integer accountId);

    // 插入数据
    void insert(Account account);

    // 更新数据
    void update(Account account);

    // 根据Id删除数据
    void delete(Integer accountId);

    // 根据姓名查找
    Account findByName(String name);

}

3.持久层实现类

/*
* 永久层实现类
* */
public class AccountDaoImpl implements IAccountDao {
    
    
    private QueryRunner queryRunner;
    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
    
    
        this.connectionUtils = connectionUtils;
    }

    public void setQueryRunner(QueryRunner queryRunner) {
    
    
        this.queryRunner = queryRunner;
    }

    @Override
    public List<Account> findAll() {
    
    
        try{
    
    
            return queryRunner.query(connectionUtils.getThreadConnection(),"select *from account", new BeanListHandler<Account>(Account.class));
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findById(Integer accountId) {
    
    
        try{
    
    
            return queryRunner.query(connectionUtils.getThreadConnection(),"select *from account where id = ?", new BeanHandler<Account>(Account.class), accountId);
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void insert(Account account) {
    
    
        try{
    
    
            queryRunner.update(connectionUtils.getThreadConnection(),"insert into account(name,money)values (?,?)", account.getName(),account.getMoney());
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void update(Account account) {
    
    
        try{
    
    
            queryRunner.update(connectionUtils.getThreadConnection(),"update account set name = ?, money = ? where id = ?", account.getName(), account.getMoney(), account.getId());
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void delete(Integer accountId) {
    
    
        try{
    
    
            queryRunner.update(connectionUtils.getThreadConnection(),"delete from account where id = ?", accountId);
        }catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findByName(String name) {
    
    
        try{
    
    
            List<Account> accounts = queryRunner.query(connectionUtils.getThreadConnection(),"select *from account where name = ?", new BeanListHandler<Account>(Account.class), name);
            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);
        }
    }
}

4.连接工具类

/**
 * 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定
 */
public class ConnectionUtils {
    
    

    private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
    
    
        this.dataSource = dataSource;
    }

    /**
     * 获取当前线程上的连接
     * @return
     */
    public Connection getThreadConnection() {
    
    
        try{
    
    
            //1.先从ThreadLocal上获取
            Connection conn = tl.get();
            //2.判断当前线程上是否有连接
            if (conn == null) {
    
    
                //3.从数据源中获取一个连接,并且存入ThreadLocal中
                conn = dataSource.getConnection();
                tl.set(conn);
            }
            //4.返回当前线程上的连接
            return conn;
        }catch (Exception e){
    
    
            throw new RuntimeException(e);
        }
    }

    /**
     * 把连接和线程解绑
     */
    public void removeConnection(){
    
    
        tl.remove();
    }
}

5.事务控制工具类

/**
 * 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
 */
public class TransactionManager {
    
    

    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
    
    
        this.connectionUtils = connectionUtils;
    }

    /**
     * 开启事务
     */
    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();
        }
    }
}

6.业务层接口

/*
* 业务层接口
* */
public interface AccountService {
    
    
    // 查询所有
    List<Account> findAll();

    // 根据id查询
    Account findById(Integer accountId);

    // 插入数据
    void insert(Account account);

    // 更新数据
    void update(Account account);

    // 根据Id删除数据
    void delete(Integer accountId);

    // 转账操作
    void transAccount(String sendName, String targetName, Float money);
}

7.业务层实现类

/*
* 业务层接口的实现类
* */
public class IAccountServiceImpl implements AccountService {
    
    

    private IAccountDao accountDao;

    // 通过set方法来让spring自动注入accountDao
    public void setAccountDao(IAccountDao accountDao) {
    
    
        this.accountDao = accountDao;
    }

    @Override
    public List<Account> findAll() {
    
    
        return accountDao.findAll();
    }

    @Override
    public Account findById(Integer accountId) {
    
    
        return accountDao.findById(accountId);
    }

    @Override
    public void insert(Account account) {
    
    
        accountDao.insert(account);
    }

    @Override
    public void update(Account account) {
    
    
        accountDao.update(account);
    }

    @Override
    public void delete(Integer accountId) {
    
    
        accountDao.delete(accountId);
    }

    @Override
    public void transAccount(String sendName, String targetName, Float money) {
    
    
        System.out.println("11111");
        // 1.查询转账人信息
        Account account1 = accountDao.findByName(sendName);
        // 2.查询接受人信息
        Account account2 = accountDao.findByName(targetName);
        // 3.转账人减去对应金额
        float money1 = account1.getMoney();
        account1.setMoney(money1 - money);

//        int a = 1/0;
        // 4.接受人加上对应的金额
        float money2 = account2.getMoney();
        account2.setMoney(money2 + money);
        // 5.刷新转账人和接受人信息
        accountDao.update(account1);
        accountDao.update(account2);

        System.out.println("转账完毕");
    }
}

8.配置bean.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


         <!-- 配置service -->
        <bean id="accountService" class="org.example.service.impl.IAccountServiceImpl">
            <!-- 注入dao -->
            <property name="accountDao" ref="accountDao"></property>
        </bean>

        <!-- 配置dao对象 -->
        <bean id="accountDao" class="org.example.dao.impl.AccountDaoImpl">
            <!-- 注入QueryRunner -->
            <property name="queryRunner" ref="queryRunner"></property>
            <property name="connectionUtils" ref="connectionUtils"></property>
        </bean>

        <!-- 配置queryRunner -->
        <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
            <!-- 注入数据源 -->
<!--            <constructor-arg name="ds" ref="dataSource"></constructor-arg>-->
        </bean>

        <!-- 配置dataSource -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 连接数据库 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://121.41.229.122:3306/spring"></property>
            <property name="user" value="root"></property>
            <property name="password" value="123456"></property>
        </bean>

        <!-- 配置Connection的工具类 ConnectionUtils -->
        <bean id="connectionUtils" class="org.example.utils.ConnectionUtils">
            <!-- 注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!-- 配置事务管理器-->
        <bean id="txManager" class="org.example.utils.TransactionManager">
            <!-- 注入ConnectionUtils -->
            <property name="connectionUtils" ref="connectionUtils"></property>
        </bean>
        <!-- 配置AOP -->
        <aop:config>
            <!-- 配置切面 -->
            <aop:aspect id="manager" ref="txManager">
                <!-- 配置切入点信息 -->
                <aop:pointcut id="pt" expression="execution(* org.example.service.*.*(..))"/>
                <!-- 前置通知,开启事务 -->
                 <aop:before method="beginTransaction" pointcut-ref="pt"></aop:before>   
                <!-- 配置后置通知,提交事务 -->
                <aop:after-returning method="commit" pointcut-ref="pt"></aop:after-returning>
                <!-- 配置异常通知,回滚事务-->
                <aop:after-throwing method="rollback" pointcut-ref="pt"></aop:after-throwing>
                <!-- 配置最终通知,释放连接 -->
                <aop:after method="release" pointcut-ref="pt"></aop:after>
            </aop:aspect>
        </aop:config>
</beans>

9.测试

/**
 * Unit test for simple App.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    
    "classpath:bean.xml"})
public class AppTest 
{
    
    
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
    
    
        assertTrue( true );
    }

   @Autowired
           @Qualifier("accountService")
    private AccountService as;
   
    @Test
    public void aopControl() {
    
    
        
        //3、使用
        as.transAccount("aaa","bbb",100f);
    }
}

最终转账成功,如果中间发生错误,事务回滚,不提交。

猜你喜欢

转载自blog.csdn.net/qq_44660367/article/details/108763587