手写mybatis

手写mybatis(代理模式实战)

1、数据源配置与数据源工厂

hikari.properties

username=root
password=root
jdbcUrl=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
driverClassName=com.mysql.cj.jdbc.Driver

druid.properties

druid.url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPubl icKeyRetrieval=true&useSSL=false
druid.username=root
druid.password=root
druid.driverClassName=com.mysql.cj.jdbc.Driver

使用数据源工厂读取配置文件进行进行数据源的生成

DataSourceFactory

package com.assin.core;

import com.alibaba.druid.pool.DruidDataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;

/**
 * @Author:ASSIN
 * @Date: 2021/9/1 16:33
 */
public class DataSourceFactory {

    public static final String DATASOURCE_TYPE_HIKARI = "hikari";
    public static final String DATASOURCE_TYPE_DRUID = "druid";

    public static void main(String[] args) {
        DataSource dataSource = DataSourceFactory.CreateDataSource(DATASOURCE_TYPE_HIKARI);
        System.out.println(dataSource);
    }

    public static DataSource CreateDataSource(String type) {

        DataSource dataSource = null;
        Properties properties = new Properties();

        if ("hikari".equals(type)) {
            try {
                properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("hikari.properties"));

            } catch (IOException e) {
                e.printStackTrace();
            }

            HikariConfig hikariConfig = new HikariConfig(properties);
            dataSource = new HikariDataSource(hikariConfig);

        } else if ("druid".equals(type)) {
            try {
                properties.load(DataSourceFactory.class.getClassLoader().getResourceAsStream("druid.properties"));

            } catch (IOException e) {
                e.printStackTrace();
            }

        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.configFromPropety(properties);
        dataSource = druidDataSource;

        }
        return dataSource;
    }

}

2、基本配置文件

mybatis-config.properties

使用的数据源和对应的mapper配置

<mybatis>
  <dataSource>hikari</dataSource>
   <mapper>mapper/userMapper.xml</mapper>
</mybatis>

UserMapper.xml

包括 sql类型 返回类型 参数类型

<mapper namespace="com.assin.dao.UserDao">

    <insert id="saveUser" resultType="com.assin.entity.User" paramType="com.assin.entity.User">
        insert into user values(?,?,?)
    </insert>

    <select id="findUser" resultType="com.assin.entity.User" paramType="com.assin.entity.User">
        select * from user where id = ?
    </select>

</mapper>

3、实体类

User

package com.assin.entity;

import java.io.Serializable;

/**
 * @Author:ASSIN
 * @Date: 2021/9/1 17:48
 */
public class User implements Serializable {

    private int id;
    private String username;
    private String password;




