单表CURD-基于事务

单表CURD-基于事务_第1张图片

 

 配置文件:

jdbc.driver=org.h2.Driver
jdbc.url=jdbc:h2:file:~/.h2/h2
jdbc.username=root
jdbc.password=123456

pom文件

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.0modelVersion>

    <groupId>org.examplegroupId>
    <artifactId>exampleartifactId>
    <version>1.0-SNAPSHOTversion>

    <packaging>jarpackaging>

    <dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.2.7.RELEASEversion>
        dependency>
        <dependency>
            <groupId>commons-dbutilsgroupId>
            <artifactId>commons-dbutilsartifactId>
            <version>1.7version>
        dependency>
        <dependency>
            <groupId>com.h2databasegroupId>
            <artifactId>h2artifactId>
            <version>1.4.200version>
        dependency>
        <dependency>
            <groupId>c3p0groupId>
            <artifactId>c3p0artifactId>
            <version>0.9.1.2version>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-testartifactId>
            <version>5.2.7.RELEASEversion>
        dependency>
    dependencies>

    <repositories>
        <repository>
            <id>alimavenid>
            <name>aliyun mavenname>
            <url>http://maven.aliyun.com/nexus/content/groups/public/url>
            <releases>
                <enabled>trueenabled>
            releases>
            <snapshots>
                <enabled>falseenabled>
            snapshots>
        repository>
    repositories>

    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <java.version>14java.version>
        <maven.compiler.source>14maven.compiler.source>
        <maven.compiler.target>14maven.compiler.target>
        <encoding>UTF-8encoding>
    properties>

project>

代码:

package com.example.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:jdbcConfig.properties")
public class Config {

    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String pass;

    @Bean("runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(){
        return new QueryRunner();
    }
    @Bean("dataSource")
    public DataSource getDataSource() {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        try {
            dataSource.setDriverClass(driver);
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
        dataSource.setJdbcUrl(url);
        dataSource.setUser(user);
        dataSource.setPassword(pass);
        return dataSource;
    }

}
package com.example.domain;

import java.io.Serializable;

/**
 * 账户的实现类
 */
public class Account implements Serializable {
    private int id;
    private String name;
    private float money;

    public Account() {}
    public Account(String name, int money) {
        this.name=name;
        this.money=money;
    }

    public Account(int id, String name, int money) {
        this.id=id;
        this.name=name;
        this.money=money;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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 +
                '}';
    }
}
package com.example.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

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

    private ThreadLocal tl = new ThreadLocal();

