手写Mybatis

Mybatis核心配置文件就是为了配置Configration

因此要首先会解析Mybatis核心配置文件

首先使用dom4J解析Mybatis核心配置文件

新建模块演示dom4j解析.xml

手写Mybatis_第1张图片手写Mybatis_第2张图片

目录放错了  无所谓手写Mybatis_第3张图片

引入依赖

手写Mybatis_第4张图片

从原来项目可以拷贝过来

手写Mybatis_第5张图片

就些简单配置就好

手写Mybatis_第6张图片

解析核心配置文件和解析xxxMapper.xml映射文件代码

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * @author hrui
 * @date 2023/9/10 18:24
 */
public class ParseXMLByDom4JTest {


    //解析Mapper映射文件
    @Test
    public void testParseSqlMapperXML() throws DocumentException {
        //创建SAXReader对象
        SAXReader reader=new SAXReader();
        //获取输入流(将resources目录下的mybatis-config1.xml转输入流)
        InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mapper/CarMapperABC.xml");
        //读XML文件
        Document document=reader.read(inputStream);
        String xpath="/mapper";
        Element mapper =(Element) document.selectSingleNode(xpath);
        String namespace = mapper.attributeValue("namespace");
        System.out.println(namespace);//aaa
        //获取mapper节点下所有子节点
        List elements = mapper.elements();
        elements.forEach(e->{
            //获取sqlId
            String id = e.attributeValue("id");
            //获取resultType  没有返回null
            System.out.println(id);
            //获取标签中的sql语句,取出前后空白
            String sql = e.getTextTrim();
            System.out.println(sql);//insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
            //现在是:insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
            //内部肯定使用JDBC:insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
            //转换
            String newSql = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");//使用正则替换
            System.out.println(newSql);//insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
        });
    }



    //解析核心配置文件
    @Test
    public void testParseMybatisConfigXML() throws DocumentException {
        //创建SAXReader对象
        SAXReader reader=new SAXReader();
        //获取输入流(将resources目录下的mybatis-config1.xml转输入流)
        InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config1.xml");
        //读XML文件
        Document document=reader.read(inputStream);
        //System.out.println(document);
        //获取根标签
        Element root = document.getRootElement();
        //System.out.println(root.getName());//configuration
        //获取跟标签后肯定是去获取环境 environments 获取里面的default数据库id
        //获取默认的环境id
        //xpath是做标签路径匹配的.能够让我们快速定位XML文件中的元素
        //以下的xpath:从跟下开始找configuration,然后找configuration标签下的子标签environments
        String xpath="/configuration/environments";
        Element element = (Element)document.selectSingleNode(xpath);
        //System.out.println(element);
        //获取属性的值 默认环境id
        String aDefaultEnvivironmentId = element.attributeValue("default");
        //System.out.println("默认环境id是:"+aDefaultEnvivironmentId);//development

        //去找environment的 id属性,然后和默认环境id比较,确定默认使用哪个数据库
        //下面是xpath的写法 意思找
        xpath="/configuration/environments/environment[@id='"+aDefaultEnvivironmentId+"']";
        Element enviroment =(Element) document.selectSingleNode(xpath);
        //System.out.println(enviroment.getName());environment
        //获取environment节点下的transactionManager
        Element transactionManager = enviroment.element("transactionManager");
        String transactionType = transactionManager.attributeValue("type");
        //System.out.println("事务管理器的类型:"+transactionType);//获取事务管理器类型----->JDBC
        //接着获取datasource节点
        Element datasource = enviroment.element("dataSource");
        String dataSourcetype = datasource.attributeValue("type");
        System.out.println("数据源的类型:"+dataSourcetype);//POOLED
        //获取dataSource下的所有子节点
        List propertyElements = datasource.elements();
        //遍历
        propertyElements.forEach(e->{
            String name = e.attributeValue("name");
            String value = e.attributeValue("value");
            System.out.println("name="+name+",value="+value);
        });

        //获取所有的mapper标签
        //如果你不想从跟下开始获取,而是想从任意位置开始,获取某个标签,xpath可以这样写
        xpath="//mapper";//  两个//开始
        List mappers = document.selectNodes(xpath);
        //遍历
        mappers.forEach(n->{
            Element e=(Element)n;
            String resource = e.attributeValue("resource");
            System.out.println(resource);
        });

    }
}

