# 手写Mybatis框架 Mybatis框架简单实现 Mybatis原理

简易版Mybatis框架

自己的Mybatis框架设计图

在这里插入图片描述

  • 依照Mybatis的框架执行原理,实现简易版的Mybatis框架
数据库建User表:
  • 建立如下的实体表,用于增删改查
    在这里插入图片描述
CREATE TABLE `NewTable` (
`id`  int(20) NOT NULL AUTO_INCREMENT ,
`username`  varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`password`  varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`gender`  int(1) NULL DEFAULT NULL ,
`age`  int(2) NULL DEFAULT NULL ,
`idcard`  int(20) NULL DEFAULT NULL ,
`phone`  int(15) NULL DEFAULT NULL ,
PRIMARY KEY (`id`)
);
新建Maven项目引入需要的依赖
  • 引入Mysql驱动依赖、Dom4j(解析Xml)、FastJson(Json工具)
<dependencies>
    <!-- Mysql 驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <!-- xml解析工具包 -->
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.1</version>
    </dependency>

    <!-- Json工具-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
</dependencies>
数据源配置文件:mysqlconfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<database>
    <property name="driverClassName">com.mysql.jdbc.Driver</property>
    <property name="url">jdbc:mysql://localhost:3306/test</property>
    <property name="username">root</property>
    <property name="password">root</property>
</database>
连接数据库和解析Mapper的工具类:MyConfiguration
public class MyConfiguration {
    
    

    private ClassLoader classLoader=ClassLoader.getSystemClassLoader();
    private Logger logger= LoggerFactory.getLogger(MyConfiguration.class);

    /**
     * 读取数据库的Xml信息
     */
    public Connection getDataSourceInfo(){
    
    
        try{
    
    
            InputStream inputStream=classLoader.getResourceAsStream("mysqlconfig.xml");
            SAXReader reader=new SAXReader();
            Document document=reader.read(inputStream);
            Element element=document.getRootElement();
            logger.info("==========数据库配置信息读取成功!");
            return getConnection(element);
        }catch (Exception e){
    
    
            logger.error(e.getMessage());
            return null;
        }
    }

    /**
     * 得到XMl中的数据库的配置信息返回连接
     */
    private Connection getConnection(Element element) {
    
    
            String driverClassName=null;
            String url=null;
            String username=null;
            String password=null;
            if(!"database".equals(element.getName())){
    
    
                throw new RuntimeException("数据库xml配置读取错误!");
            }
            List<Object> property = element.elements("property");
            for (Object o : property) {
    
    
                Element el= (Element) o;
                String name = el.attribute(0).getValue();
                String value= (String) el.getData();
                if(name==null || value==null){
    
    
                    throw new RuntimeException("property信息读取失败!");
                }
                switch (name){
    
    
                    case "driverClassName":
                        driverClassName=value;
                        break;
                    case "url":
                        url=value;
                        break;
                    case "username":
                        username=value;
                        break;
                    case "password":
                        password=value;
                        break;
                    default:
                        throw new RuntimeException("==========数据库信息有错误!");
                }
            }
        try {
    
    
            Connection connection=null;
            Class.forName(driverClassName);
            logger.info("==========连接数据库获取驱动成功!");
            connection= DriverManager.getConnection(url,username,password);
            logger.info("==========连接数据库成功!");
            return connection;
        }catch (Exception e){
    
    
            logger.error(e.getMessage());
            return null;
        }
    }

    /**
     * 读取Mapper和xml中的配置信息
     */
    public MapperBean readMapper(String path){
    
    
        MapperBean mapperBean=new MapperBean();
        try{
    
    
            InputStream inputStream=classLoader.getResourceAsStream(path);
            SAXReader saxReader=new SAXReader();
            Document document=saxReader.read(inputStream);
            Element root=document.getRootElement();

            // 存储xml文件中namespace的值
            mapperBean.setInterfaceName(root.attributeValue("namespace").trim());
            // 存储方法
            List<Function> list=new ArrayList<>();
            for(Iterator iterator=root.elementIterator();iterator.hasNext();){
    
    
                Function function=new Function();
                Element element= (Element) iterator.next();

                String sqlType=element.getName().trim();
                String functionNam=element.attributeValue("id").trim();
                String sql=element.getText().trim();
                String resultType=null;
                Object newinstance=null;
                if(null!=element.attributeValue("resultType")){
    
    
                    resultType=element.attributeValue("resultType");
                    try{
    
    
                        newinstance=Class.forName(resultType).newInstance();
                    }catch (Exception e){
    
    
                        logger.error(e.getMessage());
                    }
                    function.setResultType(resultType);
                }
                function.setFunctionName(functionNam);
                function.setSqlType(sqlType);
                function.setSql(sql);
                list.add(function);
            }
            // 所有的mapper.xml文件解析后保存
            mapperBean.setList(list);
        }catch (Exception e){
    
    
            return null;
        }
        return mapperBean;
    }
}
存放Mapper类信息的实体类:MapperBean、省略setget方法
public class MapperBean {
    
    

