• Mybatis学习之自定义持久层框架(六) 自定义持久层框架:完善CRUD方法并进行测试


    前言

    没想到会等到半年以后才来写这篇文章,我已经不记得当初自己想要在这篇文章中写什么了,还好有一些零散的笔记留着,就对照着上一篇文章及零散的笔记,把内容给补充完吧。

    完善CRUD方法

    完善DefaultSqlSession类实现查询单个及查询多个的接口

     1 package com.hardy.sqlSession;
     2 
     3 import com.hardy.pojo.Configuration;
     4 import com.hardy.pojo.MappedStatement;
     5 import java.sql.SQLException;
     6 import java.util.List;
     7 
     8 public class DefaultSqlSession implements SqlSession {
     9 
    10     private Configuration configuration;
    11 
    12     public DefaultSqlSession(Configuration configuration) {
    13         this.configuration = configuration;
    14     }
    15 
    16     // 处理器对象
    17     private Executor simpleExcutor = new SimpleExecutor();
    18 
    19     @Override
    20     public <E> List<E> selectList(String statementId, Object... params) throws Exception {
    21         // 对SimpleExecutor里的query方法的调用
    22         SimpleExecutor simpleExecutor = new SimpleExecutor();
    23         MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
    24         List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
    25 
    26         return (List<E>) list;
    27     }
    28 
    29     @Override
    30     public <T> T selectOne(String statementId, Object... params) throws Exception {
    31         List<Object> objects = selectList(statementId, params);
    32         if (objects.size() == 1) {
    33             return (T) objects.get(0);
    34         } else {
    35             throw new RuntimeException("查询结果过多或返回结果过多");
    36         }
    37 
    38     }
    39 
    40     public void close() throws SQLException {
    41         simpleExcutor.close();
    42     }
    43 
    44 }

    这里实现了单条记录查询即列表查询的方法。

    编写User实体类

     1 package com.hardy.pojo;
     2 
     3 /*
     4 * 实体类,对应数据库的user表
     5 * */
     6 public class User {
     7 
     8     private Integer id;
     9 
    10     private String username;
    11 
    12     public Integer getId() {
    13         return id;
    14     }
    15 
    16     public void setId(Integer id) {
    17         this.id = id;
    18     }
    19 
    20     public String getUsername() {
    21         return username;
    22     }
    23 
    24     public void setUsername(String username) {
    25         this.username = username;
    26     }
    27 }

    创建Executor接口及SimpleExecutor实现类

     1 package com.hardy.sqlSession;
     2 
     3 import com.hardy.pojo.Configuration;
     4 import com.hardy.pojo.MappedStatement;
     5 
     6 import java.sql.SQLException;
     7 import java.util.List;
     8 
     9 public interface Executor {
    10 
    11     public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception;
    12 
    13     void close() throws SQLException;
    14 
    15 }
      1 package com.hardy.sqlSession;
      2 
      3 import com.hardy.pojo.Configuration;
      4 import com.hardy.pojo.MappedStatement;
      5 import com.hardy.utils.GenericTokenParser;
      6 import com.hardy.utils.ParameterMapping;
      7 import com.hardy.utils.ParameterMappingTokenHandler;
      8 
      9 import java.beans.PropertyDescriptor;
     10 import java.lang.reflect.Field;
     11 import java.lang.reflect.InvocationTargetException;
     12 import java.lang.reflect.Method;
     13 import java.sql.*;
     14 import java.util.ArrayList;
     15 import java.beans.IntrospectionException;
     16 import java.util.List;
     17 
     18 public class SimpleExecutor implements Executor {
     19 
     20     private Connection connection = null;
     21 
     22     @Override
     23     public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement,Object[] params) throws SQLException, ClassNotFoundException, IllegalAccessException,
     24             InstantiationException, NoSuchFieldException, IntrospectionException, InvocationTargetException  {
     25         // 1、注册驱动,获取连接
     26         connection = configuration.getDataSource().getConnection();
     27 
     28         // 2、获取sql语句:select * from user where id = #{id} and username = #{username}(解析前)
     29         String sql = mappedStatement.getSql();
     30 
     31         // 3、对sql进行处理
     32         BoundSql boundSql = getBoundSql(sql);
     33 
     34         // 4、获取转换后的sql语句:// select * from where id = ? and username = ? (解析后)
     35         String finalSql = boundSql.getSqlText();
     36 
     37         // 5、获取预编译preparedStatement对象
     38         PreparedStatement preparedStatement = connection.prepareStatement(finalSql);
     39 
     40         // 6、设置参数,获取参数全路径
     41         String parameterType = mappedStatement.getParamterType();
     42         Class<?> paramterTypeClass = getClassType(parameterType);
     43 
     44 
     45 
     46         List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
     47 
     48         for (int i = 0; i < parameterMappingList.size(); i++) {
     49             ParameterMapping parameterMapping = parameterMappingList.get(i);
     50             String name = parameterMapping.getName();
     51 
     52             // 反射
     53             Field declaredField = paramterTypeClass.getDeclaredField(name);
     54             declaredField.setAccessible(true);
     55 
     56             // 参数的值
     57             Object o = declaredField.get(params[0]);
     58 
     59             // 给占位符赋值
     60             preparedStatement.setObject(i+1, o);
     61         }
     62 
     63         ResultSet resultSet = preparedStatement.executeQuery();
     64         String resultType = mappedStatement.getResultType();
     65         Class<?> resultTypeClass = getClassType(resultType);
     66         ArrayList<E> results = new ArrayList<E>();
     67         while (resultSet.next()) {
     68             ResultSetMetaData metaData = resultSet.getMetaData();
     69             E o = (E) resultTypeClass.newInstance();
     70             int columnCount = metaData.getColumnCount();
     71             for (int i = 1; i <= columnCount; i++) {
     72                 // 字段名
     73                 String columnName = metaData.getColumnName(i);
     74 
     75                 // 字段值
     76                 Object value = resultSet.getObject(columnName);
     77 
     78                 // 创建字段描述器,为属性生成读写方法
     79                 PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
     80 
     81                 // 获取写方法
     82                 Method writeMethod = propertyDescriptor.getWriteMethod();
     83 
     84                 // 向类中写入值
     85                 writeMethod.invoke(o, value);
     86             }
     87 
     88             results.add(o);
     89         }
     90 
     91         return results;
     92 
     93     }
     94 
     95     private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
     96         if (parameterType != null) {
     97             Class<?> aClass = Class.forName(parameterType);
     98             return aClass;
     99         }
    100 
    101         return null;
    102     }
    103 
    104     @Override
    105     public void close() throws SQLException {
    106         connection.close();
    107     }
    108 
    109     private BoundSql getBoundSql(String sql) {
    110         // 标记处理类:主要是配合通用标记解析器GenericTokenParser类完成对配置文件等的解析工作,其中TokenHandler主要完成对占位符的解析工作
    111         ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
    112         // GenericTokenParser:通用的标记解析器,完成了代码片段中的占位符的解析,然后再根据给定的标记处理器(TokenHandler)来进行表达式的处理
    113         // GenericTokenParser类 构造函数三个参数分别为openToken(开始标记)、closeToken(结束标记)、handler(标记处理器)
    114         GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
    115         String parse = genericTokenParser.parse(sql);
    116 
    117         List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
    118 
    119         BoundSql boundSql = new BoundSql(parse, parameterMappings);
    120 
    121         return boundSql;
    122     }
    123 
    124 }

    测试自定义持久层框架

    新建一个IPersistence_test项目,在IPersistence_test项目的pom.xml文件中引入相关依赖(注意:这里需要引入自定义好的持久层框架IPersistence,因此需要先将IPersistence进行maven install 打包):

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0"
     3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     5     <modelVersion>4.0.0</modelVersion>
     6 
     7     <groupId>com.hardy</groupId>
     8     <artifactId>IPersistence_test</artifactId>
     9     <version>1.0-SNAPSHOT</version>
    10 
    11     <properties>
    12         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    13         <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    14         <java.version>1.8</java.version>
    15         <maven.compiler.source>1.8</maven.compiler.source>
    16         <maven.compiler.target>1.8</maven.compiler.target>
    17     </properties>
    18 
    19     <!-- 引入自定义持久层框架的依赖 -->
    20     <dependencies>
    21         <dependency>
    22             <groupId>com.hardy</groupId>
    23             <artifactId>IPersistence</artifactId>
    24             <version>1.0-SNAPSHOT</version>
    25         </dependency>
    26     </dependencies>
    27 
    28 </project>

    编写测试类:

     1 package com.hardy.test;
     2 
     3 import com.hardy.io.Resources;
     4 import com.hardy.pojo.User;
     5 import com.hardy.sqlSession.SqlSession;
     6 import com.hardy.sqlSession.SqlSessionFactory;
     7 import com.hardy.sqlSession.SqlSessionFactoryBuilder;
     8 import org.junit.Test;
     9 
    10 import java.io.InputStream;
    11 import java.util.List;
    12 
    13 public class IPersistenceTest {
    14 
    15     @Test
    16     public void test() throws Exception {
    17         InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    18         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().builder(resourceAsStream);
    19         SqlSession sqlSession = sqlSessionFactory.openSession();
    20 
    21         System.out.println("自定义持久层框架,GO!");
    22         // 调用
    23         User user = new User();
    24         user.setId(1);
    25         user.setUsername("hardy");
    26         User user2 = sqlSession.selectOne("User.selectOne", user);
    27         System.out.println("查询单条记录:"+ user2);
    28 
    29         System.out.println("-----------------------------------------");
    30 
    31         List<User> users = sqlSession.selectList("User.selectList");
    32         System.out.println("查询多条记录:");
    33         for (User user1 : users) {
    34             System.out.println(user1);
    35         }
    36 
    37     }
    38 }

    执行测试类,结果如下所示:

     

    作者:blayn
    出处:https://www.cnblogs.com/blayn/
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
  • 相关阅读:
    变量的解构赋值 (1)对象
    变量的解构赋值 (1)数组
    const 命令
    let 命令
    【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治
    【BZOJ3771】Triple 生成函数+FFT
    【BZOJ4976】宝石镶嵌 DP
    【BZOJ4972】小Q的方格纸 前缀和
    【BZOJ4998】星球联盟 LCT+并查集
    【BZOJ4710】[Jsoi2011]分特产 组合数+容斥
  • 原文地址:https://www.cnblogs.com/blayn/p/14270036.html
Copyright © 2020-2023  润新知