• 手写简单的mybatis框架


    一、核心

    mybatis的核心是通过解析核心配置xml(获取数据源、存放mapper.xml文件的路径 ),根据mapper.xml路径解析出sql的类型(crud哪一种)、返回值类型(结果集是什么类型的)、参数类型(带不带参数就行sql操作)这些东西存放在一个Configuration 类里面(用一个map保存key为:接口全限定名.方法名。)。最后利用动态代理(jdk)去生成一个代理对象。代理对象根据Configuration类里面的存放的sql信息,利用jdbc操作数据库。

    二、代码

    (一)pom

    <dependencies>
       <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.12version>
            <scope>providedscope>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.19version>
        dependency>
        
        <dependency>
            <groupId>c3p0groupId>
            <artifactId>c3p0artifactId>
            <version>0.9.1.2version>
        dependency>
    
        
        <dependency>
            <groupId>dom4jgroupId>
            <artifactId>dom4jartifactId>
            <version>1.6.1version>
        dependency>
        <dependency>
            <groupId>jaxengroupId>
            <artifactId>jaxenartifactId>
            <version>1.1.6version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    (二)解析xml

    • 使用dom4j工具解析SqlMapConfig.xml和UserMapper.xml

    SqlMapConfig.xml

    <configuration>
    
        
        <dataSource>
            <property name="driverClass" value="com.mysql.jdbc.Driver">property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/book?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true">property>
            <property name="username" value="root">property>
            <property name="password" value="123">property>
        dataSource>
    
        
        <mapper resource="UserMapper.xml">mapper>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    UserMapper.xml

    <mapper namespace="com.lihua.mapper.UserMapper">
    
        
        <select id="queryUserAll" resultType="com.lihua.pojo.User">
            select * from user
        select>
    
        
    
    
    
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. 需要找到文件位置(路径)。通过类加载器获取resources下的配置文件的输入流
    package com.lihua.custommybatis;
    
    import java.io.InputStream;
    
    /**
     * @author lihua
     * @date 2022/12/6 17:28
     *
     * 利用 ClassLoader加载配置
     */
    public class Resources {
    
        /**
         * 根据配置文件的路径,将配置文件加载成字节输入流,存储在内存中。
         * @param path 文件路径
         * @return     字节流
         */
        public static InputStream getResourceAsStream(String path) {
            InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
            return resourceAsStream;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. 解析xml
    • 解析核心配置文件
    package com.lihua.custommybatis;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.beans.PropertyVetoException;
    import java.io.InputStream;
    import java.util.List;
    import java.util.Properties;
    
    /**
     * @author lihua
     * @date 2022/12/6 16:09
     * 用于读取mybatis核心xml文件,对mybatis核心配置文件进行读取。
     */
    public class XMLConfigBuilder {
    
        private Configuration configuration;
    
        public XMLConfigBuilder() {
            this.configuration = new Configuration();
        }
    
        /**
         * 该方法就是使用dom4j对配置文件进行解析,封装成Configuration对象
         * @param in 字节输入流
         * @return   Configuration
         */
        public Configuration parseConfig(InputStream in) throws DocumentException, PropertyVetoException {
            Document document = new SAXReader().read(in);
            // 
            Element rootElement = document.getRootElement();
            List<Element> list = rootElement.selectNodes("//property");
            Properties properties = new Properties();
            for (Element element : list) {
                String name = element.attributeValue("name");
                String value = element.attributeValue("value");
                properties.setProperty(name, value);
            }
    
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
            comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
            comboPooledDataSource.setUser(properties.getProperty("username"));
            comboPooledDataSource.setPassword(properties.getProperty("password"));
    
            configuration.setDataSource(comboPooledDataSource);
    
            // mapper.xml解析:拿到路径--字节输入流--dom4j进行解析
            List<Element> mapperList = rootElement.selectNodes("//mapper");
            for (Element element : mapperList) {
                String mapperPath = element.attributeValue("resource");
                InputStream resourceAsStream = Resources.getResourceAsStream(mapperPath);
                XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
                xmlMapperBuilder.parse(resourceAsStream);
            }
    
            return configuration;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 解析mapper.xml配置文件
    package com.lihua.custommybatis;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * @author lihua
     * @date 2022/12/6 16:11
     */
    public class XMLMapperBuilder {
    
        private Configuration configuration;
    
        public XMLMapperBuilder(Configuration configuration) {
            this.configuration = configuration;
        }
    
        public void parse(InputStream in) throws DocumentException {
            Document document = new SAXReader().read(in);
            Element rootElement = document.getRootElement();
            String namespace = rootElement.attributeValue("namespace");
    
            List<Element> list = rootElement.selectNodes("//select");
            for (Element element : list) {
                String id = element.attributeValue("id");
                String resultType = element.attributeValue("resultType");
                String parameterType = element.attributeValue("parameterType");
                String sqlText = element.getTextTrim();
                MappedStatement mappedStatement = new MappedStatement();
                mappedStatement.setId(id);
                mappedStatement.setResultType(resultType);
                mappedStatement.setParameterType(parameterType);
                mappedStatement.setSql(sqlText);
                mappedStatement.setSqlType(element.getName());
    
                String key = namespace + "." + id;
                configuration.getMappedStatement().put(key, mappedStatement);
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    (三)Configuration

    解析xml后,将结果放到一个Configuration 类里存放。在前面的解析步骤中,需要解析两个配置文件。

    • 核心配置文件:存放了我们连接数据库的数据源信息。我们用一个javax.sql.DataSource;下的DataSource类存放。

    • mapper.xml:存放了我们编写的sql语句。我们创建一个MappedStatement类存放sql语句的信息,比如:sql类型(insert\select),参数类型,结果集类型,具体的sql。因为一个mapper中有很多sql语句,因此我们需要用一个map存放,key为:接口全限定名.方法名。value为:MappedStatement

    MappedStatement

    package com.lihua.custommybatis;
    
    import lombok.Data;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:28
     * 用于存放解析后的sql语句
     *
     */
    @Data
    public class MappedStatement {
        // id标识
        private String id;
    
        //sql类型,crud
        private String sqlType;
    
        // 返回值类型
        private String resultType;
    
        // 参数值类型
        private String parameterType;
    
        // sql语句
        private String sql;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    Configuration

    package com.lihua.custommybatis;
    
    
    import lombok.Data;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:24
     * 自定义config,用于存放读取到的xml文件
     */
    @Data
    public class Configuration {
        private DataSource dataSource;
    
        private Map<String ,MappedStatement> mappedStatement = new HashMap<>();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    (四)SqlSessionFactoryBuilder

    使用建造者模式创建一个SqlSessionFactory 对象。一般以Builder 结尾的都是建造者模式。建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。(与工厂模式一样,是创建型模式,用于屏蔽复杂对象的构建过程)。

    package com.lihua.custommybatis;
    
    import org.dom4j.DocumentException;
    
    import java.beans.PropertyVetoException;
    import java.io.InputStream;
    
    /**
     * @author lihua
     * @date 2022/12/6 16:07
     * 建造者模式创建SqlSessionFactory 工厂对象
     */
    public class SqlSessionFactoryBuilder {
        public SqlSessionFactory build(InputStream in) {
            // 1.使用dom4j解析配置文件,将解析出来的内容封装到Configuration
            XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
            Configuration configuration = null;
            try {
                configuration = xmlConfigBuilder.parseConfig(in);
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            }
            // 2.创建SqlSessionFactory对象:工厂类:生产SqlSession:会话对象
            DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
            return defaultSqlSessionFactory;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    (五)通过SqlSessionFactory获取SqlSession

    SqlSessionFactory 是简单工厂模式(工厂模式),也是用于构建一个对象。这里用来构建SqlSession。

    SqlSessionFactory

    public interface SqlSessionFactory {
        /**
         * 通过工厂模式获取session
         *
         * @return
         */
        DefaultSqlSession openSession();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    默认的实现类

    package com.lihua.custommybatis;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:48
     * 默认会话工厂实现
     */
    public class DefaultSqlSessionFactory implements SqlSessionFactory {
    
        private Configuration configuration;
    
        /**
         * 通过构造器注入
         * @param configuration
         */
        public DefaultSqlSessionFactory(Configuration configuration) {
            this.configuration = configuration;
        }
    
        @Override
        public DefaultSqlSession openSession() {
    
            return new DefaultSqlSession(configuration);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    (六)核心类SqlSession

    在SqlSession中就使用了动态代理(jdk动态代理)模式创建一个代理类去操作数据库。

    • 接口
    package com.lihua.custommybatis;
    
    import java.util.List;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:56
     */
    public interface SqlSession {
    
        /**
         * 查询所有
         * @param statementId sql唯一id
         * @param params      sql有可能十四模糊查询,传可变参数
         * @param          泛型
         * @return            List集合
         */
        <E> List<E> selectList(String statementId, Object... params) throws Exception;
    
        /**
         * 根据条件查询单个
         * @param statementId sql唯一id
         * @param params      sql有可能十四模糊查询,传可变参数
         * @param          泛型
         * @return            某一对象
         */
        <T> T selectOne(String statementId, Object... params) throws Exception;
    
        /**
         * 为Dao层接口生成代理实现类(获取代理对象,执行crud)
         * @param mapperClass 字节码
         * @param          泛型
         * @return         某一对象
         */
        <T> T getMapper(Class<?> mapperClass) throws Exception;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 这里没有单独创建一个代理类,直接new了一个匿名类
    package com.lihua.custommybatis;
    
    import java.lang.reflect.*;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:49
     * 会话
     */
    public class DefaultSqlSession implements SqlSession {
    
        private Configuration configuration;
    
        private Connection connection;
    
        public DefaultSqlSession(Configuration configuration) {
            this.configuration = configuration;
            try {
                //操作数据库的连接
                this.connection= configuration.getDataSource().getConnection();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    
    
        @Override
        public <E> List<E> selectList(String statementId, Object... params) throws Exception {
    
            return null;
        }
    
        @Override
        public <T> T selectOne(String statementId, Object... params) throws Exception {
            return null;
        }
    
    
        @Override
        public <T> T getMapper(Class<?> mapperClass) throws Exception {
            // 使用JDK动态代理来为Dao层接口生成代理对象,并返回。
            Object proxyInstance = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                    /**
                     * 底层都还是去执行JDBC代码
                     * 根据不同情况来调用findAll或者findByCondition方法
                     * 准备参数:
                     * 1.statementId: sql语句的唯一标识 nnamespace.id = 接口全限定名.方法名
                     */
                    // 方法名
                    String methodNme = method.getName();
                    String className = method.getDeclaringClass().getName();
    
                    String   statementId  = className + "." + methodNme;
    
                    System.out.println(methodNme);
                    MappedStatement mappedStatement = configuration.getMappedStatement().get(statementId);//根据方法名得到它的环境信息
                    PreparedStatement statement = connection.prepareStatement(mappedStatement.getSql());//根据sql得到预编译语句
                    if ("insert".equals(mappedStatement.getSqlType())){
                        //假设传入一个参数
                        String paramType = mappedStatement.getParameterType();//得到参数类型
                        Class<?> clazz = args[0].getClass();
                        Field[] fields = clazz.getDeclaredFields();
                        for(int i=0;i<fields.length;i++){
                            fields[i].setAccessible(true);
                            statement.setObject(i+1,fields[i].get(args[0]));
                        }
                        return statement.executeUpdate();
                    }
                    else if("delete".equals(mappedStatement.getSqlType())){
    
                        for (int i=0;i<args.length;i++){
                            statement.setObject(i+1,args[i]);
                        }
                        return statement.executeUpdate();
                    }
                    else if("select".equals(mappedStatement.getSqlType())){
                        if (args!=null){
                            for (int i=0;i<args.length;i++){//替换占位符的参数
                                statement.setObject(i+1,args[i]);
                            }
                        }
                        ResultSet resultSet = statement.executeQuery();//执行查询语句得到返回集合
                        List list=new ArrayList();
                        while (resultSet.next()){//遍历返回集合
                            Class<?> clazz = Class.forName(mappedStatement.getResultType());//通过反射机制,根据返回值类型创建实例
                            Object object = clazz.newInstance();
                            Field[] fields = clazz.getDeclaredFields();//通过反射机制,该类型的所有属性
                            for (int i=0;i<fields.length;i++){
                                fields[i].setAccessible(true);//设置属性是可以访问的,避免private
                                fields[i].set(object,resultSet.getObject(fields[i].getName()));//给每个属性赋值
                            }
                            list.add(object);//把对象放在list集合中
                        }
                        return list;
                    }
                    return null;
                }
            });
            return (T) proxyInstance;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111

    MyBatis 框架中的代理类是这样的

    /**
     *    Copyright 2009-2017 the original author or authors.
     *
     *    Licensed under the Apache License, Version 2.0 (the "License");
     *    you may not use this file except in compliance with the License.
     *    You may obtain a copy of the License at
     *
     *       http://www.apache.org/licenses/LICENSE-2.0
     *
     *    Unless required by applicable law or agreed to in writing, software
     *    distributed under the License is distributed on an "AS IS" BASIS,
     *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *    See the License for the specific language governing permissions and
     *    limitations under the License.
     */
    package org.apache.ibatis.binding;
    
    import java.io.Serializable;
    import java.lang.invoke.MethodHandles;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.util.Map;
    
    import org.apache.ibatis.lang.UsesJava7;
    import org.apache.ibatis.reflection.ExceptionUtil;
    import org.apache.ibatis.session.SqlSession;
    
    /**
     * @author Clinton Begin
     * @author Eduardo Macarron
     */
    public class MapperProxy<T> implements InvocationHandler, Serializable {
    
      private static final long serialVersionUID = -6424540398559729838L;
      private final SqlSession sqlSession;
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache;
    
      public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
      }
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
          } else if (isDefaultMethod(method)) {
            return invokeDefaultMethod(proxy, method, args);
          }
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        return mapperMethod.execute(sqlSession, args);
      }
    
      private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = methodCache.get(method);
        if (mapperMethod == null) {
          mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
          methodCache.put(method, mapperMethod);
        }
        return mapperMethod;
      }
    
      @UsesJava7
      private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
          throws Throwable {
        final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
            .getDeclaredConstructor(Class.class, int.class);
        if (!constructor.isAccessible()) {
          constructor.setAccessible(true);
        }
        final Class<?> declaringClass = method.getDeclaringClass();
        return constructor
            .newInstance(declaringClass,
                MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                    | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
            .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
      }
    
      /**
       * Backport of java.lang.reflect.Method#isDefault()
       */
      private boolean isDefaultMethod(Method method) {
        return ((method.getModifiers()
            & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC)
            && method.getDeclaringClass().isInterface();
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    (七)使用

    使用方式和Mybatis基本一样,只是功能简单。

    1. 创建一个实体类,一个操作数据库的接口(比如IUserMapper.class)
    2. 创建与接口(IUserMapper.class)对应的UserMapper.xml
    3. 在SqlMapConfig.xml 的配置中加上UserMapper.xml路径
    4. 通过SqlSession的getMapper()方法获取 ,通过动态代理生成的IUserMapper对象,然后调用IUserMapper里面的方法操作数据库

    IUserMapper

    <mapper namespace="com.lihua.mapper.IUserMapper">
    
        
        <select id="queryUserAll" resultType="com.lihua.pojo.User">
            select * from user
        select>
    
        
    
    
    
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    SqlMapConfig.xml

    <configuration>
    
        
        <dataSource>
            <property name="driverClass" value="com.mysql.jdbc.Driver">property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/book?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true">property>
            <property name="username" value="root">property>
            <property name="password" value="123">property>
        dataSource>
    
        
        <mapper resource="IUserMapper.xml">mapper>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    IUserMapper

    package com.lihua.mapper;
    
    import com.lihua.pojo.User;
    
    import java.util.List;
    
    /**
     * @author lihua
     * @date 2022/12/6 16:22
     */
    public interface IUserMapper {
    
        List<User> queryUserAll();
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    User

    package com.lihua.pojo;
    
    import lombok.Data;
    import lombok.ToString;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:17
     * user
     */
    @Data
    @ToString
    public class User {
        private long id;
        private String account;
        private String password;
        private String email;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    test

    package com.lihua.test;
    
    import com.lihua.custommybatis.DefaultSqlSession;
    import com.lihua.custommybatis.Resources;
    import com.lihua.custommybatis.SqlSessionFactory;
    import com.lihua.custommybatis.SqlSessionFactoryBuilder;
    import com.lihua.mapper.UserMapper;
    import com.lihua.pojo.User;
    
    import java.io.InputStream;
    
    /**
     * @author lihua
     * @date 2022/12/6 15:20
     * test
     */
    public class Test {
    
        @org.junit.Test
        public void  test(){
    
            InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
            DefaultSqlSession sqlSession = sqlSessionFactory.openSession();
            try {
                UserMapper mapper = sqlSession.getMapper(UserMapper.class);
                for (User user : mapper.queryUserAll()) {
                    System.out.println(user.toString());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    三、参考

    手写mybatis 1

    手写mybatis 2

  • 相关阅读:
    CF152C Pocket Book
    PHP框架详解 - Laravel 框架
    金仓数据库KingbaseES客户端编程接口指南-ado.net(10. 预编译语句)
    NLP(4)--实现一个线性层
    基于Docker容器DevOps应用方案
    SAP PI/PO中使用UDF解决按字节拆分字符串的需求
    JMeter —— 接口自动化测试(数据驱动)
    api调用钉钉群机器人发信息
    浅谈用Redis实现分布式锁的方案及细节
    Linux中apache服务安装与mysql安装
  • 原文地址:https://blog.csdn.net/a123123sdf/article/details/128207430