zoukankan      html  css  js  c++  java
  • 半天撸一个简易版mybatis

    为什么需要持久层框架?

    首先我们先看看使用原生jdbc存在的问题?

    public static void main(String[] args) {
     Connection connection = null;
     PreparedStatement preparedStatement = null;
     ResultSet resultSet = null;
     try {
     // 加载数据库驱动
     Class.forName("com.mysql.jdbc.Driver");
     // 通过驱动管理类获取数据库链接
     connection =
    DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?
    characterEncoding=utf-8", "root", "root");
     // 定义sql语句?表示占位符
     String sql = "select * from user where username = ?";
     // 获取预处理statement
     preparedStatement = connection.prepareStatement(sql);
     // 设置参数,第⼀个参数为sql语句中参数的序号(从1开始),第⼆个参数为设置的参数值
    preparedStatement.setString(1, "tom");
     // 向数据库发出sql执⾏查询,查询出结果集
     resultSet = preparedStatement.executeQuery();
     // 遍历查询结果集
     while (resultSet.next()) {
     int id = resultSet.getInt("id");
     String username = resultSet.getString("username");
     // 封装User
     user.setId(id);
     user.setUsername(username);
     }
     System.out.println(user);
     }
     } catch (Exception e) {
     e.printStackTrace();
     } finally {
     // 释放资源
     if (resultSet != null) {
     try {
     resultSet.close();
     } catch (SQLException e) {
     e.printStackTrace();
     }
     }
     if (preparedStatement != null) {
     try {
     preparedStatement.close();
     } catch (SQLException e) {
     e.printStackTrace();
     } }
     if (connection != null) {
     try {
     connection.close();
     } catch (SQLException e) {
     e.printStackTrace();
     }
     } }
    

    可以看出原始jdbc存在的问题如下:

    1. 数据库连接、创建、释放频繁造成资源浪,影响系统性能
    2. sql语句卸载代码里,不易维护,也不好复用
    3. 使用preparedStatement向占位符传参存在硬编码,如果where条件变了,需要改sql
    4. 对结果集解析存在硬编码,加字段需要改sql并且改解析的代码,如果能将数据库查出的记录封装成pojo对象解析会比较方便

    解决方法如下:

    1. 使用数据库连接池初始化连接资源
    2. 将sql语句抽取到xml配置文件中
    3. 使用反射等技术,自动将实体与表进行属性与字段的自动映射

    自定义持久层框架

    本质就是对jdbc的一个封装和功能的增强,大概需要这几个步骤

    1. 创建配置文件
      • sqlMapConfig.xml :数据库配置信息
      • xxMapper.xml:sql语句信息
    2. 创建两个bean(容器对象):存放的就是对配置文件解析出来的内容
      • Configuration(核心配置类):存放sqlMapConfig.xml解析出来的内容
      • MappedStatement(映射配置类):存放xxMapper.xml解析出来的内容
    3. 创建类SqlSessionFactoryBuilder
      • 使用dom4j解析配置文件,将内容封装到容器对象中
      • 创建SqlSessionFactory对象,生产SqlSession
    4. 创建SqlSessionFactory接口及实现类DefaultSqlSessionFactory。通过方法openSession生产SqlSession
    5. 创建接口SqlSession接口及实现类DefaultSqlSession。定义query、update、save接口
    6. 创建Executor接口及实现类SimpleExecutor,执行具体的jdbc代码操作。

    开发完成后,第一阶段我们的dao层的实现是这样的:

    public class UserDaoImpl implements UserDao {
    
        @Override
        public List<User> queryAll() throws IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, DocumentException, PropertyVetoException, ClassNotFoundException {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
            SqlSessionFactory builder = sqlSessionFactoryBuilder.builder("sqlMapConfig.xml");
            SqlSession sqlSession = builder.openSession();
            List<User> objects = sqlSession.queryAll("User.selectList");
            System.out.println(objects);
            return objects;
        }
    }
    

    可以看出还有两个明显需要改进的地方:

    • 每个dao层的实现都需要写大段重复代码,userDaoImpl写一次,ProductDaoImpl写一次
    • 每次调用queryAll都需要传入参数statementid

    那么可以怎么解决呢?

    • SqlSessionFactory可以做成单例,方便调取。Dao层的实现类重复编码可以通过动态代理实现,动态生成Dao的实现类,Dao层只写接口就行了。
    • statementid可以通过约定名称对应的方式替代

    代码如下:

    原dao层实现:

    public class UserDaoImpl implements UserDao {
    
        @Override
        public List<User> queryAll() throws IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, DocumentException, PropertyVetoException, ClassNotFoundException {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
            SqlSessionFactory builder = sqlSessionFactoryBuilder.builder("sqlMapConfig.xml");
            SqlSession sqlSession = builder.openSession();
            List<User> objects = sqlSession.queryAll("User.selectList");
            System.out.println(objects);
            return objects;
        }
    }
    

    动态代理:

      public <T> T getMapper(Class mapperClass) {
            Object instance = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (method.getName().equals("queryAll")) {
                        String className = method.getDeclaringClass().getName();
                        String statementid = className + "." + method.getName();
                        List<User> objects = queryAll(statementid);
                        return objects;
                    }
                    return null;
                }
            });
            return (T) instance;
        }
    

    简单的封装就完成了。
    总体项目地址:https://gitee.com/mmcLine/simple-mybatis

    书山有路勤为径,学海无涯苦作舟
  • 相关阅读:
    linux 下vi中关于删除某段,某行,或者全部删除的命令
    Crontab的格式
    Crontab的格式
    Eclipse验证码
    jetty插件配置(开发)
    MongoDB使用手册
    Docker学习笔记(1) — docker 常用命令
    debian网易163更新服务器 源
    ssh安装过程
    HTML——列表标签
  • 原文地址:https://www.cnblogs.com/javammc/p/15450456.html
Copyright © 2011-2022 走看看