栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

自定义持久层框架

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义持久层框架

自定义持久层框架

文章目录
    • 自定义持久层框架
  • 前言
  • 一、JDBC问题分析
  • 二、解决策略分析
  • 二、框架设计
    • 1.使用端
    • 2. 框架端
  • 三、实现
    • 1.使用端
    • 2.框架端
  • 总结


前言 例如:为什么连接数据库不再使用JDBC,而改用诸如Mybatis的持久层框架,此篇通过自定义持久层框架分析对比了二者的区别,及持久层的实现原理

提示:以下是本篇文章正文内容,下面案例可供参考

一、JDBC问题分析
  1. 数据库连接创建、释放频繁,造成系统资源浪费,从而影响系统性能;
  2. sql语句存在硬编码,不易扩展和维护;
  3. 查询结果集的封装存在硬编码,sql变化会导致解析变化,不易维护;
二、解决策略分析
  1. 连接频繁---->使用连接池
  2. sql语句硬编码----->使用配置文件
  3. 封装结果集硬编码 ------>使用反射、内省封装pojo对象
二、框架设计 1.使用端

提供核心配置文件
sqlMapConfig.xml 提供数据库配置信息,引入mapper.xml
mapper.xml 提供sql语句配置信息

2. 框架端
  1. 加载配置文件,以字节流读取到内存中
    创建Resources类,getResourceAsStaream方法,返回InputStream

  2. 创建Bean对象,存放解析出来的内容
    Configuration:核心配置类,存放sqlMapConfig.xml 解析出来的内容;
    MappedStatement:映射配置类,存放mapper.xml解析春来的内容;
    Configuration 中引入MappedStatement,便于传递执行。

  3. 解析配置文件
    创建类SqlSessionFactoryBuilder
    创建方法build
    该方法做了两件事:
    第一,dom4j解析字节输入流,封装成Configuration对象中;
    第二,创建工厂类SqlSessionFactory对象。

  4. 创建SQLSessionFactory接口及实现类DefaultSqlSessionFactory
    方法openSession,该方法获取SqlSession接口的实例类对象

  5. 创建SqlSession接口及实现类DefaultSession
    创建CRUD方法:selectList()、selectOne()、insert()、update()、delete()等,方法中调用Executor接口的实力类对象的方法
    优化:在SqlSession中添加getMapper方法,通过代理实现(代理对象在调用任何方法,都会执行getMapper中的invoke方法)

  6. 创建Executor接口及实现类SimpleExecutor
    该类的crud方法中执行的就是jdbc的代码:注册驱动获连接、获取sql、获取预处理对象、设置参数、执行sql、封装结果集

三、实现 1.使用端

sqlMapConfig.xml 代码如下:


    
    
        
        
        
        
    
    
    