新建module 

手写Mybatis_第7张图片

引入依赖

手写Mybatis_第8张图片

可以回顾下标准写法

手写Mybatis_第9张图片

逆推下

Resources

SqlSessionFactoryBuilder

SqlSessionFactory

transaction  

SqlSession

SQL Mapper

思路:1.Resources用来加载核心配置文件,返回一个InputStream流,

2.SqlSessionFactoryBuilder里有个build方法,该方法用来返回一个SqlSessionFactory对象

这里要考虑,SqlSessionFactory里有些什么,用来做什么.

手写Mybatis_第10张图片

那么这样就明了了,build方法用来解析核心配置文件,用以给SqlSessionFactory里的属性赋值,而属性有哪些,就是上面这些呗(事务管理器,JDBC连接需要的driver,url,username,password)

另外

和映射文件

手写Mybatis_第11张图片

是否考虑用一个容器Map存放,key为sql的id   value是其他

手写Mybatis_第12张图片

将这个对象也封装到SqlSessionFactory中

这个对象中该有哪些属性:暂时放sql语句和resultType  当然实际放的不只这两个  获取不到就是null

SqlSessionFactory中还需要一个事务管理器,这个事务管理器可以是JDBC也可以是MANAGED,那么可以定义为接口,另外定义两个具体的实现  这里使用JDBC事务管理器

而我们定义了事务管理器之后,事务管理器需要搞定的就三个方法,commit,rollback,close

但是这三个方法需要连接对象,而要获取连接对象可以定义个数据源

在核心配置文件中,数据源有三个选项,分别是POOLED   UNPOOLED  JNDI

手写Mybatis_第13张图片

那好办,定义为接口呗

这里有个JDK规范,不管你是POOLED   UNPOOLED  JNDI所有的数据源都需要实现JDK里的DataSource接口  那么接口也不用定义了 直接写三个实现类  这里使用UNPOOLED 不使用连接池

那么在实现类里需要driver url username password属性

然后又个SqlSession对象

里面又insert方法   xxx 方法  需要用到什么,再解决

基本思路就是这样

整体结构

手写Mybatis_第14张图片

1.Resources

package com.gmybatis.utils;

import java.io.InputStream;

/**
 * 工具类
 * 用于"类路径"中资源的加载
 * @author hrui
 * @date 2023/9/10 20:25
 */
public class Resources {
    //工具类建议构造方法私有化,因为工具类一般方法都是静态的,是种编程习惯

    public Resources() {
    }

    /**
     * 用于"类路径"种加载资源
     * @param resource
     * @return
     */
    public static InputStream getResourceAsStream(String resource){
        return ClassLoader.getSystemClassLoader().getResourceAsStream(resource);
    }
}

2.SqlSessionFactoryBuilder   构建器对象

package com.gmybatis.core;

import com.gmybatis.utils.Resources;
import jdk.nashorn.internal.ir.ReturnNode;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;


import javax.sql.DataSource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * SqlSessionFactory的构建器对象
 * 通过SqlSessionFactoryBuilder的build方法来解析核心配置文件,
 * 然后创建SqlSessionFactory对象
 * @author hrui
 * @date 2023/9/10 20:31
 */
public class SqlSessionFactoryBuilder {

    public SqlSessionFactoryBuilder() {
    }


