记录Kite的学习历程之springCRUD操作

Kite学习框架的第九天

1.在创建的CRUD操作中添加一个转账操作

(因为存在了转账操作,我们需要在一个线程上运行,并且将数据库连接绑定到线程上)

1.1 首先创建一个utils包,创建一个connectionUtils类

其中包括了:
1.创建一个ThreadLocal获取当前线程
ThreadLocal作用:
1.1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
1.2、线程间数据隔离
1.3、进行事务操作,用于存储线程事务信息。
1.4、数据库连接,Session会话管理。
2. 获取数据连接源
使用dataSource
3.创建一个获取连接的方法,并且将当前的连接绑定当前线程
4.创建一个与线程解绑的方法

package cn.kitey.utils;

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

/**
 * 连接的工具类,用于获取数据源中的一个连接,并且实现线程的绑定
 */
public class ConnectionUtils {
    private ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
    DataSource dataSource;

    /**
     * 用于从IOC中注入
     * @param dataSource
     */
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Connection getThreadConnection(){
        try {
            //1.先从ThreadLocal上获取
            Connection conn = threadLocal.get();
            //2.判断当前线程上是否存在连接
            if(conn == null){
                conn = dataSource.getConnection();
                threadLocal.set(conn);
            }
            //返回当前线程的连接
            return conn;
        } catch (SQLException e) {

            throw new RuntimeException(e);
        }


    }

    /**
     * 把连接与线程解绑了
     */
    public void removeConnection(){
        //移除连接
        threadLocal.remove();

    }
}


1.2 创建一个事务管理的方法类TransactionManger


package cn.kitey.utils;

import java.sql.SQLException;

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

    private ConnectionUtils connectionUtils;

    /**
     * 定义set方法,可以通过IOC容器注入
     * @param connectionUtils
     */
    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    /**
     * 开启事务
     */
    public void beginTransaction(){
        try {
            connectionUtils.getThreadConnection().setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    /**
     * 提交事务
     */
    public void commitTransaction(){
        try {
            connectionUtils.getThreadConnection().commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 回滚事务
     */
    public void rollbackTransaction(){
        try {
            connectionUtils.getThreadConnection().rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放事务
     */
    public void relaseTransaction(){
        try {
            //将连接归还到数据连接池
            connectionUtils.getThreadConnection().close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


}

1.3 这时因为我们获取了新的连接,所以需要去吃bean.xml中的数据连接`

`其中可以不用获取数据连接

 <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">

    </bean>

1.4 在AccountDaoImpl中在CURD操作前加上数据连接

首相需要创建一个 private ConnectionUtils connectionUtils;
并设置set方法用于数据的注入
例如:
在query()方法中加上了connectionUtils.getThreadConnection()


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

    }

全部代码


package cn.kitey.dao.impl;

import cn.kitey.dao.AccountDao;
import cn.kitey.domain.Account;
import cn.kitey.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

/**
 * 持久层实现类
 */

public class AccountDaoImpl implements AccountDao {
    private QueryRunner queryRunner;
    private ConnectionUtils connectionUtils;

    /**
     * 从spring中注入相关数据
     * @param connectionUtils
     */
    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    /**
     * 从spring中配置
     * @param queryRunner
     */
    public void setQueryRunner(QueryRunner queryRunner) {
        this.queryRunner = queryRunner;
    }

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

    }

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

    }

    public void saveAccount(Account account) {
        try {
            queryRunner.update(connectionUtils.getThreadConnection(),"insert into account(id,uid, money) values(?,?,?)", account.getId(),account.getUid(),account.getMoney());
        } catch (SQLException e) {
            throw new  RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try {
            queryRunner.update(connectionUtils.getThreadConnection(),"update account set uid = ?, money = ?  where id = ?", account.getUid(),account.getMoney(),account.getId());
        } catch (SQLException e) {
            throw new  RuntimeException(e);
        }
    }

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

    public Account findAccountByName(String accountName) {
        try {
            List<Account> accounts = queryRunner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",
                    new BeanListHandler<Account>(Account.class),accountName);
            if(accounts == null|| accounts.size() == 0){
                return null;
            }else if(accounts.size() > 1){
                throw new RuntimeException("结果不唯一,数据错误");
            }else{
                return accounts.get(0);
            }
        } catch (SQLException e) {
            throw new  RuntimeException(e);
        }
    }
}


1.5 在AccountServiceImpl中添加一个转账方法

还需现在接口中先添加对应的方法



    /**
     * 这里需要在同一个线程中只有一个能控制事务对象
     * @param sourceId
     * @param targetId
     * @param money
     */
    public void transfer(Integer sourceId, Integer targetId, double money) {

        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作

            //2.1.根据名称查询传出账户
            Account source = accountDao.findById(sourceId);
            //2.2.根据id
            Account target = accountDao.findById(targetId);
            //2.3.转出账户减钱
            source.setMoney(source.getMoney() - money);

            int i =  10/0;

            //2.4.转入账户加钱
            target.setMoney(target.getMoney() + money);
            //2.5.更新转出账户
            accountDao.updateAccount(source);
            //2.6.更新转入账户
            accountDao.updateAccount(target);
            //3.提交事务
            tManger.commitTransaction();

        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }



    }

全部代码(添加了事务的CRUD操作)
首相要获取事务方法,并且提供set方法

package cn.kitey.service.impl;

import cn.kitey.dao.AccountDao;
import cn.kitey.dao.impl.AccountDaoImpl;
import cn.kitey.domain.Account;
import cn.kitey.service.AccountService;
import cn.kitey.utils.TransactionManger;

import java.util.List;

/**
 * 账户的业务实现层
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    private TransactionManger tManger;

    public void settManger(TransactionManger tManger) {
        this.tManger = tManger;
    }

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

    /**
     * 通过IOC容器进行配置
     * @param accountDao
     */
    public void setAccountDao(AccountDaoImpl accountDao) {
        this.accountDao=accountDao;
    }

    public List<Account> findAll() {
        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作
            List<Account> list = accountDao.findAll();
            //3.提交事务
            tManger.commitTransaction();
            //4.返回结果
            return  list;
        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }
    }

    public Account findById(Integer accountId) {
        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作
            Account byId = accountDao.findById(accountId);
            //3.提交事务
            tManger.commitTransaction();
            //4.返回结果
            return byId;
        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }

    }

    public void saveAccount(Account account) {
        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作
            accountDao.saveAccount(account );
            //3.提交事务
            tManger.commitTransaction();
        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }

    }

    public void updateAccount(Account account) {
        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作
            accountDao.updateAccount(account);
            //3.提交事务
            tManger.commitTransaction();
        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }

    }

    public void deleteAccount(Integer accountId) {
        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作
            accountDao.deleteAccount(accountId);
            //3.提交事务
            tManger.commitTransaction();
        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }


    }


    /**
     * 这里需要在同一个线程中只有一个能控制事务对象
     * @param sourceId
     * @param targetId
     * @param money
     */
    public void transfer(Integer sourceId, Integer targetId, double money) {

        try {
            //1.开启事务
            tManger.beginTransaction();
            //2.执行操作

            //2.1.根据名称查询传出账户
            Account source = accountDao.findById(sourceId);
            //2.2.根据id
            Account target = accountDao.findById(targetId);
            //2.3.转出账户减钱
            source.setMoney(source.getMoney() - money);

            int i =  10/0;

            //2.4.转入账户加钱
            target.setMoney(target.getMoney() + money);
            //2.5.更新转出账户
            accountDao.updateAccount(source);
            //2.6.更新转入账户
            accountDao.updateAccount(target);
            //3.提交事务
            tManger.commitTransaction();

        } catch (Exception e) {
            //5.回滚操作
            tManger.rollbackTransaction();
            //产生错误了,程序就不在继续运行
            throw new RuntimeException(e);
        } finally {
            //6.释放连接
            tManger.relaseTransaction();
        }



    }


}