    @Autowired
    private DataSource dataSource;

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

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

        }
        //4. 返回当前线程上的链接
        return conn;
    }

    /**
     * 把链接和线程解绑
     */
    public void removeConnection(){
        tl.remove();
    }
}
package com.example.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.SQLException;

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

    int i=0;

    @Autowired
    private ConnectionUtils connectionUtils;

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

    /**
     * 开启事务
     */
    public void beginTransaction(){
        try {
            connectionUtils.getThreadConnection().setAutoCommit(false);
            i--;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    /**
     * 提交事务
     */
    public void commit(){
        if(i<0){
            i++;
            return;
        }
        try {
            connectionUtils.getThreadConnection().commit();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    /**
     * 回滚事务
     */
    public void rollback(){
        try {
            connectionUtils.getThreadConnection().rollback();
            i=0;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    /**
     * 释放事务
     */
    public void release(){
        if(i<0)return;
        try {
            connectionUtils.getThreadConnection().close();
            connectionUtils.removeConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
package com.example.service;

import com.example.domain.Account;

import java.util.List;

/**
 * 账户的业务层接口
 */
public interface IAccountService {
    /**
     * 查询所有
     * @return
     */
    List findAllAccount();

    /**
     * 查询一个
     * @param id
     * @return
     */
    Account findAccountById(int id);

    /**
     * 保存账户
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新账户
     * @param account
     */
    void updateAccount(Account account);

    /**
     * 删除账户
     * @param id
     */
    void deleteAccount(int id);

    /**
     * 转账
     * @param sourceName
     * @param targetName
     * @param money
     */
    void transfer(String sourceName,String targetName,float money);

}
package com.example.service.impl;

import com.example.dao.IAccountDao;
import com.example.domain.Account;
import com.example.service.IAccountService;
import com.example.utils.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao;
    @Autowired
    private TransactionManager tm;

    public IAccountDao getAccountDao() {
        return accountDao;
    }

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

    @Override
    public List findAllAccount() {
        List accounts=null;
        tm.beginTransaction();
        try{
            accounts= accountDao.findAllAccount();
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            e.printStackTrace();
        }finally {
            tm.release();
        }
        return accounts;
    }

    @Override
    public Account findAccountById(int id) {
        return accountDao.findAccountById(id);
    }

    @Override
    public void saveAccount(Account account) {
        tm.beginTransaction();
        try{
            accountDao.saveAccount(account);
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            e.printStackTrace();
        }finally {
            tm.release();
        }

    }

    @Override
    public void updateAccount(Account account) {
        tm.beginTransaction();
        try{
            accountDao.updateAccount(account);
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            e.printStackTrace();
        }finally {
            tm.release();
        }

    }

    @Override
    public void deleteAccount(int id) {
        tm.beginTransaction();
        try{
            accountDao.deleteAccount(id);
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            e.printStackTrace();
        }finally {
            tm.release();
        }

    }

    @Override
    public void transfer(String sourceName, String targetName, float money) {
        tm.beginTransaction();
        try {
            //1. 根据名称查询转出账户
            Account sourceAccount = accountDao.findAccountByName(sourceName);
            System.out.println(sourceAccount);
            //2. 根据名称查询转入账户
            Account targetAccount = accountDao.findAccountByName(targetName);
            System.out.println(targetAccount);
            //3. 转出账户减钱
            sourceAccount.setMoney(sourceAccount.getMoney() - money);
            System.out.println(sourceAccount);
            //4. 转入账户加钱
            targetAccount.setMoney(targetAccount.getMoney() + money);
            System.out.println(targetAccount);
            //5. 更新转出账户
            updateAccount(sourceAccount);
            int i=1/0;
            //6. 更新转入账户
            updateAccount(targetAccount);
            tm.commit();
        }catch (Exception e){
            tm.rollback();
            e.printStackTrace();
        }finally {
            tm.release();
        }


    }
}
package com.example.dao;

import com.example.domain.Account;

import java.util.List;

/**
 * 账户的持久层接口
 */
public interface IAccountDao {
    /**
     * 查询所有
     * @return
     */
    List findAllAccount();

    /**
     * 查询一个
     * @param id
     * @return
     */
    Account findAccountById(int id);

    /**
     * 保存账户
     * @param account
     */
    void saveAccount(Account account);

    /**
     * 更新账户
     * @param account
     */
    void updateAccount(Account account);

    /**
     * 删除账户
     * @param id
     */
    void deleteAccount(int id);

    /**
     * 通过名称查账户,唯一
     * @param accoutName
     * @return
     */
    Account findAccountByName(String accoutName);
}
package com.example.dao.impl;

import com.example.dao.IAccountDao;
import com.example.domain.Account;
import com.example.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.context.annotation.Scope;
import org.springframework.stereotype.Repository;

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

/**
 * 账户的持久层实现类
 */
@Repository
public class AccountDaoImpl implements IAccountDao {
    @Autowired
    private QueryRunner runner;
    @Autowired
    private ConnectionUtils connectionUtils;

    public QueryRunner getRunner() {
        return runner;
    }

    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

    @Override
    public List findAllAccount() {
        try {
            return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler(Account.class));
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);
        }
    }

    @Override
    public Account findAccountById(int id) {
        try {
            return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ?",new BeanHandler(Account.class),id);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);
        }
    }

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

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

    @Override
    public void deleteAccount(int id) {
        try {
            runner.update(connectionUtils.getThreadConnection(),"delete account where id = ?",id);
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);
        }
    }

    @Override
    public Account findAccountByName(String accoutName) {
        try {
            List accounts=runner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",new BeanListHandler(Account.class),accoutName);
            if(accounts==null||accounts.size()==0){
                return null;
            }else if(accounts.size()>1){
                throw new RuntimeException("结果集不唯一,数据有问题");
            }else {
                return accounts.get(0);
            }
        } catch (SQLException throwables) {
            throw new RuntimeException(throwables);
        }
    }
}

测试:

package com.example;

import com.example.config.Config;
import com.example.domain.Account;
import com.example.service.IAccountService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

/**
 * Spring整合JUnit单元测试,测试我们的配置
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class AccountServiceTest {

    @Autowired
    IAccountService as;

    @Test
    public void testFindAll() {
        List accounts = as.findAllAccount();
        for(Account account : accounts){
            System.out.println(account);
        }
    }
    @Test
    public void testFindOne() {
        Account account=as.findAccountById(1);
        System.out.println(account);
    }
    @Test
    public void testSave() {
        Account account=new Account("account4",100);
        as.saveAccount(account);
    }
    @Test
    public void testTransfer() {
        as.transfer("account1","account3",100);
    }
    @Test
    public void testUpdate() {
        Account account=new Account(3,"ddd",100);
        as.updateAccount(account);
    }
    @Test
    public void testDelete() {
        as.deleteAccount(2);
    }
}

 

你可能感兴趣的:(单表CURD-基于事务)