手写mybatis框架

第⼀步:IDEA中创建模块

 
模块:godbatis(创建普通的Java Maven模块,打包方式jar),引入相关依赖
 
 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.god.ibatis</groupId>
    <artifactId>godbatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

<dependencies>
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.1</version>
    </dependency>
    <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.2.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.32</version>
    </dependency>
</dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

第二步:资源工具类,方便获取指向配置文件的输入流

package org.god.core;

import java.io.InputStream;

public class Resources {
    public Resources() {
    }

    public static InputStream getResourcesAsStream(String config){
        return Thread.currentThread().getContextClassLoader().getResourceAsStream(config);
    }
}

第三步:定义SqlSessionFactoryBuilder类

package org.god.core;
import java.io.InputStream;

public class SqlSessionFactoryBuilder {
 /**
 * 创建构建器对象
 */
 public SqlSessionFactoryBuilder() {
 }
 /**
 * 获取SqlSessionFactory对象
 * 该⽅法主要功能是:读取godbatis核⼼配置⽂件,并构建SqlSessionFactory对象
 * @param inputStream 指向核⼼配置⽂件的输⼊流
 * @return SqlSessionFactory对象
 */
 public SqlSessionFactory build(InputStream inputStream){
 // 解析配置⽂件,创建数据源对象
 // 解析配置⽂件,创建事务管理器对象
 // 解析配置⽂件,获取所有的SQL映射对象
 // 将以上信息封装到SqlSessionFactory对象中
 // 返回
 return null;
}
}

第四步:分析SqlSessionFactory类中有哪些属性

 

事务管理器 GodJDBCTransaction
 
SQL映射对象集合 Map<String, GodMappedStatement>
 
 

第五步:定义GodJDBCTransaction

事务管理器最好是定义⼀个接口,然后每⼀个具体的事务管理器都实现这个接口。

 

package org.god.core;

import java.sql.Connection;

public interface TransactionManager {

    void commit();

    void rollback();

    void close();

    void openConnection();

    Connection getConnection();
}
package org.god.core;

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

public class GodJDBCTransaction implements TransactionManager{

    private Connection conn;

    private DataSource dataSource;

    private boolean autoCommit;

    public GodJDBCTransaction(DataSource dataSource, boolean autoCommit) {
        this.dataSource = dataSource;
        this.autoCommit = autoCommit;
    }

