Spring整合JDBC实现转账业务

1, 整体的项目结构

 

 2,项目所需要的依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
        </dependency>
    </dependencies>

 3,实体类 Account

        实体类Account与我们的数据库字段对应即可,提供setter和getter,后期如果想查看对象,我们可以重写toString(方法)

package com.offcn.bean;

import java.io.Serializable;

public class Account implements Serializable {
    private Integer id;
    private String name;
    private double 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 double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

 4,创建工具类

        ConnectionUtils,这个工具类我们是主要获取我们的Connection,管理我们的Connection,

在这里面我们遇到了一个新的对象ThreadLocal,这个对象我需要说一下,这个是线程的对象的局部变量,在其内部,维护了一个Map集合,Map<Thread,Object> map = new HashMap<>();   这个ThreadLocal对象,赋值的通过set(传的是Object),取值通过get(),移除通过remove(),操作的时候, key不需要指定,当前线程对象做key。具体方式,如下代码演示:

    // set 
     public void set(Object obj){
         map.put(CurrentThread,obj);//key 不需要指定,默认是当前线程对象。
     }
     //get
     public Object get(){
         return map.get(CurrentThread);
     }
     // remove 移除
     public Object remove(){
         return map.remove(currentThread);
     }

package com.offcn.utils;

import javax.sql.DataSource;
import java.sql.Connection;

public class ConnectionUtils {
    //创建线程局部变量
    static ThreadLocal<Connection> threadLocal = new ThreadLocal();
    // Connection 是从我们数据源中获取
    private static DataSource dataSource;


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

    public DataSource getDataSource() {
        return dataSource;
    }

    // 创建方式 获取我们的Connection,包装获取的是同一个conn对象
    public Connection getConnection() throws Exception {
        Connection connection = threadLocal.get();
        if (connection == null) {
            // 从C3P0文件里面进行获取
            connection = dataSource.getConnection();
            // 绑定在当前线程的局部变量
            threadLocal.set(connection);
        }
        return connection;
    }

    // 从线程中进行解绑
    public void remove() {
        threadLocal.remove();
    }
}

         TxManager:是管理事务的工具类,主要定义了和事务相关的方法,例如:事务的开启,事务的提交,事务的回滚操作等。该工具类目前需要手动创建和管理,使用Spring进行事务管理后,该工具类由Spring提供,不需要手动编写和管理。所以该工具类重在理解,为Spring进行事务管理做好铺垫

package com.offcn.utils;

import java.sql.Connection;
import java.sql.SQLException;

public class TxManager {
    // 创建ConnectionUtils
    private ConnectionUtils connectionUtils;

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

    public ConnectionUtils getConnectionUtils() {
        return connectionUtils;
    }

    // 创建开启事物的方法
    public void beginTransaction() {
        try {
            // 获取我们的连接对象 //开启事务
         connectionUtils.getConnection().setAutoCommit(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 创建提交事物的方法
    public void commit() {
        try {
            // 提交事务
            connectionUtils.getConnection().commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 创建事务回滚
    public void rollback() {
        try {
           connectionUtils.getConnection().rollback();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 释放资源
    public void close() throws Exception {
        connectionUtils.getConnection().close();
    }
}

 5, 所需资源

dbConfig.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/xxxxx
jdbc.username=root
jdbc.password=root

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <context:property-placeholder location="classpath:dbConfig.properties"/>
<!--    创建dataSource对象-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
<!--    创建ConnectionUtils对象,里面有dataSource属性,需要通过ioc创建对象-->
    <bean class="com.offcn.utils.ConnectionUtils" id="connectionUtils">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    创建txManager 对象,里面需要ConnectionUtils对象-->
    <bean id="txManager" class="com.offcn.utils.TxManager">
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>
<!--    创建QueryRunner 对象-->
    <bean id="qr" class="org.apache.commons.dbutils.QueryRunner"></bean>
<!--这里是AccountDao对象  其内部有两个属性,分别为 QueryRunner 和 ConnectionUtils 对象-->
    <bean id="accountDao" class="com.offcn.dao.impl.AccountDaoImpl">
        <property name="qr" ref="qr"></property>
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>
<!--    这里我们是需要对我们的业务做事务处理,所以我们在这里面创建AccountService对象-->
    <bean id="accountService" class="com.offcn.service.impl.AccountServiceImpl">
<!--        其内部,我们需要对其中的属性进行赋值,我们发现accountDao 和 txManager 属性为对象,
            所以我们继续通过ioc创建对象-->
        <property name="accountDao" ref="accountDao"></property>
        <property name="txManager" ref="txManager"></property>
    </bean>

</beans>

6, 数据访问层

AccountDao 数据库访问层,我们定义根据名字查询用户,通过用户修改数据即可

public interface AccountDao {
    public Account findByName(String name);
    public void update(Account account);
}

AccountDaoImpl 

package com.offcn.dao.impl;

import com.offcn.bean.Account;
import com.offcn.dao.AccountDao;
import com.offcn.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

public class AccountDaoImpl implements AccountDao {

    //我们通过ioc来获取QueryRunner对象 和 ConnectionUtils对象
    private ConnectionUtils connectionUtils;
    QueryRunner qr;

    public ConnectionUtils getConnectionUtils() {
        return connectionUtils;
    }

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

    public QueryRunner getQr() {
        return qr;
    }

    public void setQr(QueryRunner qr) {
        this.qr = qr;
    }

    @Override
    public Account findByName(String name) {
        String sql = "select * from account where name = ?";
        try {
            return qr.query(connectionUtils.getConnection(), sql, new BeanHandler<Account>(Account.class), name);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过查询到的用户名,进行数据修改
     */
    @Override
    public void update(Account account) {
        String sql = "update account set money = ? where name = ?";
        try {
            qr.update(connectionUtils.getConnection(), sql, account.getMoney(), account.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7, 业务处理层

 AccountService: 我们的事务处理需要在业务处理层处理

public interface AccountService {
    /**
     * 根据账户名查询账户信息
     *
     * @param outName 账户名
     * @param inName  账户名
     * @param money   转账金额
     */
    public void transfer(String outName, String inName, double money);
}

AccountServiceImpl

package com.offcn.service.impl;

import com.offcn.bean.Account;
import com.offcn.dao.AccountDao;
import com.offcn.service.AccountService;
import com.offcn.utils.TxManager;

public class AccountServiceImpl implements AccountService {

    // 引入事务相关的代码
    private TxManager txManager;
    private AccountDao accountDao;

    public TxManager getTxManager() {
        return txManager;
    }

    public void setTxManager(TxManager txManager) {
        this.txManager = txManager;
    }

    public AccountDao getAccountDao() {
        return accountDao;
    }

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void transfer(String outName, String inName, double money) {

        try {
            // 开启事务
            txManager.beginTransaction();
            // 查询用户
            Account byName = accountDao.findByName(outName); // 来源
            Account byName2 = accountDao.findByName(inName); // 目标

            // 更改用户余额
            byName.setMoney(byName.getMoney() - money); // 来源
            byName2.setMoney(byName2.getMoney() + money);//目标
            //更新数据库
            accountDao.update(byName);
            //int i = 1 / 0;
            accountDao.update(byName2);
            // 事务提交
            txManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //回滚
            txManager.rollback();
        } finally {
            try {
                // 关闭连接
                txManager.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

8, 测试

package com.offcn.mytest;

import com.offcn.service.AccountService;
import com.offcn.service.impl.AccountServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest01 {
    @Autowired
    private AccountService accountService;

    @Test
    public void test01() {
        accountService.transfer("aaa", "bbb", 100D);

    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不不就不

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值