zoukankan      html  css  js  c++  java
  • 闭关修炼180天--手写持久层框架(mybatis简易版)

    闭关修炼180天--手写持久层框架(mybatis简易版)

     

    抛砖引玉

    首先先看一段传统的JDBC编码的代码实现:

    //传统的JDBC实现
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            //通过驱动管理类获取数据库管理
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8","root","root");
            //定义sql语句
            String sql = "select * from user where username = ?";
            //获取预处理对象statement
            preparedStatement  = connection.prepareStatement(sql);
            //设置参数,第一个参数为sql语句中的参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1,"tom");
            //像数据库发出sql执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                int id = resultSet.getInt("id");
                String username = resultSet.getString("username");
                String password = resultSet.getString("password");
                //将查询出的结果集封装进实体中
                User user = new User();
                user.setId(id);
                user.setUsername(username);
                user.setPassword(password);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //释放资源
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    

    通过以上传统的JDBC操作数据库的代码可以发现,我们能总结出来以下几条问题:

    • 每执行一次sql都要建立一次数据库连接,数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。

    • Sql编写在了代码中存在硬编码问题,实际上工作中sql变化是比较大的,每次都要修改代码,sql语句不易维护。

    • 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能 多也可能少,修改sql还要修改代码,系统不易维护。

    • 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库 记录自动封装成pojo对象解析比较方便。

    针对以上的几条JDBC问题,我们可以大致的延伸出以下几点的解决思路:

    • 使用数据库连接池初始化连接资源。

    • 将sql语句写在xml文件中,在代码中剥离出来单独维护。

    • 使用反射内省等技术,完成数据库的表字段和实体的属性的自动映射。

    深入剖析

    本次完成持久层框架的自定义编写便是从以上几个方面入手,来解决传统的JDBC存在的问题,在编写之前,我们首先要明白,框架属于开发的一个半成品,是我们在开发过程中可以直接拿来用的东西,我们在自定义编写时,什么代码是框架中所有的,什么代码属于使用端(一般开发人员)提供的,这点要想明白。经分析,大体划分如下:

    使用端

    • 提供核心配置文件:
      • sqlMapConfig.xml文件,配置数据源等信息,同时引入Mapper.xml。
      • Mapper.xml文件,配置sql语句等信息。

    框架端

    • 读取配置文件,将配置文件加载成字节输入流存放在内存中,准备好两个javaBean用来存储以后解析配置文件出来的数据。
      • Configuration:存放数据源信息dataBase、Map<String,MappedStatement>、key为唯一标识:namespace+id,value是sql相关信息实体。
      • MappedStatement:存放sql相关信息,包含id,sql语句,入参类型,返回值类型等。
    • 解析配置文件,创建SqlSessionFactoryBuild类,提供build(InputStream in)方法,用于构建SqlSessionFactory。

      • 使用dom4j技术解析xml配置文件,将解析出来的数据存放到javaBean中。
      • 创建SqlSessionFactory的实现类DefaultSqlSessionFactory
    • 生产会话对象。在SqlSessionFactory中提供openSession()方法,用于生产SqlSession。

    • 创建SqlSession接口及其实现类,用于封装crud方法。

      • selectList(String statementId,Object... param) 查询全部
      • selectOne(String statementId,Object... param) 查询单个
    • 执行实际的JDBC操作。创建Executor接口及其实现类SimpleExecutor,提供query(Configuration configuration, MappedStatement mappedStatement, Object... params)方法,完成实际的与数据库交互的工作。

      • 从连接池中获取连接
      • 处理sql语句
      • 设置参数
      • 封装结果集

    涉及到的设计模式

    • 构建者模式
    • 工厂模式
    • 代理模式

    代码实现

    这里只贴出核心代码,全部代码请看我的码云:https://gitee.com/zang-chuanlei/FrameMyBatis.git

    在这里需要创建两个项目:FrameMyBatistest和FrameMyBatis,其中FrameMyBatis_test代表的是使用端,FrameMyBatis代表的是框架端,项目结构如下:

     

    1.在FrameMyBatis_test下面的resources目录下添加两个配置文件sqlMapConfig.xml和UserMapper.xml

    <configuration>
        <dataSource>
            <property name="dataDriver" value="com.mysql.jdbc.Driver"></property>
            <property name="dataUrl" value="jdbc:mysql:///mybatis"></property>
            <property name="username" value="root"></property>
            <property name="password" value="root"></property>
        </dataSource>
        <!--加载UserMapper.xml配置文件-->
        <mapper resource="UserMapper.xml"></mapper>
    </configuration>
    <mapper namespace="com.zae.dao.UserDao">
    
        <select id="findAll" resultType="com.zae.entity.User">
            select * from users
        </select>
    
        <select id="findOne" resultType="com.zae.entity.User" paramterType="com.zae.entity.User">
            select * from users where id=#{id} and username=#{username}
        </select>
    
    </mapper>

    2.给FrameMyBatis引入一些需要的坐标

    <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.17</version>
            </dependency>
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.12</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.10</version>
            </dependency>
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
            <dependency>
                <groupId>jaxen</groupId>
                <artifactId>jaxen</artifactId>
                <version>1.1.6</version>
            </dependency>
    
        </dependencies>

    3.在FrameMyBatis下创建Resources类,用于加载字节输入流。

    import java.io.InputStream;
    
    public class Resources {
        /**
         * 根据xml路径将xml文件加载成字节流,存放在内存中
         * @param path
         * @return
         */
        public static InputStream getInputStreamByXml(String path){
            InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
            return resourceAsStream;
        }
    }

    4.创建两个bean,Configuration和MappedStatement

    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * javaBean之一:用来装sqlMapConfig.xml文件的内容
     */
    public class Configuration {
    
        /**
         * 存储数据源连接信息
         */
        private DataSource dataSource;
    
        /**
         * 存储加载进来的mapper.xml里面的数据
         * key = statementId = namespace+"."+id
         * value = mapperStatement
         */
        private Map<String,MapperStatement> mapperStatementMap = new HashMap<String, MapperStatement>();
    
    
        public DataSource getDataSource() {
            return dataSource;
        }
    
        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        public Map<String, MapperStatement> getMapperStatementMap() {
            return mapperStatementMap;
        }
    
        public void setMapperStatementMap(Map<String, MapperStatement> mapperStatementMap) {
            this.mapperStatementMap = mapperStatementMap;
        }
    }
    /**
     * javaBean-2用来装载mapper.xml的数据
     * 一条sql语句信息封装在一个MapperStatement对象中
     */
    public class MapperStatement {
    
        private String id;
    
        private String resultType;
    
        private String paramterType;
    
        private String sql;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getResultType() {
            return resultType;
        }
    
        public void setResultType(String resultType) {
            this.resultType = resultType;
        }
    
        public String getParamterType() {
            return paramterType;
        }
    
        public void setParamterType(String paramterType) {
            this.paramterType = paramterType;
        }
    
        public String getSql() {
            return sql;
        }
    
        public void setSql(String sql) {
            this.sql = sql;
        }
    }

    5.创建SqlSessionFactoryBuild

    import com.zae.config.XmlConfigBuilder;
    import com.zae.pojo.Configuration;
    
    import java.io.InputStream;
    
    public class SqlSessionFactoryBuilder {
    
        /**
         * 构建SqlSessionFactory工厂
         * @param inputStream
         * @return
         */
        public SqlSessionFactory build(InputStream inputStream) throws Exception{
            //完成xml文件的解析
            XmlConfigBuilder xmlConfigBuilder = new XmlConfigBuilder();
            Configuration configuration = xmlConfigBuilder.parasConfig(inputStream);
    
            DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
            return defaultSqlSessionFactory;
        }
    }

    6.创建解析XML文件的两个专属类XmlConfigBuilder和XmlMapperBuilder

    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import com.zae.io.Resources;
    import com.zae.pojo.Configuration;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.io.InputStream;
    import java.util.List;
    import java.util.Properties;
    
    /**
     * 解析sqlMapConfig.xml文件存放在javaBean中
     */
    public class XmlConfigBuilder {
    
        private Configuration  configuration;
    
        public XmlConfigBuilder(){
            this.configuration = new Configuration();
        }
    
        /**
         * 解析sqlMapConfig.xml文件
         * @param inputStream
         * @return
         */
        public Configuration parasConfig(InputStream inputStream) throws Exception{
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            //获取根标签里面的内容
            Element rootElement = document.getRootElement();
            //获取所有的property标签里面的内容
            List<Element> list = rootElement.selectNodes("//property");
            //将数据库连接信息读取到properties文件中
            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("dataDriver"));
            comboPooledDataSource.setJdbcUrl(properties.getProperty("dataUrl"));
            comboPooledDataSource.setUser(properties.getProperty("username"));
            comboPooledDataSource.setPassword(properties.getProperty("password"));
            //给configuration里面的数据源属性赋值
            configuration.setDataSource(comboPooledDataSource);
    
            //解析xl文件的数据
            List<Element> mapperList = rootElement.selectNodes("//mapper");
            for (Element element : mapperList) {
                //获取到mapper.xml文件的路径
                String resource = element.attributeValue("resource");
                //获取mapper文件的输入流
                InputStream mapperInputStream = Resources.getInputStreamByXml(resource);
                XmlMapperBuilder xmlMapperBuilder = new XmlMapperBuilder(configuration);
                xmlMapperBuilder.parasMapper(mapperInputStream);
            }
    
    
            return configuration;
        }
    }
    import com.zae.pojo.Configuration;
    import com.zae.pojo.MapperStatement;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.io.InputStream;
    import java.util.List;
    /**
     * 解析mapper.xml数据存放到javaBean中
     */
    public class XmlMapperBuilder {
    
        private Configuration configuration;
    
        public XmlMapperBuilder(Configuration configuration){
            this.configuration = configuration;
        }
    
        public void parasMapper(InputStream mapperInputStream) throws Exception {
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(mapperInputStream);
            //获取根标签的数据-mapper
            Element rootElement = document.getRootElement();
            //获取命名空间
            String namespace = rootElement.attributeValue("namespace");
            //获取所有的select标签的内容
            List<Element> elementList = rootElement.selectNodes("//select");
            for (Element element : elementList) {
                String id = element.attributeValue("id");
                String resultType = element.attributeValue("resultType");
                String paramterType = element.attributeValue("paramterType");
                String sql = element.getTextTrim();
                MapperStatement mapperStatement = new MapperStatement();
                mapperStatement.setId(id);
                mapperStatement.setResultType(resultType);
                mapperStatement.setParamterType(paramterType);
                mapperStatement.setSql(sql);
                String key = namespace+"."+id;
                configuration.getMapperStatementMap().put(key,mapperStatement);
            }
        }
    }

    7.创建sqlSessionFactory接口及DefaultSqlSessionFactory 实现类

    public interface SqlSessionFactory {
        SqlSession openSqlSession();
    }
    import com.zae.pojo.Configuration;
    
    public class DefaultSqlSessionFactory implements SqlSessionFactory {
    
        private Configuration configuration;
    
        public DefaultSqlSessionFactory(Configuration configuration){
            this.configuration = configuration;
        }
    
        public SqlSession openSqlSession() {
            return new DefaultSqlSession(configuration);
        }
    }

    8.创建sqlSession 接口及DefaultSqlSession 实现类

    import java.util.List;
    
    public interface SqlSession {
    
        <E> List<E> findAll(String statementId,Object ... params) throws Exception;
    
        <T> T findOne(String statement,Object ...params)throws Exception;
    
        <T> T getMapper(Class<?> mapperClass);
    }
    import com.zae.pojo.Configuration;
    import com.zae.pojo.MapperStatement;
    
    import java.lang.reflect.*;
    import java.util.List;
    import java.util.Map;
    
    public class DefaultSqlSession implements SqlSession {
        private Configuration configuration;
    
        public DefaultSqlSession(Configuration configuration){
            this.configuration = configuration;
        }
    
    
        public <E> List<E> findAll(String statementId, Object... params) throws Exception{
            Map<String, MapperStatement> statementMap = configuration.getMapperStatementMap();
            MapperStatement mapperStatement = statementMap.get(statementId);
            Executor executor = new SimpleExecutor();
            List<Object> execute = executor.execute(configuration,mapperStatement,params);
            return (List<E>) execute;
        }
    
        public <T> T findOne(String statement, Object... params) throws Exception{
            List<Object> objectList = findAll(statement, params);
            if(objectList.size() == 1){
                return (T) objectList.get(0);
            }else{
                throw new RuntimeException("返回参数不唯一或者为空");
            }
        }
    
        public <T> T getMapper(Class<?> aclass) {
            Object object = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{aclass}, new InvocationHandler() {
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //获取执行方法名
                    String methodName = method.getName();
                    //获取全限类名
                    String className = method.getDeclaringClass().getName();
                    //statementId
                    String statementId = className+"."+methodName;
                    //参数泛型化
                    Type type = method.getGenericReturnType();
                    if(type instanceof ParameterizedType){
                        //存在泛型,则调用findAll
                        List<Object> all = findAll(statementId, args);
                        return all;
                    }
                    return findOne(statementId,args);
                }
            });
    
            return (T) object;
        }
    }

    9.创建Executor接口及SimpleExecutor实现类,创建BoundSql实体,引入工具类。

    import com.zae.pojo.Configuration;
    import com.zae.pojo.MapperStatement;
    
    import java.util.List;
    
    public interface Executor {
        /**
         * jdbc处理方法
         * @param configuration
         * @param mapperStatement
         * @param params
         * @param <E>
         * @return
         */
       <E> List<E> execute(Configuration configuration, MapperStatement mapperStatement, Object ...params) throws Exception;
    }
    import com.zae.pojo.BorundSql;
    import com.zae.pojo.Configuration;
    import com.zae.pojo.MapperStatement;
    import com.zae.utils.GenericTokenParser;
    import com.zae.utils.ParameterMapping;
    import com.zae.utils.ParameterMappingTokenHandler;
    
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.util.ArrayList;
    import java.util.List;
    
    public class SimpleExecutor implements Executor {
        public <E> List<E> execute(Configuration configuration, MapperStatement mapperStatement, Object... params) throws Exception{
            //1.获取连接对象
            Connection connection = configuration.getDataSource().getConnection();
            //2.处理sql语句
            String sql = mapperStatement.getSql();
            BorundSql borundSql = dealSql(sql);
            String sqlNow = borundSql.getSql();
            List<ParameterMapping> mappingList = borundSql.getParameterMappingList();
            //3.获取预处理对象
            PreparedStatement preparedStatement = connection.prepareStatement(sqlNow);
            //4.设置参数
            Class<?> classByType = getClassByType(mapperStatement.getParamterType());
            for(int i = 0;i<mappingList.size();i++){
                String content = mappingList.get(i).getContent();
                //根据属性名获取该属性信息
                Field declaredField = classByType.getDeclaredField(content);
                //设置暴力访问
                declaredField.setAccessible(true);
                //获取参数里面的值
                Object value = declaredField.get(params[0]);
                //设置参数
                preparedStatement.setObject(i+1,value);
            }
            //5.处理返回结果集
            ResultSet resultSet = preparedStatement.executeQuery();
            Class<?> resultClass = getClassByType(mapperStatement.getResultType());
            List resultList = new ArrayList();
            while (resultSet.next()){
                //生成该类的实例对象
                Object object = resultClass.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,resultClass);
                    //获取写入方法
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    //调用invoke方法,将数据写入实体
                    writeMethod.invoke(object,value);
                }
                resultList.add(object);
            }
            return resultList;
        }
    
        /**
         * 处理sql,将sql中的#{}处理成?,并把#{}里面的字段保存下来
         * @param sourceSql
         * @return
         */
        private BorundSql dealSql(String sourceSql){
            ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
            GenericTokenParser genericTokenParser = new GenericTokenParser("#{","}",parameterMappingTokenHandler);
            String targetSql = genericTokenParser.parse(sourceSql);
            List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
            BorundSql borundSql = new BorundSql();
            borundSql.setSql(targetSql);
            borundSql.setParameterMappingList(parameterMappings);
            return borundSql;
        }
    
        /**
         * 根据类的全路径获取类对象
         * @param path
         * @return
         */
        private Class<?> getClassByType(String path) throws ClassNotFoundException {
            if(path!=null){
                Class<?> aClass = Class.forName(path);
                return aClass;
            }else{
                return null;
            }
        }
    }
    import com.zae.utils.ParameterMapping;
    
    import java.util.List;
    
    public class BorundSql {
        private String sql;
    
        private List<ParameterMapping> parameterMappingList;
    
        public String getSql() {
            return sql;
        }
    
        public void setSql(String sql) {
            this.sql = sql;
        }
    
        public List<ParameterMapping> getParameterMappingList() {
            return parameterMappingList;
        }
    
        public void setParameterMappingList(List<ParameterMapping> parameterMappingList) {
            this.parameterMappingList = parameterMappingList;
        }
    }

    工具类如下:

    public class GenericTokenParser {
    
      private final String openToken; //开始标记
      private final String closeToken; //结束标记
      private final TokenHandler handler; //标记处理器
    
      public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
        this.openToken = openToken;
        this.closeToken = closeToken;
        this.handler = handler;
      }
    
      /**
       * 解析${}和#{}
       * @param text
       * @return
       * 该方法主要实现了配置文件、脚本等片段中占位符的解析、处理工作,并返回最终需要的数据。
       * 其中,解析工作由该方法完成,处理工作是由处理器handler的handleToken()方法来实现
       */
      public String parse(String text) {
        // 验证参数问题,如果是null,就返回空字符串。
        if (text == null || text.isEmpty()) {
          return "";
        }
    
        // 下面继续验证是否包含开始标签,如果不包含,默认不是占位符,直接原样返回即可,否则继续执行。
        int start = text.indexOf(openToken, 0);
        if (start == -1) {
          return text;
        }
    
       // 把text转成字符数组src,并且定义默认偏移量offset=0、存储最终需要返回字符串的变量builder,
        // text变量中占位符对应的变量名expression。判断start是否大于-1(即text中是否存在openToken),如果存在就执行下面代码
        char[] src = text.toCharArray();
        int offset = 0;
        final StringBuilder builder = new StringBuilder();
        StringBuilder expression = null;
        while (start > -1) {
         // 判断如果开始标记前如果有转义字符,就不作为openToken进行处理,否则继续处理
          if (start > 0 && src[start - 1] == '\') {
            builder.append(src, offset, start - offset - 1).append(openToken);
            offset = start + openToken.length();
          } else {
            //重置expression变量,避免空指针或者老数据干扰。
            if (expression == null) {
              expression = new StringBuilder();
            } else {
              expression.setLength(0);
            }
            builder.append(src, offset, start - offset);
            offset = start + openToken.length();
            int end = text.indexOf(closeToken, offset);
            while (end > -1) {////存在结束标记时
              if (end > offset && src[end - 1] == '\') {//如果结束标记前面有转义字符时
                // this close token is escaped. remove the backslash and continue.
                expression.append(src, offset, end - offset - 1).append(closeToken);
                offset = end + closeToken.length();
                end = text.indexOf(closeToken, offset);
              } else {//不存在转义字符,即需要作为参数进行处理
                expression.append(src, offset, end - offset);
                offset = end + closeToken.length();
                break;
              }
            }
            if (end == -1) {
              // close token was not found.
              builder.append(src, start, src.length - start);
              offset = src.length;
            } else {
              //首先根据参数的key(即expression)进行参数处理,返回?作为占位符
              builder.append(handler.handleToken(expression.toString()));
              offset = end + closeToken.length();
            }
          }
          start = text.indexOf(openToken, offset);
        }
        if (offset < src.length) {
          builder.append(src, offset, src.length - offset);
        }
        return builder.toString();
      }
    }
    public class ParameterMapping {
    
        private String content;
    
        public ParameterMapping(String content) {
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    }
    import java.util.ArrayList;
    import java.util.List;
    
    
    public class ParameterMappingTokenHandler implements TokenHandler {
        private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
    
        // context是参数名称 #{id} #{username}
    
        public String handleToken(String content) {
            parameterMappings.add(buildParameterMapping(content));
            return "?";
        }
    
        private ParameterMapping buildParameterMapping(String content) {
            ParameterMapping parameterMapping = new ParameterMapping(content);
            return parameterMapping;
        }
    
        public List<ParameterMapping> getParameterMappings() {
            return parameterMappings;
        }
    
        public void setParameterMappings(List<ParameterMapping> parameterMappings) {
            this.parameterMappings = parameterMappings;
        }
    
    }
    public interface TokenHandler {
      String handleToken(String content);
    }

    10.在FrameMyBatis_test项目的pom文件中引入FrameMyBatis的坐标,在准备好的FrameMyBatis_test下编写测试类FrameTest

    import com.zae.dao.UserDao;
    import com.zae.entity.User;
    import com.zae.io.Resources;
    import com.zae.session.SqlSession;
    import com.zae.session.SqlSessionFactory;
    import com.zae.session.SqlSessionFactoryBuilder;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.InputStream;
    import java.util.List;
    
    public class FrameTest {
    
        private SqlSession sqlSession;
    
        private UserDao userDao;
    
        @Before
        public void test1() throws Exception{
            //获取字节输入流
            InputStream inputStream = Resources.getInputStreamByXml("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSqlSession();
            userDao = sqlSession.getMapper(UserDao.class);
        }
    
        /**
         * 全查
         * @throws Exception
         */
        @Test
        public void test2()throws Exception{
            List<User> all = sqlSession.findAll("com.zae.dao.UserDao.findAll");
            for (User user : all) {
                System.out.println(user);
            }
        }
    
        /**
         * 单条
         * @throws Exception
         */
        @Test
        public void test3() throws Exception{
            User user = new User();
            user.setId("1");
            user.setUsername("sss");
            User one = sqlSession.findOne("user.findOne", user);
            System.out.println(one);
        }
    
        /**
         * 代理对象查询
         * @throws Exception
         */
        @Test
        public void test4() throws Exception{
            List<User> userList = userDao.findAll(null);
            for (User user : userList) {
                System.out.println(user);
            }
        }
    }

     我是帝莘,期待与你的技术交流和思想碰撞。

  • 相关阅读:
    设计模式(6)--Adapter(适配器模式)--结构型
    设计模式原则(1)--Single Responsibility Principle(SRP)--单一职责原则
    设计模式(5)--Builder(建造模式)--创建型
    设计模式(4)--AbstractFactory(抽象工厂模式)--创建型
    设计模式(3)--SimpleFactory( [1] 简单工厂模式)--创建型
    JS 的map和array集合组合返回JSON字符串
    HTML中直接写js 函数
    设计模式(3)--FactoryMethod( [2] 工厂方法模式)--创建型
    图片剪贴工具类
    远程Get,Post请求工具类
  • 原文地址:https://www.cnblogs.com/zaevn00001/p/14179754.html
Copyright © 2011-2022 走看看