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 }

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

 

posted @ 2021-01-13 00:00  blayn  阅读(145)  评论(0编辑  收藏  举报