手写Mybatis框架

news2025/1/18 8:08:25

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

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

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

新建模块演示dom4j解析.xml

目录放错了  无所谓

引入依赖

从原来项目可以拷贝过来

就些简单配置就好

解析核心配置文件和解析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<Element> 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<Element> 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<Node> mappers = document.selectNodes(xpath);
        //遍历
        mappers.forEach(n->{
            Element e=(Element)n;
            String resource = e.attributeValue("resource");
            System.out.println(resource);
        });

    }
}

新建module 

引入依赖

可以回顾下标准写法

逆推下

Resources

SqlSessionFactoryBuilder

SqlSessionFactory

transaction  

SqlSession

SQL Mapper

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

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

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

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

另外

和映射文件

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

将这个对象也封装到SqlSessionFactory中

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

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

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

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

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

那好办,定义为接口呗

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

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

然后又个SqlSession对象

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

基本思路就是这样

整体结构

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<Node> mapperList = document.selectNodes("//mapper");//获取整个配置文件中所有的mapper标签
            //用于封装所有mappers里面的mapper的路径
            List<String> 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<String,MappedStatement> MappedStatements=getMappedStatements(sqlMapperXMLPathList);

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

    private Map<String, MappedStatement> getMappedStatements(List<String> sqlMapperXMLPathList) {
        Map<String,MappedStatement> 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<Element> 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<String,String> map=new HashMap<>();
        //获取节点下所有property
        List<Element> 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<String,MappedStatement> mappedStatementMap;

    public SqlSessionFactory() {
    }

    public SqlSessionFactory(Transaction transaction, Map<String, MappedStatement> mappedStatementMap) {
        this.transaction = transaction;
        this.mappedStatementMap = mappedStatementMap;
    }

    public Transaction getTransaction() {
        return transaction;
    }

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

    public Map<String, MappedStatement> getMappedStatementMap() {
        return mappedStatementMap;
    }

    public void setMappedStatementMap(Map<String, MappedStatement> 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> T unwrap(Class<T> 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> T unwrap(Class<T> 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> T unwrap(Class<T> 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路径要写对

测试基本没问题

下面把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<String,MappedStatement> mappedStatementMap;

    public SqlSessionFactory() {
    }

    public SqlSessionFactory(Transaction transaction, Map<String, MappedStatement> mappedStatementMap) {
        this.transaction = transaction;
        this.mappedStatementMap = mappedStatementMap;
    }

    public Transaction getTransaction() {
        return transaction;
    }

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

    public Map<String, MappedStatement> getMappedStatementMap() {
        return mappedStatementMap;
    }

    public void setMappedStatementMap(Map<String, MappedStatement> 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依赖测试  新建表

新建实体类

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;
    }
}

映射文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/997803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《React vs. Vue vs. Angular:2023年的全面比较》

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

如何快速下载UE源码

前置技能要求掌握Git和Github的基础操作和知识 1.获取源码仓库授权并下载源代码 (1).获取授权 UE是开源的&#xff0c;但是它的代码仓库在Github不开源&#xff0c;我们没法直接搜索到&#xff0c; 登录->个人信息->应用与账户->连接Github 请按照官网指引成功进…

想要精通算法和SQL的成长之路 - 课程表III

想要精通算法和SQL的成长之路 - 课程表III 前言一. 课程表III&#xff08;贪心优先队列&#xff09;1.1 优先选择截止时间更小的课程1.2 如果当前课程无法学习怎么办&#xff1f;1.3 优化 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 课程表III&#xff08;贪心优先队列&…

【ArcGIS pro】-使用arcpy一次保存多个布局

在arcgis Pro中常常会创建多个地图和多个布局&#xff0c;本文介绍如何使用代码&#xff0c;一次保存多个布局文件 在arcgis pro中打开python视图 找到工程位置 在python视图中输入如下代码 保存为pdf import arcpy# 设置当前项目&#xff0c;这通常是一个.aprx文件 projec…

11.Xaml DatePicker控件 时间控件

1.运行效果 2.运行源码 a.Xaml源码 <Grid Name="Grid1"><!--DisplayDate="2020-5-1" 显示的日期--><!--DisplayDateStart="2020

Linux CentOS7 添加中文输入法

在安装CentOS7时&#xff0c;现在默认安装了桌面中文系统。可以切换为英文&#xff0c;中英文可以按要求随时更换。而在CentOS7桌面环境下&#xff0c;显示中文非常方便、正确&#xff0c;并不能录入中文。 在远程登录系统的情况下&#xff0c;不论是系统语言&#xff08;LANG…

Vue2电商前台项目——完成Home首页模块业务

Vue2电商前台项目——完成Home首页模块业务 Vue基础知识点击此处——Vue.js 文章目录 Vue2电商前台项目——完成Home首页模块业务一、项目开发的步骤二、Home首页拆分静态组件1、完成TypeNav三级联动组件&#xff1a;全局组件2、完成其余静态组件&#xff1a;局部组件 三、请求…

黑马JVM总结(四)

&#xff08;1&#xff09;本地方法栈 Java虚拟机调用本地方法时&#xff0c;给本地方法提供的一个内存空间&#xff0c;本地方法它是指哪些不是由java代码编写的方法 java代码有一定限制&#xff0c;它有时候不能直接跟操作系统底层打交道&#xff0c;需要用c和c语言编写的本…

《C和指针》笔记23: 指针的指针

int a 12; int *b &a;现在有了第三个变量c c &b;c的类型是什么&#xff1f;显然它是一个指针&#xff0c;但它所指向的是什么&#xff1f;变量b是一个“指向整型的指针”&#xff0c;所以任何指向b的类型必须是指向“指向整型的指针”的指针&#xff0c;更通俗地说…

D. Paths on the Tree

Problem - 1746D - Codeforces 思路&#xff1a;先分析一下题意&#xff0c;根据第一条性质&#xff0c;每次只能够从1开始&#xff0c;而第二条性质则表明对于每个节点来说&#xff0c;经过这个节点的子节点的路径条数应该尽量均衡&#xff0c;最大值与最小值相差不能超过1&am…

水浒传之“领导力的定义:梁山集团三代领导人的特点”

周末快乐&#xff0c;我是老原。 周末修整&#xff0c;也不要忘记给自己的大脑充个电。 最近空闲时间看《水浒传》&#xff0c;有了一些关于领导力的感悟。 一提到领导力&#xff0c;有人可能会认为&#xff0c;这是企业领导才需要掌握的能力。 其实并不是。 领导力可以体…

liunx系统无sudo或管理员权限安装rar解压安装包

liunx无sudo权限安装rar解压安装包 &#xff08;1&#xff09;正常liunx安装rar&#xff08;2&#xff09;无sudo\root(管理员身份)时如何安装rar &#xff08;1&#xff09;正常liunx安装rar 1、下载安装包 WinRAR archiver, a powerful tool to process RAR and ZIP files (r…

C#类与类库调用注意事项

类 创建一个类文件&#xff0c;myfunction.cs //静态类&#xff1a;直接引用、无需实例化 static public int jiafa(int V) //普通类&#xff1a;引用时需要实例化 public int jiafa(int V)using System; using System.Collections.Generic; using System.Diagnostics; using …

VS Code 配置 JAVA(总)

VS Code 配置 JAVA&#xff08;总&#xff09; 主要参考&#xff1a; 处理单独 java 源文件的vscode配置VScode关于 java 配置的总体说明安装多版本 jdk 后&#xff0c;如何指定使用某个版本&#xff1f;某些与java相关的有用扩展VS code 如何配置不同编程语言及其工作流程 …

运维必备 | 使用 ansible 自动化批量执行工具,提升企业运维工作效率

各位亲爱的读者&#xff0c;现在公众号更改了推送规则&#xff0c;如果您需要第一时间看到我们推送的好内容。 一定要记得给公众号星标&#xff0c;经常点赞、在看、转发、分享和留下您的评论 &#xff01; 关注回复【学习交流群】加入【安全开发运维】答疑交流群 请朋友们【多…

买卖股票的最佳时机含冷冻期

题目链接 买卖股票的最佳时机含冷冻期 题目描述 注意点 卖出股票后&#xff0c;无法在第二天买入股票 (即冷冻期为 1 天)不能同时参与多笔交易&#xff08;必须在再次购买前出售掉之前的股票&#xff09;可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09…

l8-d11 TCP连接管理与UDP协议

一、三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手&#xff1a;在客户和服务器之间交换三个 TCP 报文段&#xff0c;以防止已失效的连接请求报文段突然又传送到了&#xff0c;因而产生 TCP 连接建立错误。 二、四次挥手 TCP 连接释放过程比较复杂。 数据传输结束后…

2、k-means聚类算法sklearn与手动实现

本文将对k-means聚类算法原理和实现过程进行简述 算法原理 k-means算法原理较简单&#xff0c;基本步骤如下&#xff1a; 1、假定我们要对N个样本观测做聚类&#xff0c;要求聚为K类&#xff0c;首先选择K个点作为初始中心点&#xff1b; 2、接下来&#xff0c;按照距离初始中…

蓝桥杯官网填空题(三角形的面积)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 已知三角形三个顶点在直角坐标系下的坐标分别为&#xff1a; txt (2.3, 2.5) (6.4, 3.1) (5.1, 7.2) txt 求该三角形的面积。 注意&#xff0c;要提交的是一个小…

解决ROS2 humble版本源码编译中resdep init及rosdep update失败的问题

网上有在/etc/hosts中添加ip地址的方法&#xff0c;使用了不成功&#xff0c;具体做法如下&#xff0c;仅供参考&#xff1a; a.打开查询ip的网址&#xff1a; https://site.ip138.com b.输入&#xff1a;raw.githubusercontent.com c.执行sudo vi /etc/hosts 将获取到的ip添…