    // 接口名
    private String interfaceName;
    // 接口下的所有方法
    private List<Function> list;
    public MapperBean(){
    
    }

    public MapperBean(String interfaceName, List<Function> list) {
    
    
        this.interfaceName = interfaceName;
        this.list = list;
    }
    @Override
    public String toString() {
    
    
        return "MapperBean{" +
                "interfaceName='" + interfaceName + '\'' +
                ", list=" + list +
                '}';
    }
}
存放Mapper.xml的信息的实体类:Function
public class Function {
    
    
    private String sqlType;
    private String functionName;
    private String sql;
    private String resultType;
    private String parameterType;
    public Function(){
    
    }

    public Function(String sqlType, String functionName, String sql, String resultType, String parameterType) {
    
    
        this.sqlType = sqlType;
        this.functionName = functionName;
        this.sql = sql;
        this.resultType = resultType;
        this.parameterType = parameterType;
    }
}

MyMapperProxy代理类完成读取的UserMapper.xml中方法与真实方法校验,并调用执行对应的方法
public class MyMapperProxy implements InvocationHandler {
    
    

    private MysqlSession mysqlSession;
    private MyConfiguration myConfiguration;


    public MyMapperProxy(MysqlSession mysqlSession, MyConfiguration myConfiguration) {
    
    
        this.mysqlSession = mysqlSession;
        this.myConfiguration = myConfiguration;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        MapperBean mapperBean = myConfiguration.readMapper("UserMapper.xml");
        // 判断是否是xml文件对应的接口
        if (!method.getDeclaringClass().getName().equals(mapperBean.getInterfaceName())) {
    
    
            return null;
        }
        List<Function> list = mapperBean.getList();
        if (!CollectionUtils.isEmpty(list)) {
    
    
            for (Function x : list) {
    
    
                if (judge(method, x, "selectById")) {
    
    
                    return mysqlSession.selectOne(x.getSql(), String.valueOf(args[0]));
                }
                if (judge(method, x, "deleteById")) {
    
    
                    mysqlSession.deleteOne(x.getSql(), String.valueOf(args[0]));
                }
                if (judge(method, x, "insert")) {
    
    
                    mysqlSession.insertOne(x.getSql(), String.valueOf(args[0]));
                }
                if (judge(method, x, "updateById")) {
    
    
                    mysqlSession.updateOne(x.getSql(), String.valueOf(args[0]));
                }
            }
        }
        return null;
    }


    /**
     * 判断Mapper文件中id是否一致
     */
    private boolean judge(Method method, Function x, String methodId) {
    
    
        return method.getName().equals(x.getFunctionName()) && x.getFunctionName().equals(methodId);
    }
}
MysqlSession类,其中getMapper()动态代理的方式获取对象
public class MysqlSession {
    
    

    private Logger logger= LoggerFactory.getLogger(MysqlSession.class);

    private MyConfiguration myConfiguration=new MyConfiguration();

    private Excutor excutor=new ExcutorImpl();

    public <T> T selectOne(String statment,Object parameter){
    
    
        logger.info("我是query的SqlSession!");
        return  excutor.query(statment,parameter);
    }

    public void insertOne(String statment,Object parmeter){
    
    
        logger.info("我是save的SqlSession!");
        excutor.save(statment,parmeter);
    }

    public void updateOne(String statment,Object parmeter){
    
    
        logger.info("我是modify的SqlSession!");
        excutor.modify(statment,parmeter);
    }
    public void deleteOne(String statment,Object parmeter){
    
    
        logger.info("我是remove的SqlSession!");
        excutor.remove(statment,parmeter);
    }

    public <T> T getMapper(Class<T> clazz){
    
    
        logger.info("已经通过代理获取对象!");
        // 动态代理
        return  (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{
    
    clazz}, new MyMapperProxy(this, myConfiguration));

    }
}
增删改查底层接口:Excutor
public interface Excutor {
    
    

    <T> T query(String statement,Object parameter);

    void save(String statement,Object parameter);

    void modify(String statement,Object parameter);

    void remove(String statement,Object parameter);
}
增删改查底层接口实现:ExcutorImpl
  • 连接数据库,Jdbc方式进行怎删改查操作
public class ExcutorImpl implements Excutor {
    
    

    private Logger logger= LoggerFactory.getLogger(ExcutorImpl.class);

    private MyConfiguration myConfiguration=new MyConfiguration();

    Connection connection = myConfiguration.getDataSourceInfo();

