前言
没想到会等到半年以后才来写这篇文章,我已经不记得当初自己想要在这篇文章中写什么了,还好有一些零散的笔记留着,就对照着上一篇文章及零散的笔记,把内容给补充完吧。
完善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 }
执行测试类,结果如下所示: