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 }
执行测试类,结果如下所示:
Mybatis学习之自定义持久层框架(六) 自定义持久层框架:完善CRUD方法并进行测试的更多相关文章
- 【MyBatis学习笔记】
[MyBatis学习笔记]系列之预备篇一:ant的下载与安装 [MyBatis学习笔记]系列之预备篇二:ant入门示例 [MyBatis学习笔记]系列之一:MyBatis入门示例 [MyBatis学习 ...
- Mybatis(一):手写一套持久层框架
作者 : 潘潘 未来半年,有幸与导师们一起学习交流,趁这个机会,把所学所感记录下来. 「封面图」 自毕业以后,自己先创业后上班,浮沉了近8年,内心着实焦躁,虽一直是走科班路线,但在技术道路上却始终没静 ...
- Django框架(六)--模板层:变量、过滤器、标签、自定义标签和过滤器
将页面的设计和Python的代码分离开会更干净简洁更容易维护. 我们可以使用 Django的 模板系统 (Template System)来实现这种模式 # django模板修改的视图函数 def c ...
- mybatis学习笔记之基础框架(2)
mybatis学习笔记之基础框架(2) mybatis是一个持久层的框架,是apache下的顶级项目. mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成满足s ...
- 【MyBatis学习01】宏观上把握MyBatis框架
今天开始学习mybatis框架,博客主要记录学习过程中的一些总结,如有错误之处,欢迎留言指正~先用mybatis的鸟鸟来镇个楼,咳咳~~ mybatis框架是一个持久层框架,是Apache下的顶级项目 ...
- mybatis 学习笔记(三):mapper 代理开发 dao 层
mybatis 学习笔记(三):mapper 代理开发 dao 层 优势 通过使用mapper 代理,我们可以不需要去编写具体的实现类(使用 getMapper() 方法自动生成),只需编写接口即可, ...
- WisDom.Net 框架设计(八) 持久层
WisDom.Net ---持久层 1.什么是持久层 持久层负责最基础的功能支撑,为项目提供一个高层,统一,和并发的数据持久机制,提供了比如建立数据库连接,关闭数据库连接,执行sql语 ...
- mybatis学习笔记(六) -- maven+spring+mybatis从零开始搭建整合详细过程(下)
继续 mybatis学习笔记(五) -- maven+spring+mybatis从零开始搭建整合详细过程(上) 五.使用监听器启动Spring容器 1.修改pom.xml文件,添加Spring-we ...
- Unity3D学习笔记(二十六):MVC框架下的背包系统(1)
MVC背包 需求: 1.背包格子的装备是可以拖动的 2.装备栏的装备也是可以拖动的 3.当背包格子的装备拖动到装备栏时,如果是装备类型和装备栏类型是一致的能装上 4.背包的装备是按照顺序放在格子中的, ...
随机推荐
- CSS浮动布局带来的高度塌陷以及其解决办法
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...
- IPFS挖矿赚钱吗?IPFS挖矿是真的吗?
IPFS一出现就获得了极高的关注度,「让人类信息永存」的口号也让其蒙上了一层神秘的面纱.今天我就来给大家自剖析,一探IPFS技术的真相. IPFS是一个去中心化存储网络,而Filecoin是IPFS激 ...
- 菜刀jsp小马
逛google收获小马一枚,收藏一下 <%@page import="java.io.*,java.util.*,java.net.*,java.sql.*,java.text.*&q ...
- 开源的 Switch 模拟器——GitHub 热点速览 v.21.12
作者:HelloGitHub-小鱼干 脸滚键盘操作选手小鱼干这里要推荐一个超酷 Switch 模拟器,不能埋没你的游戏天赋.Ryujinx 是一个 C# 写的 Switch 模拟器,1700+ 游戏可 ...
- python中gzip模块的使用
gzip模块能够直接压缩和解压缩bytes-like类型的数据,同时也能实现对应格式文件的压缩与解压缩 一.数据压缩与解压缩 压缩 函数-gzip.compress(data, compresslev ...
- 计算机体系结构——CH5 标量处理机
计算机体系结构--CH5 标量处理机 右键点击查看图像,查看清晰图像 X-mind 计算机体系结构--CH5 标量处理机 先行控制技术 指令得重叠执行方式 顺序执行方式 一次重叠执行方式 二次重叠技术 ...
- 「HTML+CSS」--自定义加载动画【006】
前言 Hello!小伙伴! 首先非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 哈哈 自我介绍一下 昵称:海轰 标签:程序猿一只|C++选手|学生 简介:因C语言结识编程,随后转入计算机 ...
- C++并发与多线程学习笔记--unique_lock详解
unique_lock 取代lock_quard unique_lock 的第二个参数 std::adopt_lock std::try_to_lock std::defer_lock unique_ ...
- 腾讯高级工程师带你完整体验Node.js开发实战
Node.js拥有广大的 JavaScript程序员基础并且完全开源,它被广泛地用在 Web服务.开发工作流.客户端应用等诸多领域.在 Web 服务开发这个领域,业界对 Node.js 的接受程度最高 ...
- Java中获取类的运行时结构
获取运行时类的完整结构 通过反射获取运行时类的完整结构 Field(属性).Method(方法).Constructor(构造器).Superclass(父类).Interface(接口).Annot ...