    public User() {
    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

4、Dao

UserDao

package com.assin.dao;

import com.assin.entity.User;

import java.util.List;

/**
 * @Author:ASSIN
 * @Date: 2021/9/1 17:47
 */
public interface UserDao {

    /**
     * 保存用户
     * @param user
     * @return
     */
    Integer saveUser(User user);

    /**
     * 查找用户
     * @param id
     * @return
     */
    List<User> findUser(Integer id);


}

Dao包装将配置UserMapper.xml读取到内存中包装起来

DaoWrapper

package com.assin.core;

import java.io.Serializable;

/**
 * 用于描述一个Dao的方法的必要条件
 * @Author:ASSIN
 * @Date: 2021/9/1 18:02
 */
public class DaoWrapper implements Serializable {

    /**
     * 类型,insert|update|delete
     */
    private String type;

    /**
     * 返回值的类型
     */
    private String resultType;

    /**
     * 参数的类型
     * */
    private String paramType;

    /**
     * sql语句
     */
    private String sql;


    public DaoWrapper(String type, String resultType, String paramType, String sql) {

        this.type = type;
        this.resultType = resultType;
        this.paramType = paramType;
        this.sql = sql;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    public String getParamType() {
        return paramType;
    }

    public void setParamType(String paramType) {
        this.paramType = paramType;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    @Override
    public String toString() {
        return "DaoWrapper{" +
                "type='" + type + '\'' +
                ", resultType='" + resultType + '\'' +
                ", paramType='" + paramType + '\'' +
                ", sql='" + sql + '\'' +
                '}';
    }
}

5、会话

Session

package com.assin.core;

import com.assin.dao.UserDao;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.Map;

/**
 * 会话对象
 * @Author:ASSIN
 * @Date: 2021/9/1 19:21
 */
public class Session {

    /**
     * 每个会话持有一个连接
     */
    private Connection connection;
    private Map<String,Map<String,DaoWrapper>> env;

    public Session(Connection connection,Map<String,Map<String,DaoWrapper>> env) {
        this.connection = connection;
        this.env = env;
    }


    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public <T> T getMapper(Class clazz) {

       T t = (T) Proxy.newProxyInstance(Session.class.getClassLoader(),
                new Class[]{clazz},new SqlInvocationHandler(connection,env.get(clazz.getName())));

       return t;

    }
}

Session工厂

package com.assin.core;

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

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.*;

/**
 * @Author:ASSIN
 * @Date: 2021/9/1 19:23
 */
public class SessionFactory {

    private DataSource dataSource;

    private Map<String,Map<String,DaoWrapper>> env = new HashMap<>(8);

    public SessionFactory(String configPath) {


        parseConifgXml(configPath);


       // dataSource = DataSourceFactory.CreateDataSource(type);
    }

    /**
     * 解析配置文件,加载资源环境
     * @param configPath
     */
    private void parseConifgXml(String configPath) {
        try {
            //解析数据源
       SAXReader saxReader = new SAXReader();
       InputStream resourceAsStream = SessionFactory.class.getClassLoader().getResourceAsStream(configPath);

       Document read= saxReader.read(resourceAsStream);

        Element rootElement = read.getRootElement();

        Element dataSourceElement = rootElement.element("dataSource");

       dataSource =  DataSourceFactory.CreateDataSource(dataSourceElement.getTextTrim());



        //获取所有的mapper文件
            List mapperElements = rootElement.elements("mapper");
            List<String> mapperPaths = new ArrayList<>();
            for (Object o : mapperElements) {
                Element element = (Element)o;
                mapperPaths.add(element.getTextTrim());
            }


            for (String mapperPath : mapperPaths) {
                Map<String,DaoWrapper> wrapper = new HashMap<>(8);
                Document document = saxReader.read(Session.class.getClassLoader().getResourceAsStream(mapperPath));

                Element root = document.getRootElement();
                String namespace = root.attribute("namespace").getValue();
                Iterator iterator = root.elementIterator();

                while (iterator.hasNext()){

                    Element element = (Element) iterator.next();
                    String type = element.getName();
                    String id = element.attribute("id").getValue();
                    String resultType = element.attribute("resultType").getValue();
                    String paramType = element.attribute("paramType").getValue();
                    String sqlStr = element.getTextTrim();

                    wrapper.put(id,new DaoWrapper(type,resultType,paramType,sqlStr));
                }
                env.put(namespace,wrapper);
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    public Session openSession(){
        try {
            Session session = new Session(dataSource.getConnection(),env);
            return session;
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }
}

6、SQLHandler

package com.assin.core;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

/**
 * @Author:ASSIN
 * @Date: 2021/9/1 20:02
 */
public class SqlInvocationHandler implements InvocationHandler {

    /**
     * 传入一个连接
     */
    private Connection connection ;

    /**
     * 传入独立环境
     */
    private Map<String,DaoWrapper> env;

    public SqlInvocationHandler(Connection connection, Map<String, DaoWrapper> env) {
        this.connection = connection;
        this.env = env;
    }


    /**
     * 生成代理对象
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //拿到包装
        String name = method.getName();
        DaoWrapper daoWrapper = env.get(name);

        PreparedStatement statement = connection.prepareStatement(daoWrapper.getSql());

        //对每一种sql语句中操作
        if ("insert".equals(daoWrapper.getType())){

            //暂定传入一个对象
            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 ("select".equals(daoWrapper.getType())){
            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(daoWrapper.getResultType());
                Object object = clazz.newInstance();
                Field[] fields = clazz.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                    fields[i].setAccessible(true);
                    fields[i].set(object,resultSet.getObject(fields[i].getName()));
                }
                list.add(object);
            }
            return list;
        }

        return null;
    }
}

7、Test main

package com.assin;

import com.assin.core.Session;
import com.assin.core.SessionFactory;
import com.assin.dao.UserDao;
import com.assin.entity.User;

/**
 * @Author:ASSIN
 * @Date: 2021/9/1 19:27
 */
public class Test {

    public static void main(String[] args) {
        
        SessionFactory sessionFactory = new SessionFactory("mybatis-config.xml");
        Session session = sessionFactory.openSession();

        UserDao userDao = session.getMapper(UserDao.class);
        System.out.println(userDao.findUser(10));


    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
手写MyBatis框架可以遵循以下步骤: 1. 创建一个配置类,用于加载数据库配置信息和Mapper接口配置信息。 2. 创建一个SqlSession类,用于管理数据库连接、执行SQL语句和返回结果。 3. 创建一个Mapper接口,定义数据库操作方法。 4. 创建一个MapperProxy类,实现动态代理,将Mapper接口的方法调用转发给SqlSession执行对应的SQL语句。 5. 创建一个MapperRegistry类,用于管理Mapper接口和对应的MapperProxy对象。 6. 创建一个DefaultSqlSessionFactory类,用于创建SqlSession对象。 7. 创建一个SqlSessionFactoryBuilder类,用于读取配置信息并创建DefaultSqlSessionFactory对象。 8. 创建一个Configuration类,用于保存MyBatis的全局配置信息。 9. 创建一个Executor类,用于执行SQL语句。 10. 创建一个StatementHandler类,用于封装和执行JDBC操作。 11. 创建一个ResultSetHandler类,用于处理查询结果集。 12. 创建一个TypeHandler类,用于处理Java类型和数据库类型之间的转换。 13. 创建一个XMLMapperBuilder类,用于解析Mapper配置文件,并将解析结果注册到Configuration中。 14. 创建一个XMLConfigBuilder类,用于解析MyBatis配置文件,并将解析结果保存到Configuration中。 15. 在主程序中,使用SqlSessionFactoryBuilder读取配置信息创建SqlSessionFactory,并通过SqlSessionFactory创建SqlSession对象,最后使用SqlSession获取Mapper接口的代理对象,从而实现对数据库的操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值