    /**
     * 解析核心配置文件,来构建SqlSessionFactory
     * @param in
     * @return
     */
    public SqlSessionFactory build(InputStream in){
        SqlSessionFactory sqlSessionFactory=null;
        try {
            //解析核心配置文件
            //创建SAXReader对象
            SAXReader reader=new SAXReader();

            //读XML文件
            Document document=reader.read(in);
            //获取environments
            Element environments =(Element) document.selectSingleNode("/configuration/environments");
            //获取default属性值
            String defaultId = environments.attributeValue("default");

            //拿匹配的环境节点
            Element environment = (Element)document.selectSingleNode("/configuration/environments/environment[@id='"+defaultId+"']");
            //获取transactionManager
            Element transactionManagerEle = environment.element("transactionManager");
            //获取dataSource
            Element dataSourceEle = environment.element("dataSource");
            //获取mapper
            List mapperList = document.selectNodes("//mapper");//获取整个配置文件中所有的mapper标签
            //用于封装所有mappers里面的mapper的路径
            List sqlMapperXMLPathList=new ArrayList<>();
            mapperList.forEach(n->{
                Element e=(Element) n;
                String resource = e.attributeValue("resource");
                sqlMapperXMLPathList.add(resource);
            });


            //获取数据源对象
            DataSource dataSource=getDataSource(dataSourceEle);

            //定义事务管理器
            Transaction transaction=getTransaction(transactionManagerEle,dataSource);


            //key是namespase+sql的id
            Map MappedStatements=getMappedStatements(sqlMapperXMLPathList);

            //解析完成之后,构建出SqlSessionFactory对象
            sqlSessionFactory=new SqlSessionFactory(transaction,MappedStatements);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sqlSessionFactory;
    }

    private Map getMappedStatements(List sqlMapperXMLPathList) {
        Map map=new HashMap<>();
        sqlMapperXMLPathList.forEach(path->{
            try {
                //创建SAXReader对象
                SAXReader reader=new SAXReader();
                //读XXXMapper.XML映射文件
                Document document=reader.read(Resources.getResourceAsStream(path));
                //解析映射文件
                Element mapper = (Element)document.selectSingleNode("mapper");//带不带/都可以
                String namespace = mapper.attributeValue("namespace");
                List elements = mapper.elements();
                elements.forEach(e->{
                    String id = e.attributeValue("id");
                    //namespase+id
                    String sqlId=namespace+"."+id;
                    String resultType = e.attributeValue("resultType");
                    String sqlContent = e.getTextTrim();
                    MappedStatement mappedStatement=new MappedStatement(sqlContent,resultType);

                    map.put(sqlId,mappedStatement);
                });
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        });
        return map;
    }

    private DataSource getDataSource(Element dataSourceEle) {
        Map map=new HashMap<>();
        //获取节点下所有property
        List propertys = dataSourceEle.elements("property");
        propertys.forEach(e->{
            String name = e.attributeValue("name");
            String value = e.attributeValue("value");
            map.put(name,value);
        });

        DataSource dataSource=null;
        //type 可能是  POOLED UNPOOLED JNDI
        String type = dataSourceEle.attributeValue("type");
//        if(type.equalsIgnoreCase("POOLED")){  //这里简易定义常量类
//
//        }
        if(type.equalsIgnoreCase(Const.POOLED_DATASOURCE)){
            dataSource=new POOLEDDataSource();
        }
        if(type.equalsIgnoreCase(Const.UN_POOLED_DATASOURCE)){//只对这个做了实现
            dataSource=new UNPOOLEDDataSource(map.get("driver"),map.get("url"),map.get("username"),map.get("password"));
        }
        if(type.equalsIgnoreCase(Const.JNDI_DATASOURCE)){
            dataSource=new JNDIDataSource();
        }
        return dataSource;
    }

    private Transaction getTransaction(Element transactionManager, DataSource dataSource) {

        Transaction transaction=null;
        String type = transactionManager.attributeValue("type");
        if(type.equalsIgnoreCase(Const.JDBC_TRANSACTION)){
            transaction=new JDBCTransaction(dataSource,false );//只对JDBCTransaction做了实现
        }
        if(type.equalsIgnoreCase(Const.MANAGED_TRANSACTION)){
            transaction=new MANAGEDTransaction();
        }
        return transaction;
    }


}

3.SqlSessionFactory

package com.gmybatis.core;

import java.util.Map;

/**
 *SqlSessionFactory对象,一个数据库对应一个SqlSessionFactory对象
 * 通过SqlSessionFactory对象可以获得SqlSession对象(开启会话)
 * 一个SqlSessionFactory对象可以开启多个SqlSession会话
 * @author hrui
 * @date 2023/9/10 20:34
 */
public class SqlSessionFactory {
    //事务管理器 可以是JDBC:原生JDBC事务 也可以是MANAGED:交容器管理,比如Spring   可以灵活切换建议定义为接口
    private Transaction transaction;

    //数据源属性 因为已经在事务管理器里定义了数据源,因此这里不需要定义  可以通过事务管理器来获取


    private Map mappedStatementMap;

    public SqlSessionFactory() {
    }

    public SqlSessionFactory(Transaction transaction, Map mappedStatementMap) {
        this.transaction = transaction;
        this.mappedStatementMap = mappedStatementMap;
    }

    public Transaction getTransaction() {
        return transaction;
    }

    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }

    public Map getMappedStatementMap() {
        return mappedStatementMap;
    }

    public void setMappedStatementMap(Map mappedStatementMap) {
        this.mappedStatementMap = mappedStatementMap;
    }

    //    public SqlSession openSession(boolean flag){
//        return null;
//    }
}

Transaction接口及实现类,这里只实现了JDBCTransaction

package com.gmybatis.core;

import java.sql.Connection;

/**
 * 事务管理器接口,所有的事务管理器都应该实现该接口
 * JDBC事务管理器,MANAGED事务管理器都应该实现这个接口
 * 提供控制事务的方法
 * @author hrui
 * @date 2023/9/10 21:14
 */
public interface Transaction {

