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

    书山有路勤为径,学海无涯苦作舟
  • 相关阅读:
    Postgresql HStore 插件试用小结
    postgres-xl 安装与部署 【异常处理】ERROR: could not open file (null)/STDIN_***_0 for write, No such file or directory
    GPDB 5.x PSQL Quick Reference
    postgresql 数据库schema 复制
    hive 打印日志
    gp与 pg 查询进程
    jquery table 发送两次请求 解惑
    python 字符串拼接效率打脸帖
    postgresql 日期类型处理实践
    IBM Rational Rose软件下载以及全破解方法
  • 原文地址:https://www.cnblogs.com/javammc/p/15450456.html
Copyright © 2011-2022 走看看