1.6 在bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置Service-->
    <bean id="accountService" class="cn.kitey.service.impl.AccountServiceImpl">
        <!--注入dao-->
        <property name="accountDao" ref="accountDao"></property>
        <!--注入事务管理器-->
        <property name="tManger" ref="tManger"></property>
    </bean>

    <!--配置Dao对象-->
    <bean id="accountDao" class="cn.kitey.dao.impl.AccountDaoImpl">
        <!-- 注入QueryRunner -->
        <property name="queryRunner" ref="runner"></property>
        <!--注入connectionUtils数据-->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>

    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">

    </bean>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT%2B8"></property>
        <property name="user" value="root"></property>
        <property name="password" value="25002500"></property>
    </bean>

    <!--配置Connection的工具类,ConnectionUtils-->
    <bean id = "connectionUtils" class="cn.kitey.utils.ConnectionUtils">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置Connection工具类中的:TransactionManger-->
    <bean id="tManger" class="cn.kitey.utils.TransactionManger">
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>
</beans>

1.7 编写测试类 进行测试

package cn.kitey.test;

import cn.kitey.domain.Account;
import cn.kitey.service.AccountService;
import cn.kitey.service.impl.AccountServiceImpl;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

import static org.junit.Assert.*;

public class AccountServiceTest {
    private  AccountService xmlBean;

    @Before
    public void init(){
        ApplicationContext xml = new ClassPathXmlApplicationContext("bean.xml");
         xmlBean = xml.getBean("accountService", AccountServiceImpl.class);

    }



    @Test
    public void transfer(){
        xmlBean.transfer(1,2,100);
    }

    @Test
    public void findAll() {
        List<Account> all = xmlBean.findAll();
        System.out.println("findAll()数据结果为:");
        for (Account account : all) {
            System.out.println(account);
        }
    }

    @Test
    public void findById() {
        Account byId = xmlBean.findById(1);
        System.out.println(byId);
    }

    @Test
    public void saveAccount() {
        Account acc = new Account();
        acc.setId(6);
        acc.setUid(1);
        acc.setMoney(123456);
        xmlBean.saveAccount(acc);
        List<Account> all = xmlBean.findAll();
        for (Account account : all) {
            System.out.println("进行数据插入后的结果:");
            System.out.println(account);
        }
    }

    @Test
    public void updateAccount() {
        Account acc = new Account(6, 1, 8888);
        xmlBean.updateAccount(acc);
        List<Account> all = xmlBean.findAll();
        for (Account account : all) {
            System.out.println("进行数据更新后的结果后的结果:");
            System.out.println(account);
        }
    }

    @Test
    public void deleteAccount() {
        xmlBean.deleteAccount(6);
        List<Account> all = xmlBean.findAll();
        for (Account account : all) {
            System.out.println("进行数据删除后的结果:");
            System.out.println(account);
        }
    }
}

你可能感兴趣的:(每天的学习笔记)