    @Override
    public void commit() {
        try {
            conn.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void rollback() {
        try {
            conn.rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void close() {
        try {
            conn.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void openConnection() {
        try {
            this.conn = dataSource.getConnection();
            this.conn.setAutoCommit(this.autoCommit);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

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

第六步:事务管理器中需要数据源,定义GodUNPOOLEDDataSource

 

package org.god.core;

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;

public class GodUNPOOLEDDataSource implements javax.sql.DataSource{
    private String driver;
    private String url;
    private String username;

    private String password;

    public GodUNPOOLEDDataSource(String driver, String url, String username, String password) {
        //this.driver = driver;
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        this.url = url;
        this.username = username;
        this.password = password;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

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

第七步:定义GodMappedStatement

package org.god.core;

public class GodMappedStatement {
    private String sqlId;
    private String resultType;
    private String sql;
    private String parameterType;
    private String sqlType;

    public String getSqlId() {
        return sqlId;
    }

    public void setSqlId(String sqlId) {
        this.sqlId = sqlId;
    }

    public String getResultType() {
        return resultType;
    }

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

    public String getSql() {
        return sql;
    }

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

    public String getParameterType() {
        return parameterType;
    }

    public void setParameterType(String parameterType) {
        this.parameterType = parameterType;
    }

    public String getSqlType() {
        return sqlType;
    }

    public void setSqlType(String sqlType) {
        this.sqlType = sqlType;
    }

    public GodMappedStatement(String sqlId, String resultType, String sql, String parameterType, String sqlType) {
        this.sqlId = sqlId;
        this.resultType = resultType;
        this.sql = sql;
        this.parameterType = parameterType;
        this.sqlType = sqlType;
    }

    @Override
    public String toString() {
        return "GodMappedStatement{" +
                "sqlId='" + sqlId + '\'' +
                ", resultType='" + resultType + '\'' +
                ", sql='" + sql + '\'' +
                ", parameterType='" + parameterType + '\'' +
                ", sqlType='" + sqlType + '\'' +
                '}';
    }
}

第八步:完善SqlSessionFactory类

package org.god.core;

import java.util.Map;

public class SqlSessionFactory {
    private TransactionManager transactionManager;
    private Map<String,GodMappedStatement> mappedStatements;

    public TransactionManager getTransactionManager() {
        return transactionManager;
    }

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public Map<String, GodMappedStatement> getMappedStatements() {
        return mappedStatements;
    }

    public void setMappedStatements(Map<String, GodMappedStatement> mappedStatements) {
        this.mappedStatements = mappedStatements;
    }

    public SqlSessionFactory(TransactionManager transactionManager, Map<String, GodMappedStatement> mappedStatements) {
        this.transactionManager = transactionManager;
        this.mappedStatements = mappedStatements;
    }
   
}

第九步:完善SqlSessionFactoryBuilder中的build方法

 

package org.god.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.util.HashMap;
import java.util.Map;

public class SqlSessionFactoryBuilder {
    /**
     * 创建构建器对象
     */
    public SqlSessionFactoryBuilder() {
    }
    /**
     * 获取SqlSessionFactory对象
     * 该⽅法主要功能是:读取godbatis核⼼配置⽂件,并构建SqlSessionFactory对象
     *
     * @param inputStream 指向核⼼配置⽂件的输⼊流
     * @return SqlSessionFactory对象
     */
    public SqlSessionFactory build(InputStream inputStream) throws DocumentException {
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(inputStream);
        Element environmentsElt = (Element) document.selectSingleNode("/configuration/environments");
                String defaultEnv = environmentsElt.attributeValue("default");
        Element environmentElt = (Element) document.selectSingleNode("/configuration/environments/environment[@id='" + defaultEnv + "']");
        // 解析配置⽂件,创建数据源对象
        Element dataSourceElt = environmentElt.element("dataSource");
        DataSource dataSource = getDataSource(dataSourceElt);
        // 解析配置⽂件,创建事务管理器对象
        Element transactionManagerElt = environmentElt.element("transactionManager");
                TransactionManager transactionManager = getTransactionManager(transactionManagerElt, dataSource);
        // 解析配置⽂件,获取所有的SQL映射对象
        Element mappers = environmentsElt.element("mappers");
        Map<String, GodMappedStatement> mappedStatements = getMappedStatements(mappers);
        // 将以上信息封装到SqlSessionFactory对象中
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(transactionManager, mappedStatements);
        // 返回
        return sqlSessionFactory;
    }
    private Map<String, GodMappedStatement> getMappedStatements(Element mappers) {
        Map<String, GodMappedStatement> mappedStatements = new HashMap<>();
        mappers.elements().forEach((Element mapperElt) -> {
            try {
                String resource = mapperElt.attributeValue("resource");
                SAXReader saxReader = new SAXReader();
                Document document = saxReader.read(Resources.getResourcesAsStream(resource));
                Element mapper = (Element) document.selectSingleNode("/mapper");
                        String namespace = mapper.attributeValue("namespace");
                mapper.elements().forEach((Element sqlMapper) -> {
                    String sqlId = sqlMapper.attributeValue("id");
                    String sql = sqlMapper.getTextTrim();
                    String parameterType = sqlMapper.attributeValue("parameterType");
                            String resultType = sqlMapper.attributeValue("resultType");
                                    String sqlType = sqlMapper.getName().toLowerCase();
                    // 封装GodMappedStatement对象
                    GodMappedStatement godMappedStatement = new GodMappedStatement(sqlId, resultType, sql, parameterType, sqlType);
                    mappedStatements.put(namespace + "." + sqlId, godMappedStatement);
                });
            } catch (DocumentException e) {
                throw new RuntimeException(e);
            }
        });
        return mappedStatements;
    }
    private TransactionManager getTransactionManager(Element transactionManagerElt, DataSource dataSource) {
        String type = transactionManagerElt.attributeValue("type").toUpperCase();
        TransactionManager transactionManager = null;
        if ("JDBC".equals(type)) {
            // 使⽤JDBC事务
            transactionManager = new GodJDBCTransaction(dataSource, false
            );
        } else if ("MANAGED".equals(type)) {
            // 事务管理器是交给JEE容器的
        }
        return transactionManager;
    }
    private DataSource getDataSource(Element dataSourceElt) {
        // 获取所有数据源的属性配置
        Map<String, String> dataSourceMap = new HashMap<>();
        //Element  propertyElt = (Element) beanNode;
        dataSourceElt.elements().forEach(( Element propertyElt) -> {
            dataSourceMap.put(propertyElt.attributeValue("name"), propertyElt.attributeValue("value"));
        });
        String dataSourceType = dataSourceElt.attributeValue("type").toUpperCase();
        DataSource dataSource = null;
        if ("POOLED".equals(dataSourceType)) {
        } else if ("UNPOOLED".equals(dataSourceType)) {
            dataSource = new GodUNPOOLEDDataSource(dataSourceMap.get("driver"), dataSourceMap.get("url"), dataSourceMap.get("username"), dataSourceMap.get("password"));
        } else if ("JNDI".equals(dataSourceType)) {
        }
        return dataSource;
    }
}

第十步:在SqlSessionFactory中添加openSession方法

   public SqlSession openSession(){
        transactionManager.openConnection();
        SqlSession sqlSession=new SqlSession(transactionManager,mappedStatements);
        return sqlSession;
    }

第十一步:编写SqlSession类中commit rollback close方法

ackage org.god.core;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;



public class SqlSession {
    private TransactionManager transactionManager;
    private Map<String,GodMappedStatement> mappedStatements;

    public SqlSession(TransactionManager transactionManager,  Map<String,GodMappedStatement> mappedStatements) {
        this.transactionManager = transactionManager;
        this.mappedStatements = mappedStatements;
    }

    public void commit(){
        try {
            transactionManager.getConnection().commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    public void rollback(){
        try {
            transactionManager.getConnection().rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    public void close(){
        try {
            transactionManager.getConnection().close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

第十二步:编写SqlSession类中的insert,delete,select,update方法(略)

 public int insert(String sqlId, Object obj) {
        GodMappedStatement godMappedStatement = mappedStatements.get(sqlId);
        Connection connection = transactionManager.getConnection();
        // 获取sql语句
        // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
        String godbatisSql = godMappedStatement.getSql();
        // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
        String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
        // 重点⼀步
        Map<Integer, String> map = new HashMap<>();
        int index = 1;
        while (godbatisSql.indexOf("#") >= 0) {
            int beginIndex = godbatisSql.indexOf("#") + 2;
            int endIndex = godbatisSql.indexOf("}");
            map.put(index++, godbatisSql.substring(beginIndex, endIndex).trim(
            ));
            godbatisSql = godbatisSql.substring(endIndex + 1);
        }
        final PreparedStatement ps;
        try {
            ps = connection.prepareStatement(sql);
            // 给?赋值
            map.forEach((k, v) -> {
                try {
                    // 获取java实体类的get⽅法名
                    String getMethodName = "get" + v.toUpperCase().charAt(0) +
                            v.substring(1);
                    Method getMethod = obj.getClass().getDeclaredMethod(getMethodName);
                    ps.setString(k, getMethod.invoke(obj).toString());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            int count = ps.executeUpdate();
            ps.close();
            return count;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
  public Object selectOne(String sqlId, Object parameterObj){
        GodMappedStatement godMappedStatement = mappedStatements.get(sqlId);
        Connection connection = transactionManager.getConnection();
        // 获取sql语句
        String godbatisSql = godMappedStatement.getSql();
        String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
        // 执⾏sql
        PreparedStatement ps = null;
        ResultSet rs = null;
        Object obj = null;
        try {
            ps = connection.prepareStatement(sql);
            ps.setString(1, parameterObj.toString());
            rs = ps.executeQuery();
            if (rs.next()) {
                // 将结果集封装对象,通过反射
                String resultType = godMappedStatement.getResultType();
                Class<?> aClass = Class.forName(resultType);
                Constructor<?> con = aClass.getDeclaredConstructor();
                obj = con.newInstance();
                // 给对象obj属性赋值
                ResultSetMetaData rsmd = rs.getMetaData();
                int columnCount = rsmd.getColumnCount();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = rsmd.getColumnName(i);
                    String setMethodName = "set" + columnName.toUpperCase().charAt(0) + columnName.substring(1);
                    Method setMethod = aClass.getDeclaredMethod(setMethodName,
                            aClass.getDeclaredField(columnName).getType());
                    setMethod.invoke(obj, rs.getString(columnName));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            try {
                ps.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        return obj;
    }

第十三步:测试类及配置文件

import com.god.pojo

public class Car {
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guidePrice=" + guidePrice +
                ", produceTime='" + produceTime + '\'' +
                ", carType='" + carType + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

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

    public String getCarNum() {
        return carNum;
    }

    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getGuidePrice() {
        return guidePrice;
    }

    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }

    public String getProduceTime() {
        return produceTime;
    }

    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }

    public String getCarType() {
        return carType;
    }

    public void setCarType(String carType) {
        this.carType = carType;
    }

    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }
}
import org.junit.Test;
import prg.god.pojo.Car

public class testYourbatis {

    @Test
    public void testInsert() {
        SqlSession sqlSession = null;
        try {
            // 1.创建SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 2.创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("Yourbatis-config.xml"));
            // 3.创建SqlSession对象
            sqlSession = sqlSessionFactory.openSession();
            // 4.执⾏SQL
            Car car = new Car(null, "111", "宝⻢X7", 70.3, "2010-10-11", "燃油⻋");
            int count = sqlSession.insert("insertCar", car);
            System.out.println("更新了⼏条记录:" + count);
            // 5.提交
            sqlSession.commit();
        } catch (Exception e) {
            // 回滚
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        } finally {
            // 6.关闭
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    @Test
    public void testSelectOne() {
        SqlSession sqlSession = null;
        try {
            // 1.创建SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 2.创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
            // 3.创建SqlSession对象
            sqlSession = sqlSessionFactory.openSession();

// 4.执⾏SQL
            Car car = (Car) sqlSession.selectOne("selectCarByCarNum", "111");
            System.out.println(car);
            // 5.提交
            sqlSession.commit();
        } catch (Exception e) {
            // 回滚
            if (sqlSession != null) {
                sqlSession.rollback();
            }
            e.printStackTrace();
        } finally {
            // 6.关闭
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/po
wernode"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
        <mappers>
            <mapper resource="sqlmapper.xml"/>
        </mappers>
    </environments>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="car">
    <insert id="insertCar">
        insert into t_car(id,car_num,brand,guide_price,produce_time,car_ty
        pe) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carTyp
e})
    </insert>
    <select id="selectCarByCarNum" resultType="com.god.pojo.
Car">
        select id,car_num carNum,brand,guide_price guidePrice,produce_tim
        e produceTime,car_type carType from t_car where car_num = #{carNum}
    </select>
</mapper>

本项目是基于自学b站中动力节点老杜的mybatis视频,笔记仅供学习参考使用。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值