手动实现IOC与事务控制-基于JDBC-1

38 篇文章 0 订阅
2 篇文章 0 订阅

手动实现IOC与事务控制基于JDBC

sql

在这里插入图片描述

DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `name` varchar(50) NOT NULL COMMENT ' 姓名',
  `cardNo` varchar(50) NOT NULL COMMENT '卡号',
  `money` int(11) NOT NULL COMMENT '金额'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('张三', '123456', '10000');
INSERT INTO `account` VALUES ('李四', '456789', '10000');
新建项目

在这里插入图片描述
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">
    <parent>
        <artifactId>stage01-spring</artifactId>
        <groupId>com.liu</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-classroom</artifactId>
    <packaging>war</packaging>


    <dependencies>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>9099</port>
                    <path>/</path>
                    <server>tomcat7</server>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                   http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1"
         metadata-complete="false">


    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>
Servlet
package com.liu.spring.servlet;

import com.alibaba.fastjson.JSON;
import com.liu.spring.factory.BeanFactory;
import com.liu.spring.result.Result;
import com.liu.spring.service.TransferService;
import com.liu.spring.service.impl.TransferServcieImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;

/**
 * @Description
 * @ClassName TransferServlet
 * @Author 刘楠
 * @date 2020.06.24
 */
@WebServlet(name = "transferServlet",urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {
    /**
     * http mine,json类型
     */
    public static final String MIME_TYPE_JSON = "application/json";
    /**
     * http mine,json类型指定utf-8编码
     */
    public final static String MIME_TYPE_JSON_UTF8 = MIME_TYPE_JSON + ";charset=UTF-8";
    //1.实例化TransferService
    private TransferService transferService = new TransferServcieImpl();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求的字体编码
        req.setCharacterEncoding("UTF-8");

        String fromCardNo=req.getParameter("fromCardNo");
        String toCardNo=req.getParameter("toCardNo");
        String moneyValue = req.getParameter("money");
        Integer money = Integer.valueOf(moneyValue);

		 //默认就是200
        Result result = new Result();
        try {
           

            transferService.transfer(fromCardNo, toCardNo,money);
        } catch (Exception e) {
            e.printStackTrace();
            result.setResult(Result.ResultEnum.SERVER_ERROR);
        }

        //设置响应字符编码
        resp.setContentType(MIME_TYPE_JSON_UTF8);

        resp.getWriter().println(JSON.toJSON(result));

    }
}
##### Result 
```java

/**
 * @Description
 * @ClassName Result
 * @Author 刘楠
 * @date 2020.06.24
 */
public class Result<T> implements Serializable {

    private static final long serialVersionUID = -645547982453859521L;
    private Integer status;

    private String message;
    private T data;


    public Result() {
        this(ResultEnum.SUCCESS);
    }
    public Result(ResultEnum result) {
        setResult(result.getStatus(), result.getMessage());
    }
    public void setResult(ResultEnum result) {
        status = result.getStatus();
        message = result.getMessage();
    }

    public void setResult(int status, String message) {
        this.status = status;
        this.message = message;
    }


    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", Result.class.getSimpleName() + "[", "]")
                .add("status=" + status)
                .add("message='" + message + "'")
                .add("data=" + data)
                .toString();
    }

    public enum ResultEnum {
        SUCCESS(200),
        PARAM_ERROR(400),
        NO_AUTH(401),
        FORBIDDEN(403),
        SERVER_ERROR(500),
        FAILED(-1);

        private int status;
        private final static String[] initMsgs = { "执行成功","提交的数据错误","身份验证失败","无权限访问","执行错误","执行失败" };

        private ResultEnum(int status) {
            this.status = status;
        }

        public int getStatus() {
            return status;
        }

        /**
         * 返回结果描述.
         *
         * @return 结果描述String
         */
        public String getMessage() {
            switch (status) {
                case 200:
                    return initMsgs[0];
                case 400:
                    return initMsgs[1];
                case 401:
                    return initMsgs[2];
                case 403:
                    return initMsgs[3];
                case 500:
                    return initMsgs[4];
                case -1:
                    return initMsgs[5];
                default:
                    break;
            }
            return null;
        }
    }
}

service
public interface TransferService {

    boolean transfer(String fromAccount, String toAccount, Integer money) throws SQLException, Exception;
}

service 实体类
package com.liu.spring.service.impl;

import com.liu.spring.dao.AccountDao;
import com.liu.spring.dao.impl.AccountDaoImpl;
import com.liu.spring.entity.Account;
import com.liu.spring.factory.BeanFactory;
import com.liu.spring.service.TransferService;
import com.liu.spring.transaction.TransactionManager;
import com.liu.spring.util.ConnectionUtils;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Description
 * @ClassName TransferServcieImpl
 * @Author 刘楠
 * @date 2020.06.23
 */
public class TransferServcieImpl implements TransferService {

	private AccountDao accountDao = new AccountDaoImpl();

    @Override
    public boolean transfer(String fromAccount, String toAccount, Integer money) throws Exception {
        System.out.println("=====开始转账==== ");

      

            Account fAccount = accountDao.queryByCardNo(fromAccount);
            Account tAccount = accountDao.queryByCardNo(toAccount);

            fAccount.setMoney(fAccount.getMoney()-money);
            tAccount.setMoney(tAccount.getMoney()+money);
            accountDao.updateAccountByCardno(fAccount);
            //int i=1/0; 异常用于测试 事务
            accountDao.updateAccountByCardno(tAccount);

        return true;
    }

}

dao
public interface AccountDao {

    /**
     * 根据卡号查询
     * @param cardNo
     * @return
     */
     Account queryByCardNo(String cardNo) throws SQLException;

    int  updateAccountByCardno(Account fAccount) throws SQLException;
}

dao实现类
package com.liu.spring.dao.impl;

import com.alibaba.druid.pool.DruidPooledConnection;
import com.liu.spring.dao.AccountDao;
import com.liu.spring.entity.Account;
import com.liu.spring.util.ConnectionUtils;
import com.liu.spring.util.DruidUtils;

import javax.swing.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @Description
 * @ClassName AccountDaoImpl
 * @Author 刘楠
 * @date 2020.06.23
 */
public class AccountDaoImpl implements AccountDao {
    @Override
    public Account queryByCardNo(String cardNo) throws SQLException {
        //从连接池获取连接
		Connection connection = DruidUtils.getInstance().getConnection();
        System.out.println("queryByCardNo connection "+connection.toString());
        String sql = "select name ,cardNo ,money from account where cardNo=?";
        //预编译SQL
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //填充参数
        preparedStatement.setString(1, cardNo);
        //执行查询
        ResultSet resultSet = preparedStatement.executeQuery();
        Account account = null;
        while (resultSet.next()) {
            account = new Account();
            account.setMoney(resultSet.getInt("money"));
            account.setCardNo(resultSet.getString("cardNo"));
            account.setName(resultSet.getString("name"));
        }
        preparedStatement.close();
        connection.close(); 
        return account;
    }

    @Override
    public int updateAccountByCardno(Account fAccount) throws SQLException {
        Connection connection = DruidUtils.getInstance().getConnection();
     
        System.out.println("updateAccountByCardno connection "+connection.toString());
        String sql = "update account set money =? where cardNo=? ";
        //预编译SQL
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //设置参数
        preparedStatement.setInt(1, fAccount.getMoney());
        preparedStatement.setString(2, fAccount.getCardNo());
        //执行更新
        int update = preparedStatement.executeUpdate();
        preparedStatement.close();
        connection.close(); 
        return update;
    }
}

实体类
public class Account  implements Serializable {
    private static final long serialVersionUID = -6836411742270629093L;
    /**
     * 帐户名称
     */
    private String name;
    /**
     * 卡号
     */
    private String cardNo;
    /**
     * 金额,余额
     */
    private Integer money;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCardNo() {
        return cardNo;
    }

    public void setCardNo(String cardNo) {
        this.cardNo = cardNo;
    }

    public Integer getMoney() {
        return money;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }
}
工具类

DruidUtils

public class DruidUtils {

    private DruidUtils(){

    }
    private static DruidDataSource druidDataSource = new DruidDataSource();

    static {
        druidDataSource.setUrl("jdbc:mysql://127.0.0.1/bank?characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false");
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
    }

    public static DruidDataSource getInstance(){
        return druidDataSource;
    }




    public static void main(String[] args) throws SQLException {
        System.out.println(DruidUtils.getInstance().getConnection().toString());
    }
}

使用tomcat7插件启动

在这里插入图片描述

测试 postman

在这里插入图片描述
正常执行没有问题
在这里插入图片描述
数据库也正常,

打开异常代码-重启项目

在这里插入图片描述
再次发送同样的请求
在这里插入图片描述
看数据库
在这里插入图片描述
第一个记录扣了钱,但第二记录并没有增加,钱不见了,因为没有事务控制

现在的问题
  1. Servlet中使用了new 关键字创建Service–代码耦合
    在这里插入图片描述
  2. Service中也使用的new 创建dao—代码耦合
    在这里插入图片描述
  3. 没有事务事务
一共2个大问题
代码代码耦合
 *  使用工厂来创建对象,不使用new 
没有事务
  • 在servcie中的select,update方法每次都会创建一个新的连接,这样不是一个Connection,
  • 同时每次执行完都把连接关闭了,再次又要重新获取新连接 肯定不是一个事务的见下方代码
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
* 事务控制JDBC默认是在dao层Connection对象的,控制在Service层中,解决就是把事务控制放在Service中
在这里插入图片描述

解决第一个问题-代码耦合

使用工厂来解决
使用配置文件的方式来声明bean
在这里插入图片描述
beans.xml

<beans>

    <!--id标识 class 类的全限定类名-->
    <bean id="transferService" class="com.liu.spring.service.impl.TransferServcieImpl">
        <property name="AccountDao" ref="accountDao"/>
    </bean>

    <bean id="accountDao" class="com.liu.spring.dao.impl.AccountDaoImpl">
    </bean>
</beans>

只是名称和spring一样,没有任何关系
1.创建工厂来解析XML,
2.把对象实例保存
3. 提供接口获取对象

package com.liu.spring.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description 使用反射创建对象
 * @ClassName BeanFactory
 * @Author 刘楠
 * @date 2020.06.24
 */
public class BeanFactory {
    /**
     * 1.解析xml,将bean保存
     * 2.提供获取对象的接口
     */

    /**
     * 保存对象
     */
    private static    Map<String, Object> beansMap = new ConcurrentHashMap<>();

    private static  String beansXml="beans.xml";
    static {
        //解析xml 保存在map中
        //1.加载xml
        InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream(beansXml);
        try {
            Document document = new SAXReader().read(in);
            //获取根据节点
            Element rootElement = document.getRootElement();
            //获取所有bean的标签
            List<Element> beanList = rootElement.selectNodes("//bean");

            for (Element element : beanList) {
                /**
                 * 获取每个元素的id、class属性
                 */
                String id = element.attributeValue("id");
                String clazz = element.attributeValue("class");
                /**
                 * 通过反射创建对象
                 */
                Class<?> cla = Class.forName(clazz);
                //实例化之后的对象
                Object instance = cla.newInstance();
                /**
                 * 放入map中
                 */
                beansMap.put(id, instance);
            }
            //实例化后,维护对象的依赖关系
            List<Element> propertyList = rootElement.selectNodes("//property");

            //解析property获取父元素
            for (Element element : propertyList) {
                String name = element.attributeValue("name");
                String ref = element.attributeValue("ref");
                //找到当前需要被处理依赖关系的Bean
                Element parent = element.getParent();
                //调用父元素的反射功能
                String parantId = parent.attributeValue("id");
                Object parantObject = beansMap.get(parantId);
                Method[] methods = parantObject.getClass().getMethods();
                for (Method method : methods) {
                    String methodName = method.getName();
                    //这个方法是要要赋值的方法
                    if(methodName.equalsIgnoreCase("set"+name)){
                        method.invoke(parantObject, beansMap.get(ref));
                    }
                }
                //重新放入容器
                beansMap.put(parantId, parantObject);
            }

        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据id获取对象
     * @param id
     * @return
     */
    public static Object getBean(String id){
        Object o = beansMap.get(id);
        return  o;
    }
}


修改servlet 与service

在这里插入图片描述
在这里插入图片描述
TransferServlet

@WebServlet(name = "transferServlet",urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {
    /**
     * http mine,json类型
     */
    public static final String MIME_TYPE_JSON = "application/json";
    /**
     * http mine,json类型指定utf-8编码
     */
    public final static String MIME_TYPE_JSON_UTF8 = MIME_TYPE_JSON + ";charset=UTF-8";
    //1.实例化TransferService
//    private TransferService transferService = new TransferServcieImpl();
    private TransferService transferService =(TransferService) BeanFactory.getBean("transferService");
    ...
    }


service

public class TransferServcieImpl implements TransferService {

//   private AccountDao accountDao = new AccountDaoImpl();

    private AccountDao accountDao ;

    /**
     * 提供get,set方法
     * @return
     */
    public AccountDao getAccountDao() {
        return accountDao;
    }

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

启动并把异常代码注释

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

执行成功,但打开异常代码后,还是不行的,因为没有事务控制在Service中

解决第二个大问题
  • 在servcie中的select,update方法每次都会创建一个新的连接,这样不是一个Connection,
  • 同时每次执行完都把连接关闭了,再次又要重新获取新连接
  • 事务控制JDBC默认是在dao层Connection对象的,控制在Service层中,解决就是把事务控制放在Service中
    ####### 1.每次都创建新连接
    一个请求到Server后就一个线程在处理,可不可把当前线程与Connection绑定在一起这样就解决了呢?

新建ConnectionUtils工具类来实现


/**
 * @Description
 * @ClassName ConnectionUtils
 * @Author 刘楠
 * @date 2020.06.24
 */
public class ConnectionUtils {

    /**
     * 单例
     */
    private ConnectionUtils(){


    }
    private static  ConnectionUtils connectionUtils = new ConnectionUtils();
    /**
     * 使用ThreadLocal与Connection绑定
     */
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();


    public static ConnectionUtils getInstance(){

        return connectionUtils;
    }

    public   Connection getCurrentConnection() throws SQLException {
        //先直接从当前线程取
        Connection connection  =threadLocal.get();
        //判断是否为空
        if(connection==null){
            //空就从工具类中创建一个连接Connection
            connection = DruidUtils.getInstance().getConnection();
            //Connection与当前线程绑定 
            threadLocal.set(connection);
        }
        //返回连接
        return connection;
    }
}

  1. Connection每次使用完都关闭了?我们不关闭就好了吗
改造Dao层
public class AccountDaoImpl implements AccountDao {

    @Override
    public Account queryByCardNo(String cardNo) throws SQLException {
        //从连接池获取连接
//        Connection connection = DruidUtils.getInstance().getConnection();
        /**
         * 获取当前线程的Connection
         */
        Connection connection = ConnectionUtils.getInstance().getCurrentConnection();

        System.out.println("queryByCardNo connection " + connection.toString());
        String sql = "select name ,cardNo ,money from account where cardNo=?";
        //预编译SQL
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //填充参数
        preparedStatement.setString(1, cardNo);
        //执行查询
        ResultSet resultSet = preparedStatement.executeQuery();
        Account account = null;
        while (resultSet.next()) {
            account = new Account();
            account.setMoney(resultSet.getInt("money"));
            account.setCardNo(resultSet.getString("cardNo"));
            account.setName(resultSet.getString("name"));
        }
        preparedStatement.close();
        //关闭后就不是当前线程了
//        connection.close();
        return account;
    }

   
    @Override
    public int updateAccountByCardno(Account fAccount) throws SQLException {
//        Connection connection = DruidUtils.getInstance().getConnection();
        /**
         * 获取当前线程的Connection
         */
        Connection connection = ConnectionUtils.getInstance().getCurrentConnection();
        System.out.println("updateAccountByCardno connection " + connection.toString());
        String sql = "update account set money =? where cardNo=? ";
        //预编译SQL
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //设置参数
        preparedStatement.setInt(1, fAccount.getMoney());
        preparedStatement.setString(2, fAccount.getCardNo());
        //执行更新
        int update = preparedStatement.executeUpdate();
        preparedStatement.close();
        //关闭后就不是当前线程了
//        connection.close();
        return update;
    }
}
测试下Connection是不是同一个

发一个请求
在这里插入图片描述

在这里插入图片描述

改造Servcie层-使用手动事务-异常未开启

package com.liu.spring.service.impl;

import com.liu.spring.dao.AccountDao;
import com.liu.spring.dao.impl.AccountDaoImpl;
import com.liu.spring.entity.Account;
import com.liu.spring.factory.BeanFactory;
import com.liu.spring.service.TransferService;
import com.liu.spring.transaction.TransactionManager;
import com.liu.spring.util.ConnectionUtils;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Description
 * @ClassName TransferServcieImpl
 * @Author 刘楠
 * @date 2020.06.23
 */
public class TransferServcieImpl implements TransferService {

//   private AccountDao accountDao = new AccountDaoImpl();

    private AccountDao accountDao ;




    @Override
    public boolean transfer(String fromAccount, String toAccount, Integer money) throws Exception {
        System.out.println("=====开始转账==== ");



        try {
            /**
             * 开启事务关闭事务的自动提交
             */
            ConnectionUtils.getInstance().getCurrentConnection().setAutoCommit(false);

            Account fAccount = accountDao.queryByCardNo(fromAccount);
            Account tAccount = accountDao.queryByCardNo(toAccount);

            fAccount.setMoney(fAccount.getMoney()-money);
            tAccount.setMoney(tAccount.getMoney()+money);
            accountDao.updateAccountByCardno(fAccount);
            //int i=1/0;
            accountDao.updateAccountByCardno(tAccount);
            /**
             * 正常执行完成 提交事务
             */
            ConnectionUtils.getInstance().getCurrentConnection().commit();
        }catch (Exception e){
            e.printStackTrace();
            /**
             * 有异常回滚事务
             */
            ConnectionUtils.getInstance().getCurrentConnection().rollback();
            //抛出异常 便于上层 捕获
            throw  new RuntimeException(e);
        }

        return true;
    }

    /**
     * 提供get,set方法
     * @return
     */
    public AccountDao getAccountDao() {
        return accountDao;
    }

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


测试下

在这里插入图片描述
在这里插入图片描述

打开异常代码

在这里插入图片描述
测试
在这里插入图片描述

重点看数据库
在这里插入图片描述
并没有出现最开始的现象

优化,将事务的开启,提交,回滚提取到一个公共类中
package com.liu.spring.transaction;

import com.liu.spring.util.ConnectionUtils;

import java.sql.SQLException;

/**
 * @Description 负责手动事务的开启,提交 ,回滚
 * @ClassName TransactionManager 事务管理器
 * @Author 刘楠
 * @date 2020.06.24
 */
public class TransactionManager {


    private static  TransactionManager INSTANCE = new TransactionManager();

    private TransactionManager(){

    }
    public static TransactionManager getInstance(){
        return INSTANCE;
    }

    /**
     * 开启事务
     */
    public void beginTransaction() throws SQLException {
        ConnectionUtils.getInstance().getCurrentConnection().setAutoCommit(false);
    }

    /**
     * 提交事务
     */
    public void commitTransaction() throws SQLException {
        ConnectionUtils.getInstance().getCurrentConnection().commit();
    }

    /**
     * 回滚事务
     */
    public void rollbackTransaction() throws SQLException {
        ConnectionUtils.getInstance().getCurrentConnection().rollback();
    }
}



改造Service

在这里插入图片描述

在这里插入图片描述

package com.liu.spring.service.impl;

import com.liu.spring.dao.AccountDao;
import com.liu.spring.dao.impl.AccountDaoImpl;
import com.liu.spring.entity.Account;
import com.liu.spring.factory.BeanFactory;
import com.liu.spring.service.TransferService;
import com.liu.spring.transaction.TransactionManager;
import com.liu.spring.util.ConnectionUtils;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Description
 * @ClassName TransferServcieImpl
 * @Author 刘楠
 * @date 2020.06.23
 */
public class TransferServcieImpl implements TransferService {

//   private AccountDao accountDao = new AccountDaoImpl();

    private AccountDao accountDao ;




    @Override
    public boolean transfer(String fromAccount, String toAccount, Integer money) throws Exception {
        System.out.println("=====开始转账==== ");



        try {
            /**
             * 开启事务关闭事务的自动提交
             */
//            ConnectionUtils.getInstance().getCurrentConnection().setAutoCommit(false);
            //使用事务管理器-开启使用
            TransactionManager.getInstance().beginTransaction();
            Account fAccount = accountDao.queryByCardNo(fromAccount);
            Account tAccount = accountDao.queryByCardNo(toAccount);

            fAccount.setMoney(fAccount.getMoney()-money);
            tAccount.setMoney(tAccount.getMoney()+money);
            accountDao.updateAccountByCardno(fAccount);
            int i=1/0;
            accountDao.updateAccountByCardno(tAccount);
            /**
             * 正常执行完成 提交事务
             */
//            ConnectionUtils.getInstance().getCurrentConnection().commit();
            //使用事务管理器-提交事务
            TransactionManager.getInstance().commitTransaction();
        }catch (Exception e){
            e.printStackTrace();
            /**
             * 有异常回滚事务
             */
//            ConnectionUtils.getInstance().getCurrentConnection().rollback();
            //使用事务管理器回滚事务
            TransactionManager.getInstance().rollbackTransaction();
            //抛出异常 便于上层 捕获
            throw  new RuntimeException(e);
        }

        return true;
    }

    /**
     * 提供get,set方法
     * @return
     */
    public AccountDao getAccountDao() {
        return accountDao;
    }

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

再次测试异常情况

在这里插入图片描述

在这里插入图片描述

并没有改变,

测试下正常情况

注释异常代码
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

提交成功
这样事务就改选到Service中了,改造完成
代码:https://gitee.com/null_631_9084/myhomework/tree/master/stage01-spring/spring-classroom

还存在一些问题,后期优化
每个方法方法都有一大段try-catch代码不太友好

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值