sqlMapConfig.xml 代码如下:




    
        select * from user where id=#{id} and username=#{username}
    

    
        insert into user values(#{id},#{username})
    

    
        update user set username = #{username} where id = #{id}
    

    
        delete from user where id = #{id}
    




2.框架端

Resources.java代码如下:

    public static InputStream getResourceAsStaream(String path){
        InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
        return resourceAsStream;

SqlSessionFactoryBuilder.java代码如下:

    public SqlSessionFactory build(InputStream in) throws PropertyVetoException, documentException {

        //第一:使用dom4j解析配合文件,将解析出来的配置文件封装到Configuration中
        XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
        Configuration configuration = xmlConfigBuilder.parseConfig(in);

        //第二:创建SqlsessionFactory对象:工厂类:生产sqlSession:会话对象
        DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);

        return defaultSqlSessionFactory;
    }

XMLConfigBuilder.java代码如下:

    
    public Configuration parseConfig(InputStream in) throws documentException, PropertyVetoException {
        document document = new SAXReader().read(in);
        //根标签
        Element rootElement = document.getRootElement();
        List list = rootElement.selectNodes("//property");
        Properties properties = new Properties();
        for (Element element : list) {
            String name = element.attributevalue("name");
            String value = element.attributevalue("value");
            properties.setProperty(name,value);
        }
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
        comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
        comboPooledDataSource.setUser(properties.getProperty("username"));
        comboPooledDataSource.setPassword(properties.getProperty("password"));

        configuration.setDataSource(comboPooledDataSource);

        //mapper.xml解析:拿到路径--字节输入流---解析
        List mapperList = rootElement.selectNodes("//mapper");
        for (Element element : mapperList) {
            String mapperPath = element.attributevalue("resource");
            InputStream resourceAsStaream = Resources.getResourceAsStaream(mapperPath);
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
            xmlMapperBuilder.parse(resourceAsStaream);
        }



        return configuration;
    }

xmlMapperBuilder.java代码如下:

public void parse(InputStream inputStream) throws documentException {
        document document = new SAXReader().read(inputStream);
        Element rootElement = document.getRootElement();
        String namesapce = rootElement.attributevalue("namespace");
        List selectlist = rootElement.selectNodes("//select");
        List insertlist = rootElement.selectNodes("//insert");
        List updatelist = rootElement.selectNodes("//update");
        List deletelist = rootElement.selectNodes("//delete");
        //组装方法类型与标签集合的对应关系
        Map map = new HashMap();
        map.put("select",selectlist);
        map.put("insert",insertlist);
        map.put("update",updatelist);
        map.put("delete",deletelist);

        Iterator> it = map.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry entry = it.next();
            dealConfiguration(configuration,(List)entry.getValue(),(String)entry.getKey(),namesapce);
        }

    }


    
    private void dealConfiguration(Configuration configuration,List list,String methodType,String namesapce){
        for (Element element : list) {
            String id = element.attributevalue("id");
            String resultType = element.attributevalue("resultType");
            String paramterType = element.attributevalue("paramterType");
            String sqlText = element.getTextTrim();

            MappedStatement mappedStatement = new MappedStatement();
            mappedStatement.setId(id);
            mappedStatement.setResultType(resultType);
            mappedStatement.setParamterType(paramterType);
            mappedStatement.setSql(sqlText);
            mappedStatement.setMethodType(methodType);
            String key = namesapce + "." + id;
            configuration.getMappedStatementMap().put(key,mappedStatement);
        }

    }

DefaultSqlSession.java代码如下:

 @Override
    public  List selectList(String statementid, Object... params) throws Exception{
        //完成对SimpleExecutor里query方法的调用
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
        List list = simpleExecutor.query(configuration, mappedStatement, params);
        return (List) list;
    }
 

DefaultSqlSession.java代码如下:

   @Override
    public  List query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {

        //1.注册驱动获取连接
        Connection connection = configuration.getDataSource().getConnection();
        //2.获取SQL语句:  select * from user where id=#{id} and username=#{username}
        String sql = mappedStatement.getSql();
        //解析sql语句: select * from user where id=? and username=? 转换过程中,对#{}里面的值进行存储
        BoundSql boundSql = getBoundSql(sql);

        //3. 获取预处理对象:paramterStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());

        //4. 设置参数
         //获取参数全路径
        String paramterType = mappedStatement.getParamterType();
        Class paramterClass = getClassType(paramterType);
        List parameterMappings = boundSql.getParameterMappings();
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            //反射
            Field declaredField = paramterClass.getDeclaredField(content);
            //暴力访问
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            preparedStatement.setObject(i+1,o);
        }

        //5. 执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = mappedStatement.getResultType();
        Class resultTypeClass = getClassType(resultType);

        ArrayList objects = new ArrayList<>();

        //6. 封装返回结果集
        while(resultSet.next()){
            Object o = resultTypeClass.newInstance();
            //元数据,因为元数据带有列名
            ResultSetmetaData metaData = resultSet.getmetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                //字段名
                String columnName = metaData.getColumnName(i);
                //字段值
                Object value = resultSet.getObject(columnName);
                //使用反射或内省,根据数据库表和实体的对应关系完成封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName,resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o,value);
            }
            objects.add(o);
        }


        return (List) objects;
    }
 

总结 以上就是自定义持久层框架的思路及内容,其中对sql语句解析的类时mybatis中自带的类。
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号