    //提交事务
    void commit();

    //回滚事务
    void rollback();

    //关闭事务
    void close();

    /**
     * 是否需要其他方法后续再看
     * 真正开启数据库连接
     */
    void openConnection();

    Connection getConnection();
}

JDBCTransaction

package com.gmybatis.core;

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

/**
 * JDBC事务管理器
 * @author hrui
 * @date 2023/9/10 21:19
 */
public class JDBCTransaction implements Transaction{

    //数据源属性
    private  DataSource dataSource;

    /**
     * 自动提交标志
     * true为自动提交
     * false为不自动提交
     */
    private Boolean aotoCommit;

    private Connection connection;

    /**
     * 用于外界获取Connection
     * 外界用的Connection对象 必须和事务管理器的是同一个
     * 这样才可以在事务管理器里  commit  rollback  closed
     * @return
     */
    @Override
    public Connection getConnection() {
        return connection;
    }

    //用于给属性connection赋值 只要事务管理器不换 连接就是同一个连接、
    @Override
    public void openConnection(){
        if(connection==null){
            try {
                connection=dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public JDBCTransaction(DataSource dataSource, Boolean aotoCommit) {
        this.dataSource = dataSource;
        this.aotoCommit = aotoCommit;
    }

    @Override
    public void commit() {
        //控制事务的时候需要调用JDBC里的连接对象 需要数据源
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void rollback() {
        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() {
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

MANAGEDTransaction

package com.gmybatis.core;

import java.sql.Connection;

/**
 * MANAGED事务管理器
 * @author hrui
 * @date 2023/9/10 21:19
 */
public class MANAGEDTransaction implements Transaction{
    @Override
    public void commit() {

    }

    @Override
    public void rollback() {

    }

    @Override
    public void close() {

    }

    @Override
    public void openConnection() {

    }

    @Override
    public Connection getConnection() {
        return null;
    }
}

实现DataSource的3个实现   只实现了UNPOOLEDDataSource

package com.gmybatis.core;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * 数据源的实现类--->UNPOOLED
 * 不使用数据库连接池
 * @author hrui
 * @date 2023/9/10 21:33
 */
public class UNPOOLEDDataSource implements DataSource {

    private String driver;

    private String url;

    private String username;

    private String password;


    public UNPOOLEDDataSource(String driver, String url, String username, String password) {
        try {
            //直接注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        this.driver = driver;
        this.url = url;
        this.username = username;
        this.password = password;
    }



    @Override
    public Connection getConnection() throws SQLException {
        //需要driver url username password 定义为属性
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public  T unwrap(Class iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
package com.gmybatis.core;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * 数据源的实现类--->POOLED
 * 使用数据库连接池  这里不写连接池
 * @author hrui
 * @date 2023/9/10 21:32
 */
public class POOLEDDataSource implements DataSource {
    @Override
    public Connection getConnection() throws SQLException {
        //从数据库连接池获取Connection对象 这里不写连接池
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public  T unwrap(Class iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}

JNDIDataSource

package com.gmybatis.core;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * 数据源的实现类--->JNDI
 * 使用第三方的数据库连接池获取Connection对象
 * @author hrui
 * @date 2023/9/10 21:33
 */
public class JNDIDataSource implements DataSource {
    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {

        return null;
    }

    @Override
    public  T unwrap(Class iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}

定义了一个常量类

package com.gmybatis.core;

/**
 * 整个框架的常量类
 * @author hrui
 * @date 2023/9/10 22:26
 */
public class Const {

    public static final String UN_POOLED_DATASOURCE="UNPOOLED";

    public static final String POOLED_DATASOURCE="POOLED";

    public static final String JNDI_DATASOURCE="JNDI";

    public static final String JDBC_TRANSACTION="JDBC";

    public static final String MANAGED_TRANSACTION="MANAGED";
}

注意测试时候事务管理要选用JDBC   数据源类型要选用UNPOOLED

mapper路径要写对

手写Mybatis_第15张图片

手写Mybatis_第16张图片

测试基本没问题

手写Mybatis_第17张图片

下面把SqlSession加进去

package com.gmybatis.core;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Locale;

/**
 * 专门负责执行SQL语句的会话对象
 * @author hrui
 * @date 2023/9/10 23:40
 */
public class SqlSession {

    private SqlSessionFactory sqlSessionFactory;

    public SqlSession(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }


    //测试
    public static void main(String[] args) {
        String sql="insert into t_car values(#{id},#{asd},#{name})";
        int fromIndex=0;
        int index=1;
        while(true) {
            int jingIndex = sql.indexOf("#",fromIndex);

            if(jingIndex<0){
                break;
            }
            System.out.println(index);
            index++;
            int youkuohaoIndex = sql.indexOf("}",fromIndex);
            String propertyName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();
            System.out.println(propertyName);
            fromIndex = youkuohaoIndex + 1;
        }

    }


    public int insert(String sqlId,Object obj){
        //JDBC代码
        Connection connection=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        int count = 0;
        try {
            connection=sqlSessionFactory.getTransaction().getConnection();
            String sql=sqlSessionFactory.getMappedStatementMap().get(sqlId).getSql();
            String sql1 = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");//使用正则替换
            ps = connection.prepareStatement(sql1);
            //有几个?号 不知道将pojo对象中的哪个属性给哪个 暂时全当String

            int fromIndex=0;
            int index=1;
            while(true) {
                int jingIndex = sql.indexOf("#",fromIndex);

                if(jingIndex<0){
                    break;
                }
                //System.out.println(index);

                int youkuohaoIndex = sql.indexOf("}",fromIndex);
                String propertyName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();
                //System.out.println(propertyName);
                fromIndex = youkuohaoIndex + 1;
                String getMethodName="get"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1);
                Method getMethod=obj.getClass().getDeclaredMethod(getMethodName);
                Object invoke = getMethod.invoke(obj);
                ps.setString(index,invoke.toString());
                index++;
            }

            count = ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //这里不要加 不然直接关闭了
//        finally {
//            if(rs!=null){
//                try {
//                    rs.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//            if(ps!=null){
//                try {
//                    ps.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//            if(connection!=null){
//                try {
//                    connection.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
        return count;
    }


    public Object selectOne(){
        return null;
    }

    public void commit(){
        sqlSessionFactory.getTransaction().commit();
    }

    public void rollback(){
        sqlSessionFactory.getTransaction().rollback();
    }

    public void close(){
        sqlSessionFactory.getTransaction().close();
    }
}

修改sqlSessionFactory

package com.gmybatis.core;

import java.util.Map;

/**
 *SqlSessionFactory对象,一个数据库对应一个SqlSessionFactory对象
 * 通过SqlSessionFactory对象可以获得SqlSession对象(开启会话)
 * 一个SqlSessionFactory对象可以开启多个SqlSession会话
 * @author hrui
 * @date 2023/9/10 20:34
 */
public class SqlSessionFactory {
    //事务管理器 可以是JDBC:原生JDBC事务 也可以是MANAGED:交容器管理,比如Spring   可以灵活切换建议定义为接口
    private Transaction transaction;

    //数据源属性 因为已经在事务管理器里定义了数据源,因此这里不需要定义  可以通过事务管理器来获取


    private Map mappedStatementMap;

    public SqlSessionFactory() {
    }

    public SqlSessionFactory(Transaction transaction, Map mappedStatementMap) {
        this.transaction = transaction;
        this.mappedStatementMap = mappedStatementMap;
    }

    public Transaction getTransaction() {
        return transaction;
    }

    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }

    public Map getMappedStatementMap() {
        return mappedStatementMap;
    }

    public void setMappedStatementMap(Map mappedStatementMap) {
        this.mappedStatementMap = mappedStatementMap;
    }

    /**
     * 获取sql会话对象
     * @param flag
     * @return
     */
    public SqlSession openSession(){
        //开启会话的前提是开启连接
        transaction.openConnection();
        //创建SqlSession对象
        SqlSession sqlSession=new SqlSession(this);
        return sqlSession;
    }
}

JDBCTransaction的openConnection的代码加上开启事务

package com.gmybatis.core;

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

/**
 * JDBC事务管理器
 * @author hrui
 * @date 2023/9/10 21:19
 */
public class JDBCTransaction implements Transaction{

    //数据源属性
    private  DataSource dataSource;

    /**
     * 自动提交标志
     * true为自动提交
     * false为不自动提交
     */
    private boolean aotoCommit;

    private Connection connection;

    /**
     * 用于外界获取Connection
     * 外界用的Connection对象 必须和事务管理器的是同一个
     * 这样才可以在事务管理器里  commit  rollback  closed
     * @return
     */
    @Override
    public Connection getConnection() {
        return connection;
    }

    //用于给属性connection赋值 只要事务管理器不换 连接就是同一个连接、
    @Override
    public void openConnection(){
        if(connection==null){
            try {
                connection=dataSource.getConnection();
                //开启事务
                connection.setAutoCommit(aotoCommit);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public JDBCTransaction(DataSource dataSource, Boolean aotoCommit) {
        this.dataSource = dataSource;
        this.aotoCommit = aotoCommit;
    }

    @Override
    public void commit() {
        //控制事务的时候需要调用JDBC里的连接对象 需要数据源
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void rollback() {
        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() {
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

引入mysql依赖测试  新建表

手写Mybatis_第18张图片

新建实体类

package com.gmybatis.core;

/**
 * @author hrui
 * @date 2023/9/11 0:31
 */
public class Car {
    private String id;
    private String name;
    private String age;

    public Car() {
    }

    public Car(String id, String name, String age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

映射文件

手写Mybatis_第19张图片

手写Mybatis_第20张图片手写Mybatis_第21张图片

你可能感兴趣的:(mybatis,学习,笔记)