    @Override
    public <T> T query(String statement, Object parameter) {
    
    
        try{
    
    
            PreparedStatement preparedStatement = connection.prepareStatement(statement);
            preparedStatement.setString(1,parameter.toString());
            ResultSet resultSet = preparedStatement.executeQuery();
            User user=new User();
            while (resultSet.next()){
    
    
                user.setId(resultSet.getInt("id"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                user.setGender(resultSet.getInt("gender"));
                user.setAge(resultSet.getInt("age"));
                user.setIdcard(resultSet.getInt("idcard"));
                user.setPhone(resultSet.getInt("phone"));
            }
            logger.info("遍历结果集完成!");
            return (T)user;
        }catch (Exception e){
    
    
            logger.error("查询结果报错"+e.getMessage());
            return null;
        }
    }

    @Override
    public void save(String statement, Object parameter) {
    
    
        try {
    
    
            connection.setAutoCommit(false);
            PreparedStatement preparedStatement = connection.prepareStatement(statement);
            User user = JSON.parseObject(String.valueOf(parameter),User.class);
            preparedStatement.setInt(1,user.getId());
            preparedStatement.setString(2,user.getUsername());
            preparedStatement.setString(3,user.getPassword());
            preparedStatement.setInt(4,user.getGender());
            preparedStatement.setInt(5,user.getAge());
            preparedStatement.setInt(6,user.getIdcard());
            preparedStatement.setInt(7,user.getPhone());

            preparedStatement.execute();
            comit(connection);
            logger.info("保存成功!");
        } catch (Exception e ) {
    
    
            logger.error("保存失败"+e.getMessage());
            rollBack(connection);
        }
    }

    @Override
    public void modify(String statement, Object parameter) {
    
    
        try {
    
    
            PreparedStatement preparedStatement = connection.prepareStatement(statement);
            User user = JSON.parseObject(String.valueOf(parameter),User.class);
            preparedStatement.setInt(3,user.getId());
            preparedStatement.setString(1,user.getUsername());
            preparedStatement.setString(2,user.getPassword());

            preparedStatement.execute();
            comit(connection);
            logger.info("修改成功!");

        } catch (SQLException e) {
    
    
            logger.error("修改失败"+e.getMessage());
            rollBack(connection);
        }
    }

    @Override
    public void remove(String statement, Object parameter) {
    
    
        try {
    
    
            PreparedStatement preparedStatement = connection.prepareStatement(statement);
            preparedStatement.setString(1,parameter.toString());
            preparedStatement.execute();
            logger.info("删除成功!");
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }
    }


    /**
     * 事物提交
     */
    private void comit(Connection connection){
    
    
        try {
    
    
            connection.commit();
            logger.error("事物提交成功!");
        }catch (Exception e){
    
    
            logger.error("事物提交失败!"+e.getMessage());
        }
    }

    /**
     * 事物回滚
     */
    private void rollBack(Connection connection){
    
    
        try{
    
    
            connection.rollback();
            logger.info("事物回滚成功!");
        } catch (Exception e){
    
    
            logger.info("事物回滚失败!"+e.getMessage());
        }
    }

}
User实体类
public class User {
    
    

    private int id;
    private String username;
    private String password;
    private int gender;
    private int age;
    private int idcard;
    private int phone;
    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender=" + gender +
                ", age=" + age +
                ", idcard=" + idcard +
                ", phone=" + phone +
                '}';
    }
}

UserMapper类
public interface UserMapper {
    
    

    User selectById(String id);
    void insert(Object user);
    void updateById(Object user);
    void deleteById(String id);
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.li.mybatisconfig.mapper.UserMapper">

    <select id="selectById" resultType="com.li.mybatisconfig.entity.User">
        select * from user where id=?
    </select>

    <delete id="deleteById" >
        delete from user where id=?
    </delete>

    <insert id="insert">
        insert into user (id,username,password,gender,age,idcard,phone) values(?,?,?,?,?,?,?)
    </insert>

    <update id="updateById">
        update user set username=?,password=? where id=?
    </update>

</mapper>
增删改查测试类:MybatisTestRunner
public class MybatisTestRunner {
    
    

    MysqlSession mysqlSession=new MysqlSession();
    UserMapper mapper=mysqlSession.getMapper(UserMapper.class);

    @Test
    public void findById(){
    
    
        User user = mapper.selectById("1");
        System.out.println(user);
    }

    @Test
    public void insert(){
    
    
        User user=new User();
        user.setId(2);
        user.setUsername("test1");
        user.setPassword("test1");
        mapper.insert(JSON.toJSON(user));
    }

    @Test
    public void deleteById(){
    
    
        mapper.deleteById("1");
    }

    @Test
    public void update(){
    
    
        User user=new User();
        user.setId(2);
        user.setUsername("test2");
        user.setPassword("test2");
        mapper.updateById(JSON.toJSON(user));
    }
}
  • 查询接口方法运行日志打印如下
    在这里插入图片描述

很Nice 感觉Mybatis 不是那么难 哈哈 哈哈!

代码详情见https://gitee.com/Marlon_Brando/back.git

猜你喜欢

转载自blog.csdn.net/qq_37248504/article/details/108371768
今日推荐